summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--aarch64/src/lib.rs10
-rw-r--r--arch/src/lib.rs4
-rw-r--r--src/linux.rs4
-rw-r--r--x86_64/src/lib.rs11
-rw-r--r--x86_64/src/mptable.rs75
5 files changed, 81 insertions, 23 deletions
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
index 6a25a26..86fa03a 100644
--- a/aarch64/src/lib.rs
+++ b/aarch64/src/lib.rs
@@ -20,7 +20,7 @@ use std::io::stdout;
 use std::sync::{Arc, Mutex};
 use std::ffi::CStr;
 
-use devices::Bus;
+use devices::{Bus, PciInterruptPin};
 use sys_util::{EventFd, GuestAddress, GuestMemory};
 use resources::{AddressRanges, SystemAllocator};
 use std::os::unix::io::FromRawFd;
@@ -171,8 +171,12 @@ impl arch::LinuxArch for AArch64 {
         Ok(())
     }
 
-    fn setup_system_memory(mem: &GuestMemory, mem_size: u64, vcpu_count: u32,
-                           cmdline: &CStr) -> Result<()> {
+    fn setup_system_memory(mem: &GuestMemory,
+                           mem_size: u64,
+                           vcpu_count: u32,
+                           cmdline: &CStr,
+                           _pci_irqs: Vec<(u32, PciInterruptPin)>) -> Result<()> {
+        // TODO(dgreid) set up PCI in the device tree.
         fdt::create_fdt(AARCH64_FDT_MAX_SIZE as usize,
                         mem,
                         vcpu_count,
diff --git a/arch/src/lib.rs b/arch/src/lib.rs
index 1b07c62..e2d447c 100644
--- a/arch/src/lib.rs
+++ b/arch/src/lib.rs
@@ -41,10 +41,12 @@ pub trait LinuxArch {
     /// * `mem_size` - The size in bytes of system memory
     /// * `vcpu_count` - Number of virtual CPUs the guest will have
     /// * `cmdline` - the kernel commandline
+    /// * `pci_irqs` - Any PCI irqs that need to be configured (Interrupt Line, PCI pin).
     fn setup_system_memory(mem: &GuestMemory,
                            mem_size: u64,
                            vcpu_count: u32,
-                           cmdline: &CStr) -> Result<()>;
+                           cmdline: &CStr,
+                           pci_irqs: Vec<(u32, devices::PciInterruptPin)>) -> Result<()>;
 
     /// Creates a new VM object and initializes architecture specific devices
     ///
diff --git a/src/linux.rs b/src/linux.rs
index 7e7f2b0..46ea35b 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -910,8 +910,8 @@ pub fn run_config(cfg: Config) -> Result<()> {
     // kernel loading
     Arch::load_kernel(&mem, &mut kernel_image).map_err(|e| Error::LoadKernel(e))?;
     Arch::setup_system_memory(&mem, mem_size as u64, vcpu_count,
-                              &CString::new(cmdline).unwrap()).
-        map_err(|e| Error::SetupSystemMemory(e))?;
+                              &CString::new(cmdline).unwrap(), Vec::new())
+        .map_err(|e| Error::SetupSystemMemory(e))?;
 
     setup_vcpu_signal_handler()?;
     for (cpu_id, vcpu) in vcpus.into_iter().enumerate() {
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index f2ca16d..763f71b 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -69,6 +69,7 @@ use std::io::stdout;
 
 use bootparam::boot_params;
 use bootparam::E820_RAM;
+use devices::PciInterruptPin;
 use sys_util::{EventFd, GuestAddress, GuestMemory};
 use resources::{AddressRanges, SystemAllocator};
 use kvm::*;
@@ -139,7 +140,8 @@ fn configure_system(guest_mem: &GuestMemory,
                     kernel_addr: GuestAddress,
                     cmdline_addr: GuestAddress,
                     cmdline_size: usize,
-                    num_cpus: u8)
+                    num_cpus: u8,
+                    pci_irqs: Vec<(u32, PciInterruptPin)>)
                     -> Result<()> {
     const EBDA_START: u64 = 0x0009fc00;
     const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55;
@@ -150,7 +152,7 @@ fn configure_system(guest_mem: &GuestMemory,
     let end_32bit_gap_start = GuestAddress(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE);
 
     // Note that this puts the mptable at 0x0 in guest physical memory.
-    mptable::setup_mptable(guest_mem, num_cpus)?;
+    mptable::setup_mptable(guest_mem, num_cpus, pci_irqs)?;
 
     let mut params: boot_params = Default::default();
 
@@ -250,11 +252,12 @@ impl arch::LinuxArch for X8664arch {
     /// * `vcpu_count` - Number of virtual CPUs the guest will have.
     /// * `cmdline` - the kernel commandline
     fn setup_system_memory(mem: &GuestMemory, _mem_size: u64,
-                           vcpu_count: u32, cmdline: &CStr) -> Result<()> {
+                           vcpu_count: u32, cmdline: &CStr,
+                           pci_irqs: Vec<(u32, PciInterruptPin)>) -> Result<()> {
         kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline)?;
         configure_system(mem, GuestAddress(KERNEL_START_OFFSET),
                          GuestAddress(CMDLINE_OFFSET),
-                         cmdline.to_bytes().len() + 1, vcpu_count as u8)?;
+                         cmdline.to_bytes().len() + 1, vcpu_count as u8, pci_irqs)?;
         Ok(())
     }
 
diff --git a/x86_64/src/mptable.rs b/x86_64/src/mptable.rs
index d433433..b37ef97 100644
--- a/x86_64/src/mptable.rs
+++ b/x86_64/src/mptable.rs
@@ -11,6 +11,7 @@ use std::fmt::{self, Display};
 
 use libc::c_char;
 
+use devices::PciInterruptPin;
 use sys_util::{GuestAddress, GuestMemory};
 
 use mpspec::*;
@@ -79,6 +80,7 @@ const MPC_SPEC: i8 = 4;
 const MPC_OEM: [c_char; 8] = char_array!(c_char; 'C', 'R', 'O', 'S', 'V', 'M', ' ', ' ');
 const MPC_PRODUCT_ID: [c_char; 12] = ['0' as c_char; 12];
 const BUS_TYPE_ISA: [u8; 6] = char_array!(u8; 'I', 'S', 'A', ' ', ' ', ' ');
+const BUS_TYPE_PCI: [u8; 6] = char_array!(u8; 'P', 'C', 'I', ' ', ' ', ' ');
 const IO_APIC_DEFAULT_PHYS_BASE: u32 = 0xfec00000; // source: linux/arch/x86/include/asm/apicdef.h
 const APIC_DEFAULT_PHYS_BASE: u32 = 0xfee00000; // source: linux/arch/x86/include/asm/apicdef.h
 const APIC_VERSION: u8 = 0x14;
@@ -105,13 +107,17 @@ fn mpf_intel_compute_checksum(v: &mpf_intel) -> u8 {
 fn compute_mp_size(num_cpus: u8) -> usize {
     mem::size_of::<mpf_intel>() + mem::size_of::<mpc_table>() +
     mem::size_of::<mpc_cpu>() * (num_cpus as usize) + mem::size_of::<mpc_ioapic>() +
-    mem::size_of::<mpc_bus>() + mem::size_of::<mpc_intsrc>() +
+    mem::size_of::<mpc_bus>() * 2 + mem::size_of::<mpc_intsrc>() +
     mem::size_of::<mpc_intsrc>() * 16 +
     mem::size_of::<mpc_lintsrc>() * 2
 }
 
 /// Performs setup of the MP table for the given `num_cpus`.
-pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> {
+pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8,
+                     pci_irqs: Vec<(u32, PciInterruptPin)>)
+        -> Result<()> {
+    const PCI_BUS_ID: u8 = 0;
+    const ISA_BUS_ID: u8 = 1;
 
     // Used to keep track of the next base pointer into the MP table.
     let mut base_mp = GuestAddress(MPTABLE_START);
@@ -188,7 +194,18 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> {
         let size = mem::size_of::<mpc_bus>();
         let mut mpc_bus = mpc_bus::default();
         mpc_bus.type_ = MP_BUS as u8;
-        mpc_bus.busid = 0;
+        mpc_bus.busid = PCI_BUS_ID;
+        mpc_bus.bustype = BUS_TYPE_PCI;
+        mem.write_obj_at_addr(mpc_bus, base_mp)
+            .map_err(|_| Error::WriteMpcBus)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_bus));
+    }
+    {
+        let size = mem::size_of::<mpc_bus>();
+        let mut mpc_bus = mpc_bus::default();
+        mpc_bus.type_ = MP_BUS as u8;
+        mpc_bus.busid = ISA_BUS_ID;
         mpc_bus.bustype = BUS_TYPE_ISA;
         mem.write_obj_at_addr(mpc_bus, base_mp)
             .map_err(|_| Error::WriteMpcBus)?;
@@ -201,7 +218,7 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> {
         mpc_intsrc.type_ = MP_INTSRC as u8;
         mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8;
         mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
-        mpc_intsrc.srcbus = 0;
+        mpc_intsrc.srcbus = ISA_BUS_ID;
         mpc_intsrc.srcbusirq = 0;
         mpc_intsrc.dstapic = 0;
         mpc_intsrc.dstirq = 0;
@@ -211,13 +228,13 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> {
         checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
     }
     // Per kvm_setup_default_irq_routing() in kernel
-    for i in 0..16 {
+    for i in 0..5 {
         let size = mem::size_of::<mpc_intsrc>();
         let mut mpc_intsrc = mpc_intsrc::default();
         mpc_intsrc.type_ = MP_INTSRC as u8;
         mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8;
         mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
-        mpc_intsrc.srcbus = 0;
+        mpc_intsrc.srcbus = ISA_BUS_ID;
         mpc_intsrc.srcbusirq = i;
         mpc_intsrc.dstapic = ioapicid;
         mpc_intsrc.dstirq = i;
@@ -226,13 +243,45 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> {
         base_mp = base_mp.unchecked_add(size as u64);
         checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
     }
+    // Insert PCI interrupts after platform IRQs.
+    for (i, pci_irq) in pci_irqs.iter().enumerate() {
+        let size = mem::size_of::<mpc_intsrc>();
+        let mut mpc_intsrc = mpc_intsrc::default();
+        mpc_intsrc.type_ = MP_INTSRC as u8;
+        mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8;
+        mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
+        mpc_intsrc.srcbus = PCI_BUS_ID;
+        mpc_intsrc.srcbusirq = 1 << 2 | pci_irq.1.to_mask() as u8; // slot <<2 | int A(0)
+        mpc_intsrc.dstapic = ioapicid;
+        mpc_intsrc.dstirq = 5 + i as u8;
+        mem.write_obj_at_addr(mpc_intsrc, base_mp)
+            .map_err(|_| Error::WriteMpcIntsrc)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
+    }
+    // Finally insert ISA interrupts.
+    for i in 5 + pci_irqs.len()..16 {
+        let size = mem::size_of::<mpc_intsrc>();
+        let mut mpc_intsrc = mpc_intsrc::default();
+        mpc_intsrc.type_ = MP_INTSRC as u8;
+        mpc_intsrc.irqtype = mp_irq_source_types_mp_INT as u8;
+        mpc_intsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
+        mpc_intsrc.srcbus = ISA_BUS_ID;
+        mpc_intsrc.srcbusirq = i as u8;
+        mpc_intsrc.dstapic = ioapicid;
+        mpc_intsrc.dstirq = i as u8;
+        mem.write_obj_at_addr(mpc_intsrc, base_mp)
+            .map_err(|_| Error::WriteMpcIntsrc)?;
+        base_mp = base_mp.unchecked_add(size as u64);
+        checksum = checksum.wrapping_add(compute_checksum(&mpc_intsrc));
+    }
     {
         let size = mem::size_of::<mpc_lintsrc>();
         let mut mpc_lintsrc = mpc_lintsrc::default();
         mpc_lintsrc.type_ = MP_LINTSRC as u8;
         mpc_lintsrc.irqtype = mp_irq_source_types_mp_ExtINT as u8;
         mpc_lintsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
-        mpc_lintsrc.srcbusid = 0;
+        mpc_lintsrc.srcbusid = ISA_BUS_ID;
         mpc_lintsrc.srcbusirq = 0;
         mpc_lintsrc.destapic = 0;
         mpc_lintsrc.destapiclint = 0;
@@ -247,7 +296,7 @@ pub fn setup_mptable(mem: &GuestMemory, num_cpus: u8) -> Result<()> {
         mpc_lintsrc.type_ = MP_LINTSRC as u8;
         mpc_lintsrc.irqtype = mp_irq_source_types_mp_NMI as u8;
         mpc_lintsrc.irqflag = MP_IRQDIR_DEFAULT as u16;
-        mpc_lintsrc.srcbusid = 0;
+        mpc_lintsrc.srcbusid = ISA_BUS_ID;
         mpc_lintsrc.srcbusirq = 0;
         mpc_lintsrc.destapic = 0xFF; // Per SeaBIOS
         mpc_lintsrc.destapiclint = 1;
@@ -299,7 +348,7 @@ mod tests {
         let mem = GuestMemory::new(&[(GuestAddress(MPTABLE_START),
                                       compute_mp_size(num_cpus) as u64)]).unwrap();
 
-        setup_mptable(&mem, num_cpus).unwrap();
+        setup_mptable(&mem, num_cpus, Vec::new()).unwrap();
     }
 
     #[test]
@@ -308,7 +357,7 @@ mod tests {
         let mem = GuestMemory::new(&[(GuestAddress(MPTABLE_START),
                                       (compute_mp_size(num_cpus) - 1) as u64)]).unwrap();
 
-        assert!(setup_mptable(&mem, num_cpus).is_err());
+        assert!(setup_mptable(&mem, num_cpus, Vec::new()).is_err());
     }
 
     #[test]
@@ -317,7 +366,7 @@ mod tests {
         let mem = GuestMemory::new(&[(GuestAddress(MPTABLE_START),
                                       compute_mp_size(num_cpus) as u64)]).unwrap();
 
-        setup_mptable(&mem, num_cpus).unwrap();
+        setup_mptable(&mem, num_cpus, Vec::new()).unwrap();
 
         let mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
 
@@ -330,7 +379,7 @@ mod tests {
         let mem = GuestMemory::new(&[(GuestAddress(MPTABLE_START),
                                       compute_mp_size(num_cpus) as u64)]).unwrap();
 
-        setup_mptable(&mem, num_cpus).unwrap();
+        setup_mptable(&mem, num_cpus, Vec::new()).unwrap();
 
         let mpf_intel: mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
         let mpc_offset = GuestAddress(mpf_intel.physptr as u64);
@@ -362,7 +411,7 @@ mod tests {
                                       compute_mp_size(MAX_CPUS) as u64)]).unwrap();
 
         for i in 0..MAX_CPUS {
-            setup_mptable(&mem, i).unwrap();
+            setup_mptable(&mem, i, Vec::new()).unwrap();
 
             let mpf_intel: mpf_intel = mem.read_obj_from_addr(GuestAddress(MPTABLE_START)).unwrap();
             let mpc_offset = GuestAddress(mpf_intel.physptr as u64);