From f2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7 Mon Sep 17 00:00:00 2001 From: Zhuocheng Ding Date: Mon, 2 Dec 2019 15:50:20 +0800 Subject: Add logic to setup PIC/IOAPIC. TODO: Route irqfd to PIC/IOAPIC to make them fully work. BUG=chromium:908689 TEST=None Change-Id: I301287b1cf32cfccffce6c52ebbb5e123931178e Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1945796 Reviewed-by: Daniel Verkamp Tested-by: kokoro Commit-Queue: Zhuocheng Ding --- Cargo.lock | 3 +++ aarch64/Cargo.toml | 1 + aarch64/src/lib.rs | 3 +++ arch/Cargo.toml | 1 + arch/src/lib.rs | 3 +++ devices/src/ioapic.rs | 14 ++++++-------- devices/src/lib.rs | 2 +- kvm/src/lib.rs | 9 +++++++++ src/linux.rs | 14 ++++++++++++++ x86_64/Cargo.toml | 1 + x86_64/src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++-- 11 files changed, 80 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6210b6c..bb75235 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -16,6 +16,7 @@ dependencies = [ "resources 0.1.0", "sync 0.1.0", "sys_util 0.1.0", + "vm_control 0.1.0", ] [[package]] @@ -37,6 +38,7 @@ dependencies = [ "resources 0.1.0", "sync 0.1.0", "sys_util 0.1.0", + "vm_control 0.1.0", ] [[package]] @@ -776,6 +778,7 @@ dependencies = [ "resources 0.1.0", "sync 0.1.0", "sys_util 0.1.0", + "vm_control 0.1.0", ] [metadata] diff --git a/aarch64/Cargo.toml b/aarch64/Cargo.toml index 8c754d1..7e346ac 100644 --- a/aarch64/Cargo.toml +++ b/aarch64/Cargo.toml @@ -17,3 +17,4 @@ remain = "*" resources = { path = "../resources" } sync = { path = "../sync" } sys_util = { path = "../sys_util" } +vm_control = { path = "../vm_control" } diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index 67fad72..d4c4a50 100644 --- a/aarch64/src/lib.rs +++ b/aarch64/src/lib.rs @@ -21,6 +21,7 @@ use remain::sorted; use resources::SystemAllocator; use sync::Mutex; use sys_util::{EventFd, GuestAddress, GuestMemory, GuestMemoryError}; +use vm_control::VmIrqRequestSocket; use kvm::*; use kvm_sys::kvm_device_attr; @@ -195,6 +196,7 @@ impl arch::LinuxArch for AArch64 { fn build_vm( mut components: VmComponents, _split_irqchip: bool, + _ioapic_device_socket: VmIrqRequestSocket, serial_parameters: &BTreeMap, serial_jail: Option, create_devices: F, @@ -314,6 +316,7 @@ impl arch::LinuxArch for AArch64 { vcpus, vcpu_affinity, irq_chip, + split_irqchip: None, io_bus, mmio_bus, pid_debug_label_map, diff --git a/arch/Cargo.toml b/arch/Cargo.toml index bf28560..6b4e529 100644 --- a/arch/Cargo.toml +++ b/arch/Cargo.toml @@ -13,3 +13,4 @@ libc = "*" resources = { path = "../resources" } sync = { path = "../sync" } sys_util = { path = "../sys_util" } +vm_control = { path = "../vm_control" } diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 6af78e3..5112798 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -25,6 +25,7 @@ use kvm::{IoeventAddress, Kvm, Vcpu, Vm}; use resources::SystemAllocator; use sync::Mutex; use sys_util::{syslog, EventFd, GuestAddress, GuestMemory, GuestMemoryError}; +use vm_control::VmIrqRequestSocket; pub enum VmImage { Kernel(File), @@ -60,6 +61,7 @@ pub struct RunnableLinuxVm { pub vcpus: Vec, pub vcpu_affinity: Vec, pub irq_chip: Option, + pub split_irqchip: Option<(Arc>, Arc>)>, pub io_bus: Bus, pub mmio_bus: Bus, pub pid_debug_label_map: BTreeMap, @@ -88,6 +90,7 @@ pub trait LinuxArch { fn build_vm( components: VmComponents, split_irqchip: bool, + ioapic_device_socket: VmIrqRequestSocket, serial_parameters: &BTreeMap, serial_jail: Option, create_devices: F, diff --git a/devices/src/ioapic.rs b/devices/src/ioapic.rs index 3b5ea80..e1fbfb8 100644 --- a/devices/src/ioapic.rs +++ b/devices/src/ioapic.rs @@ -40,11 +40,9 @@ pub enum DeliveryStatus { } const IOAPIC_VERSION_ID: u32 = 0x00170011; -#[allow(dead_code)] -const IOAPIC_BASE_ADDRESS: u32 = 0xfec00000; +pub const IOAPIC_BASE_ADDRESS: u64 = 0xfec00000; // The Intel manual does not specify this size, but KVM uses it. -#[allow(dead_code)] -const IOAPIC_MEM_LENGTH_BYTES: usize = 0x100; +pub const IOAPIC_MEM_LENGTH_BYTES: u64 = 0x100; // Constants for IOAPIC direct register offset. const IOAPIC_REG_ID: u8 = 0x00; @@ -52,10 +50,10 @@ const IOAPIC_REG_VERSION: u8 = 0x01; const IOAPIC_REG_ARBITRATION_ID: u8 = 0x02; // Register offsets -pub const IOREGSEL_OFF: u8 = 0x0; -pub const IOREGSEL_DUMMY_UPPER_32_BITS_OFF: u8 = 0x4; -pub const IOWIN_OFF: u8 = 0x10; -pub const IOWIN_SCALE: u8 = 0x2; +const IOREGSEL_OFF: u8 = 0x0; +const IOREGSEL_DUMMY_UPPER_32_BITS_OFF: u8 = 0x4; +const IOWIN_OFF: u8 = 0x10; +const IOWIN_SCALE: u8 = 0x2; /// Given an IRQ and whether or not the selector should refer to the high bits, return a selector /// suitable to use as an offset to read to/write from. diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 174b956..2319d86 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -28,7 +28,7 @@ pub use self::bus::Error as BusError; pub use self::bus::{Bus, BusDevice, BusRange, BusResumeDevice}; pub use self::cmos::Cmos; pub use self::i8042::I8042Device; -pub use self::ioapic::Ioapic; +pub use self::ioapic::{Ioapic, IOAPIC_BASE_ADDRESS, IOAPIC_MEM_LENGTH_BYTES}; pub use self::pci::{ Ac97Dev, PciConfigIo, PciConfigMmio, PciDevice, PciDeviceError, PciInterruptPin, PciRoot, VfioPciDevice, diff --git a/kvm/src/lib.rs b/kvm/src/lib.rs index b900505..66ebd20 100644 --- a/kvm/src/lib.rs +++ b/kvm/src/lib.rs @@ -1121,6 +1121,9 @@ pub enum VcpuExit { size: usize, data: [u8; 8], }, + IoapicEoi { + vector: u8, + }, Unknown, Exception, Hypercall, @@ -1811,6 +1814,12 @@ impl RunnableVcpu { Ok(VcpuExit::MmioRead { address, size }) } } + KVM_EXIT_IOAPIC_EOI => { + // Safe because the exit_reason (which comes from the kernel) told us which + // union field to use. + let vector = unsafe { run.__bindgen_anon_1.eoi.vector }; + Ok(VcpuExit::IoapicEoi { vector }) + } KVM_EXIT_UNKNOWN => Ok(VcpuExit::Unknown), KVM_EXIT_EXCEPTION => Ok(VcpuExit::Exception), KVM_EXIT_HYPERCALL => Ok(VcpuExit::Hypercall), diff --git a/src/linux.rs b/src/linux.rs index 007e18e..ad35407 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1356,6 +1356,7 @@ fn run_vcpu( start_barrier: Arc, io_bus: devices::Bus, mmio_bus: devices::Bus, + split_irqchip: Option<(Arc>, Arc>)>, exit_evt: EventFd, requires_kvmclock_ctrl: bool, run_mode_arc: Arc, @@ -1417,6 +1418,13 @@ fn run_vcpu( }) => { mmio_bus.write(address, &data[..size]); } + Ok(VcpuExit::IoapicEoi{vector}) => { + if let Some((_, ioapic)) = &split_irqchip { + ioapic.lock().end_of_interrupt(vector); + } else { + panic!("userspace ioapic not found in split irqchip mode, should be impossible."); + } + }, Ok(VcpuExit::Hlt) => break, Ok(VcpuExit::Shutdown) => break, Ok(VcpuExit::FailEntry { @@ -1589,10 +1597,15 @@ pub fn run_config(cfg: Config) -> Result<()> { msg_socket::pair::().map_err(Error::CreateSocket)?; control_sockets.push(TaggedControlSocket::VmMemory(gpu_host_socket)); + let (ioapic_host_socket, ioapic_device_socket) = + msg_socket::pair::().map_err(Error::CreateSocket)?; + control_sockets.push(TaggedControlSocket::VmIrq(ioapic_host_socket)); + let sandbox = cfg.sandbox; let linux = Arch::build_vm( components, cfg.split_irqchip, + ioapic_device_socket, &cfg.serial_parameters, simple_jail(&cfg, "serial")?, |mem, vm, sys_allocator, exit_evt| { @@ -1739,6 +1752,7 @@ fn run_control( vcpu_thread_barrier.clone(), linux.io_bus.clone(), linux.mmio_bus.clone(), + linux.split_irqchip.clone(), linux.exit_evt.try_clone().map_err(Error::CloneEventFd)?, linux.vm.check_extension(Cap::KvmclockCtrl), run_mode_arc.clone(), diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml index bb1c445..49ef53f 100644 --- a/x86_64/Cargo.toml +++ b/x86_64/Cargo.toml @@ -20,3 +20,4 @@ resources = { path = "../resources" } sync = { path = "../sync" } sys_util = { path = "../sys_util" } acpi_tables = {path = "../acpi_tables" } +vm_control = { path = "../vm_control" } diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index b6f18e3..d9fe8a9 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -55,13 +55,17 @@ use std::sync::Arc; use crate::bootparam::boot_params; use arch::{RunnableLinuxVm, VmComponents, VmImage}; -use devices::{get_serial_tty_string, PciConfigIo, PciDevice, PciInterruptPin, SerialParameters}; +use devices::{ + get_serial_tty_string, Ioapic, PciConfigIo, PciDevice, PciInterruptPin, Pic, SerialParameters, + IOAPIC_BASE_ADDRESS, IOAPIC_MEM_LENGTH_BYTES, +}; use io_jail::Minijail; use kvm::*; use remain::sorted; use resources::SystemAllocator; use sync::Mutex; use sys_util::{Clock, EventFd, GuestAddress, GuestMemory, GuestMemoryError}; +use vm_control::VmIrqRequestSocket; #[sorted] #[derive(Debug)] @@ -73,6 +77,7 @@ pub enum Error { CreateDevices(Box), CreateEventFd(sys_util::Error), CreateFdt(arch::fdt::Error), + CreateIoapicDevice(sys_util::Error), CreateIrqChip(sys_util::Error), CreateKvm(sys_util::Error), CreatePciRoot(arch::DeviceRegistrationError), @@ -120,6 +125,7 @@ impl Display for Error { CreateDevices(e) => write!(f, "error creating devices: {}", e), CreateEventFd(e) => write!(f, "unable to make an EventFd: {}", e), CreateFdt(e) => write!(f, "failed to create fdt: {}", e), + CreateIoapicDevice(e) => write!(f, "failed to create IOAPIC device: {}", e), CreateIrqChip(e) => write!(f, "failed to create irq chip: {}", e), CreateKvm(e) => write!(f, "failed to open /dev/kvm: {}", e), CreatePciRoot(e) => write!(f, "failed to create a PCI root hub: {}", e), @@ -314,6 +320,7 @@ impl arch::LinuxArch for X8664arch { fn build_vm( mut components: VmComponents, split_irqchip: bool, + ioapic_device_socket: VmIrqRequestSocket, serial_parameters: &BTreeMap, serial_jail: Option, create_devices: F, @@ -362,6 +369,23 @@ impl arch::LinuxArch for X8664arch { let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?; + let split_irqchip = if split_irqchip { + let pic = Arc::new(Mutex::new(Pic::new())); + let ioapic = Arc::new(Mutex::new( + Ioapic::new(&mut vm, ioapic_device_socket).map_err(Error::CreateIoapicDevice)?, + )); + mmio_bus + .insert( + ioapic.clone(), + IOAPIC_BASE_ADDRESS, + IOAPIC_MEM_LENGTH_BYTES, + false, + ) + .unwrap(); + Some((pic, ioapic)) + } else { + None + }; let pci_devices = create_devices(&mem, &mut vm, &mut resources, &exit_evt) .map_err(|e| Error::CreateDevices(Box::new(e)))?; let (pci, pci_irqs, pid_debug_label_map) = @@ -376,7 +400,7 @@ impl arch::LinuxArch for X8664arch { let mut io_bus = Self::setup_io_bus( &mut vm, - split_irqchip, + split_irqchip.is_some(), exit_evt.try_clone().map_err(Error::CloneEventFd)?, Some(pci_bus.clone()), components.memory_size, @@ -394,6 +418,17 @@ impl arch::LinuxArch for X8664arch { None => None, }; + if let Some((pic, _)) = &split_irqchip { + io_bus.insert(pic.clone(), 0x20, 0x2, true).unwrap(); + io_bus.insert(pic.clone(), 0xa0, 0x2, true).unwrap(); + io_bus.insert(pic.clone(), 0x4d0, 0x2, true).unwrap(); + + let mut irq_num = resources.allocate_irq().unwrap(); + while irq_num < kvm::NUM_IOAPIC_PINS as u32 { + irq_num = resources.allocate_irq().unwrap(); + } + } + match components.vm_image { VmImage::Bios(ref mut bios) => Self::load_bios(&mem, bios)?, VmImage::Kernel(ref mut kernel_image) => { @@ -447,6 +482,7 @@ impl arch::LinuxArch for X8664arch { vcpus, vcpu_affinity, irq_chip, + split_irqchip, io_bus, mmio_bus, pid_debug_label_map, -- cgit 1.4.1