summary refs log tree commit diff
diff options
context:
space:
mode:
authorZhuocheng Ding <zhuocheng.ding@intel.corp-partner.google.com>2019-12-02 15:50:20 +0800
committerCommit Bot <commit-bot@chromium.org>2020-03-05 01:02:48 +0000
commitf2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7 (patch)
tree20a8210f21c3e530c80e45146fbb91f284064507
parent50740cece43671cc42035f92cde460aad3d29494 (diff)
downloadcrosvm-f2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7.tar
crosvm-f2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7.tar.gz
crosvm-f2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7.tar.bz2
crosvm-f2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7.tar.lz
crosvm-f2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7.tar.xz
crosvm-f2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7.tar.zst
crosvm-f2e90bf0b0ca101d2925e91ca50d3e9e5ea2fdb7.zip
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 <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Zhuocheng Ding <zhuocheng.ding@intel.corp-partner.google.com>
-rw-r--r--Cargo.lock3
-rw-r--r--aarch64/Cargo.toml1
-rw-r--r--aarch64/src/lib.rs3
-rw-r--r--arch/Cargo.toml1
-rw-r--r--arch/src/lib.rs3
-rw-r--r--devices/src/ioapic.rs14
-rw-r--r--devices/src/lib.rs2
-rw-r--r--kvm/src/lib.rs9
-rw-r--r--src/linux.rs14
-rw-r--r--x86_64/Cargo.toml1
-rw-r--r--x86_64/src/lib.rs40
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<F, E>(
         mut components: VmComponents,
         _split_irqchip: bool,
+        _ioapic_device_socket: VmIrqRequestSocket,
         serial_parameters: &BTreeMap<u8, SerialParameters>,
         serial_jail: Option<Minijail>,
         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<Vcpu>,
     pub vcpu_affinity: Vec<usize>,
     pub irq_chip: Option<File>,
+    pub split_irqchip: Option<(Arc<Mutex<devices::Pic>>, Arc<Mutex<devices::Ioapic>>)>,
     pub io_bus: Bus,
     pub mmio_bus: Bus,
     pub pid_debug_label_map: BTreeMap<u32, String>,
@@ -88,6 +90,7 @@ pub trait LinuxArch {
     fn build_vm<F, E>(
         components: VmComponents,
         split_irqchip: bool,
+        ioapic_device_socket: VmIrqRequestSocket,
         serial_parameters: &BTreeMap<u8, SerialParameters>,
         serial_jail: Option<Minijail>,
         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<Barrier>,
     io_bus: devices::Bus,
     mmio_bus: devices::Bus,
+    split_irqchip: Option<(Arc<Mutex<devices::Pic>>, Arc<Mutex<devices::Ioapic>>)>,
     exit_evt: EventFd,
     requires_kvmclock_ctrl: bool,
     run_mode_arc: Arc<VcpuRunMode>,
@@ -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::<VmMemoryResponse, VmMemoryRequest>().map_err(Error::CreateSocket)?;
     control_sockets.push(TaggedControlSocket::VmMemory(gpu_host_socket));
 
+    let (ioapic_host_socket, ioapic_device_socket) =
+        msg_socket::pair::<VmIrqResponse, VmIrqRequest>().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<dyn StdError>),
     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<F, E>(
         mut components: VmComponents,
         split_irqchip: bool,
+        ioapic_device_socket: VmIrqRequestSocket,
         serial_parameters: &BTreeMap<u8, SerialParameters>,
         serial_jail: Option<Minijail>,
         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,