mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-12-24 11:58:41 +00:00
mptable: Add ability to allocate pci interrupts
PCI devices will require interrupts, allow this by passing a vector of IRQs to the mptable so the guest kernel can find the IRQs. Change-Id: I9fa8a2ed0a34089e631441570521082ffde9c4ef Reviewed-on: https://chromium-review.googlesource.com/1072578 Commit-Ready: Dylan Reid <dgreid@chromium.org> Tested-by: Dylan Reid <dgreid@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
b847858e66
commit
a697d31fc6
5 changed files with 81 additions and 23 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
///
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue