mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-05 10:10:41 +00:00
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>
This commit is contained in:
parent
50740cece4
commit
f2e90bf0b0
11 changed files with 80 additions and 11 deletions
3
Cargo.lock
generated
3
Cargo.lock
generated
|
@ -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]
|
||||
|
|
|
@ -17,3 +17,4 @@ remain = "*"
|
|||
resources = { path = "../resources" }
|
||||
sync = { path = "../sync" }
|
||||
sys_util = { path = "../sys_util" }
|
||||
vm_control = { path = "../vm_control" }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -13,3 +13,4 @@ libc = "*"
|
|||
resources = { path = "../resources" }
|
||||
sync = { path = "../sync" }
|
||||
sys_util = { path = "../sys_util" }
|
||||
vm_control = { path = "../vm_control" }
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
|
|
14
src/linux.rs
14
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(),
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue