diff options
author | Dmitry Torokhov <dtor@chromium.org> | 2018-03-26 17:14:19 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-03-30 00:07:07 -0700 |
commit | eda8b215369802296e86bd3cceee5f54bf659eda (patch) | |
tree | ea4bba47e260b167c8a78fe3720938595e6f11ec /kvm/src/lib.rs | |
parent | 4757cf164b4a9b00e686326fbddaafa598686d6c (diff) | |
download | crosvm-eda8b215369802296e86bd3cceee5f54bf659eda.tar crosvm-eda8b215369802296e86bd3cceee5f54bf659eda.tar.gz crosvm-eda8b215369802296e86bd3cceee5f54bf659eda.tar.bz2 crosvm-eda8b215369802296e86bd3cceee5f54bf659eda.tar.lz crosvm-eda8b215369802296e86bd3cceee5f54bf659eda.tar.xz crosvm-eda8b215369802296e86bd3cceee5f54bf659eda.tar.zst crosvm-eda8b215369802296e86bd3cceee5f54bf659eda.zip |
kvm: fix fetching irqchip state for PICs other than the first one
The KVM API to fetch interrupt controller state expects caller to supply number (id) of the interrupt controller number in which state the caller is interested. To allow crosvm to fetch the correct state and to improve type safety we split the API into one that handles the PIC (primary and secondary) and the one that handles IOAPIC. BUG=b:76083711 TEST=cargo test -p kvm Change-Id: Ia45b51cb218072a275c244af2de1b4a73a1d3352 Signed-off-by: Dmitry Torokhov <dtor@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/986510 Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'kvm/src/lib.rs')
-rw-r--r-- | kvm/src/lib.rs | 93 |
1 files changed, 80 insertions, 13 deletions
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs index a585fff..2bf2677 100644 --- a/kvm/src/lib.rs +++ b/kvm/src/lib.rs @@ -195,6 +195,12 @@ pub struct IrqRoute { pub source: IrqSource, } +/// Interrupt controller IDs +pub enum PicId { + Primary = 0, + Secondary = 1, +} + /// A wrapper around creating and using a VM. pub struct Vm { vm: File, @@ -395,30 +401,40 @@ impl Vm { } } - /// Retrieves the state of irqchip by issuing KVM_GET_IRQCHIP ioctl. + /// Retrieves the state of given interrupt controller by issuing KVM_GET_IRQCHIP ioctl. /// /// Note that this call can only succeed after a call to `Vm::create_irq_chip`. #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub fn get_irq_chip_state(&self) -> Result<kvm_irqchip> { - // Safe because we know that our file is a VM fd, we know the kernel will only write - // correct amount of memory to our pointer, and we verify the return result. - let mut irqchip_state = unsafe { std::mem::zeroed() }; - let ret = unsafe { ioctl_with_mut_ref(self, KVM_GET_IRQCHIP(), &mut irqchip_state) }; + pub fn get_pic_state(&self, id: PicId) -> Result<kvm_pic_state> { + let mut irqchip_state = kvm_irqchip::default(); + irqchip_state.chip_id = id as u32; + let ret = unsafe { + // Safe because we know our file is a VM fd, we know the kernel will only write + // correct amount of memory to our pointer, and we verify the return result. + ioctl_with_mut_ref(self, KVM_GET_IRQCHIP(), &mut irqchip_state) + }; if ret == 0 { - Ok(irqchip_state) + Ok(unsafe { + // Safe as we know that we are retrieving data related to the + // PIC (primary or secondary) and not IOAPIC. + irqchip_state.chip.pic + }) } else { errno_result() } } - /// Sets the state of irqchip by issuing KVM_SET_IRQCHIP ioctl. + /// Sets the state of given interrupt controller by issuing KVM_SET_IRQCHIP ioctl. /// /// Note that this call can only succeed after a call to `Vm::create_irq_chip`. #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub fn set_irq_chip_state(&self, irqchip_state: &kvm_irqchip) -> Result<()> { + pub fn set_pic_state(&self, id: PicId, state: &kvm_pic_state) -> Result<()> { + let mut irqchip_state = kvm_irqchip::default(); + irqchip_state.chip_id = id as u32; + irqchip_state.chip.pic = *state; // Safe because we know that our file is a VM fd, we know the kernel will only read // correct amount of memory from our pointer, and we verify the return result. - let ret = unsafe { ioctl_with_ref(self, KVM_SET_IRQCHIP(), irqchip_state) }; + let ret = unsafe { ioctl_with_ref(self, KVM_SET_IRQCHIP(), &irqchip_state) }; if ret == 0 { Ok(()) } else { @@ -427,6 +443,47 @@ impl Vm { } + /// Retrieves the state of IOAPIC by issuing KVM_GET_IRQCHIP ioctl. + /// + /// Note that this call can only succeed after a call to `Vm::create_irq_chip`. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub fn get_ioapic_state(&self) -> Result<kvm_ioapic_state> { + let mut irqchip_state = kvm_irqchip::default(); + irqchip_state.chip_id = 2; + let ret = unsafe { + // Safe because we know our file is a VM fd, we know the kernel will only write + // correct amount of memory to our pointer, and we verify the return result. + ioctl_with_mut_ref(self, KVM_GET_IRQCHIP(), &mut irqchip_state) + }; + if ret == 0 { + Ok(unsafe { + // Safe as we know that we are retrieving data related to the + // IOAPIC and not PIC. + irqchip_state.chip.ioapic + }) + } else { + errno_result() + } + } + + /// Sets the state of IOAPIC by issuing KVM_SET_IRQCHIP ioctl. + /// + /// Note that this call can only succeed after a call to `Vm::create_irq_chip`. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub fn set_ioapic_state(&self, state: &kvm_ioapic_state) -> Result<()> { + let mut irqchip_state = kvm_irqchip::default(); + irqchip_state.chip_id = 2; + irqchip_state.chip.ioapic = *state; + // Safe because we know that our file is a VM fd, we know the kernel will only read + // correct amount of memory from our pointer, and we verify the return result. + let ret = unsafe { ioctl_with_ref(self, KVM_SET_IRQCHIP(), &irqchip_state) }; + if ret == 0 { + Ok(()) + } else { + errno_result() + } + } + /// Sets the level on the given irq to 1 if `active` is true, and 0 otherwise. #[cfg(any(target_arch = "x86", target_arch = "x86_64", target_arch = "arm", target_arch = "aarch64"))] pub fn set_irq_line(&self, irq: u32, active: bool) -> Result<()> { @@ -1283,13 +1340,23 @@ mod tests { } #[test] - fn irqchip_handling() { + fn pic_handling() { + let kvm = Kvm::new().unwrap(); + let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); + let vm = Vm::new(&kvm, gm).unwrap(); + vm.create_irq_chip().unwrap(); + let pic_state = vm.get_pic_state(PicId::Secondary).unwrap(); + vm.set_pic_state(PicId::Secondary, &pic_state).unwrap(); + } + + #[test] + fn ioapic_handling() { let kvm = Kvm::new().unwrap(); let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap(); let vm = Vm::new(&kvm, gm).unwrap(); vm.create_irq_chip().unwrap(); - let irqchip_state = vm.get_irq_chip_state().unwrap(); - vm.set_irq_chip_state(&irqchip_state).unwrap(); + let ioapic_state = vm.get_ioapic_state().unwrap(); + vm.set_ioapic_state(&ioapic_state).unwrap(); } #[test] |