summary refs log tree commit diff
path: root/kvm/src/lib.rs
diff options
context:
space:
mode:
authorZach Reizner <zachr@google.com>2018-01-09 10:41:10 -0800
committerchrome-bot <chrome-bot@chromium.org>2018-01-25 19:23:42 -0800
commit086922c222a856252e46b35c912b435635ea0682 (patch)
tree5d3f0b3a7befdba6dcac409ad60e1d047090ae9c /kvm/src/lib.rs
parent0ba70d8d3c69a4fa8853d317e2dc1f45dd25acd8 (diff)
downloadcrosvm-086922c222a856252e46b35c912b435635ea0682.tar
crosvm-086922c222a856252e46b35c912b435635ea0682.tar.gz
crosvm-086922c222a856252e46b35c912b435635ea0682.tar.bz2
crosvm-086922c222a856252e46b35c912b435635ea0682.tar.lz
crosvm-086922c222a856252e46b35c912b435635ea0682.tar.xz
crosvm-086922c222a856252e46b35c912b435635ea0682.tar.zst
crosvm-086922c222a856252e46b35c912b435635ea0682.zip
kvm: add set_irq_routing method
This is used by the plugin process API, which may register an IRQ
routing table.

TEST=./build_test
BUG=chromium:800626

Change-Id: If40965e8abfb0c9074c90b5fc77f9042f06499e0
Reviewed-on: https://chromium-review.googlesource.com/857910
Commit-Ready: Zach Reizner <zachr@chromium.org>
Tested-by: Zach Reizner <zachr@chromium.org>
Reviewed-by: Dmitry Torokhov <dtor@chromium.org>
Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'kvm/src/lib.rs')
-rw-r--r--kvm/src/lib.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs
index 3dee94c..be1feec 100644
--- a/kvm/src/lib.rs
+++ b/kvm/src/lib.rs
@@ -14,6 +14,7 @@ mod cap;
 use std::fs::File;
 use std::collections::{BinaryHeap, HashMap};
 use std::collections::hash_map::Entry;
+use std::mem::size_of;
 use std::os::raw::*;
 use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
 
@@ -168,6 +169,18 @@ impl Into<u64> for NoDatamatch {
     }
 }
 
+/// A source of IRQs in an `IrqRoute`.
+pub enum IrqSource {
+    Irqchip { chip: u32, pin: u32 },
+    Msi { address: u64, data: u32 },
+}
+
+/// A single route for an IRQ.
+pub struct IrqRoute {
+    pub gsi: u32,
+    pub source: IrqSource,
+}
+
 /// A wrapper around creating and using a VM.
 pub struct Vm {
     vm: File,
@@ -473,6 +486,55 @@ impl Vm {
             errno_result()
         }
     }
+
+    /// Sets the GSI routing table, replacing any table set with previous calls to
+    /// `set_gsi_routing`.
+    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+    pub fn set_gsi_routing(&self, routes: &[IrqRoute]) -> Result<()> {
+        let vec_size_bytes = size_of::<kvm_irq_routing>() +
+            (routes.len() * size_of::<kvm_irq_routing_entry>());
+        let bytes: Vec<u8> = vec![0; vec_size_bytes];
+        let irq_routing: &mut kvm_irq_routing = unsafe {
+            // We have ensured in new that there is enough space for the structure so this
+            // conversion is safe.
+            &mut *(bytes.as_ptr() as *mut kvm_irq_routing)
+        };
+        irq_routing.nr = routes.len() as u32;
+
+        {
+            // Safe because we ensured there is enough space in irq_routing to hold the number of
+            // route entries.
+            let irq_routes = unsafe { irq_routing.entries.as_mut_slice(routes.len()) };
+            for (route, irq_route) in routes.iter().zip(irq_routes.iter_mut()) {
+                irq_route.gsi = route.gsi;
+                match route.source {
+                    IrqSource::Irqchip { chip, pin } => {
+                        irq_route.type_ = KVM_IRQ_ROUTING_IRQCHIP;
+                        irq_route.u.irqchip = kvm_irq_routing_irqchip {
+                            irqchip: chip,
+                            pin,
+                        }
+                    }
+                    IrqSource::Msi { address, data } => {
+                        irq_route.type_ = KVM_IRQ_ROUTING_MSI;
+                        irq_route.u.msi = kvm_irq_routing_msi {
+                            address_lo: address as u32,
+                            address_hi: (address >> 32) as u32,
+                            data: data,
+                            ..Default::default()
+                        }
+                    }
+                }
+            }
+        }
+
+        let ret = unsafe { ioctl_with_ref(self, KVM_SET_GSI_ROUTING(), irq_routing) };
+        if ret == 0 {
+            Ok(())
+        } else {
+            errno_result()
+        }
+    }
 }
 
 impl AsRawFd for Vm {
@@ -982,6 +1044,44 @@ mod tests {
     }
 
     #[test]
+    fn set_gsi_routing() {
+        let kvm = Kvm::new().unwrap();
+        let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
+        let vm = Vm::new(&kvm, gm).unwrap();
+        vm.set_gsi_routing(&[]).unwrap();
+        vm.set_gsi_routing(&[IrqRoute {
+            gsi: 1,
+            source: IrqSource::Irqchip {
+                chip: KVM_IRQCHIP_IOAPIC,
+                pin: 3,
+            },
+        }]).unwrap();
+        vm.set_gsi_routing(&[IrqRoute {
+            gsi: 1,
+            source: IrqSource::Msi {
+                address: 0xf000000,
+                data: 0xa0,
+            },
+        }]).unwrap();
+        vm.set_gsi_routing(&[
+            IrqRoute {
+                gsi: 1,
+                source: IrqSource::Irqchip {
+                    chip: KVM_IRQCHIP_IOAPIC,
+                    pin: 3,
+                },
+            },
+            IrqRoute {
+                gsi: 2,
+                source: IrqSource::Msi {
+                    address: 0xf000000,
+                    data: 0xa0,
+                },
+            },
+        ]).unwrap();
+    }
+
+    #[test]
     fn create_vcpu() {
         let kvm = Kvm::new().unwrap();
         let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();