summary refs log tree commit diff
path: root/kvm/src/lib.rs
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor@chromium.org>2018-03-26 17:14:19 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-03-30 00:07:07 -0700
commiteda8b215369802296e86bd3cceee5f54bf659eda (patch)
treeea4bba47e260b167c8a78fe3720938595e6f11ec /kvm/src/lib.rs
parent4757cf164b4a9b00e686326fbddaafa598686d6c (diff)
downloadcrosvm-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.rs93
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]