diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index 6a25a2659f..86fa03ad1e 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 1b07c62fcd..e2d447c6c0 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 7e7f2b02e9..46ea35bdd4 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 f2ca16d2f1..763f71bcdf 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 d433433625..b37ef97fe5 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::() + mem::size_of::() + mem::size_of::() * (num_cpus as usize) + mem::size_of::() + - mem::size_of::() + mem::size_of::() + + mem::size_of::() * 2 + mem::size_of::() + mem::size_of::() * 16 + mem::size_of::() * 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::(); 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::(); + 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::(); 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::(); + 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::(); + 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::(); 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);