diff options
-rw-r--r-- | aarch64/src/lib.rs | 6 | ||||
-rw-r--r-- | arch/src/lib.rs | 7 | ||||
-rw-r--r-- | src/linux.rs | 2 | ||||
-rw-r--r-- | src/main.rs | 7 | ||||
-rw-r--r-- | x86_64/src/lib.rs | 48 |
5 files changed, 58 insertions, 12 deletions
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index 48effe5..6bbc775 100644 --- a/aarch64/src/lib.rs +++ b/aarch64/src/lib.rs @@ -190,7 +190,11 @@ fn fdt_offset(mem_size: u64) -> u64 { pub struct AArch64; impl arch::LinuxArch for AArch64 { - fn build_vm<F>(mut components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm> + fn build_vm<F>( + mut components: VmComponents, + _split_irqchip: bool, + virtio_devs: F, + ) -> Result<RunnableLinuxVm> where F: FnOnce( &GuestMemory, diff --git a/arch/src/lib.rs b/arch/src/lib.rs index 795591a..e6814bc 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -74,8 +74,13 @@ pub trait LinuxArch { /// # Arguments /// /// * `components` - Parts to use to build the VM. + /// * `split_irqchip` - whether to use a split IRQ chip (i.e. userspace PIT/PIC/IOAPIC) /// * `virtio_devs` - Function to generate a list of virtio devices. - fn build_vm<F>(components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm> + fn build_vm<F>( + components: VmComponents, + split_irqchip: bool, + virtio_devs: F, + ) -> Result<RunnableLinuxVm> where F: FnOnce( &GuestMemory, diff --git a/src/linux.rs b/src/linux.rs index d2e0610..beb1021 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -1011,7 +1011,7 @@ pub fn run_config(cfg: Config) -> Result<()> { disk_host_sockets.push(disk_host_socket); } - let linux = Arch::build_vm(components, |m, e| { + let linux = Arch::build_vm(components, cfg.split_irqchip, |m, e| { create_virtio_devs( cfg, m, diff --git a/src/main.rs b/src/main.rs index 8e83621..31019f9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -120,6 +120,7 @@ pub struct Config { virtio_mouse: Option<PathBuf>, virtio_keyboard: Option<PathBuf>, virtio_input_evdevs: Vec<PathBuf>, + split_irqchip: bool, } impl Default for Config { @@ -153,6 +154,7 @@ impl Default for Config { virtio_mouse: None, virtio_keyboard: None, virtio_input_evdevs: Vec::new(), + split_irqchip: false, } } } @@ -564,6 +566,9 @@ fn set_argument(cfg: &mut Config, name: &str, value: Option<&str>) -> argument:: } cfg.virtio_input_evdevs.push(dev_path); } + "split-irqchip" => { + cfg.split_irqchip = true; + } "help" => return Err(argument::Error::PrintHelp), _ => unreachable!(), } @@ -627,6 +632,8 @@ fn run_vm(args: std::env::Args) -> std::result::Result<(), ()> { Argument::value("trackpad", "PATH:WIDTH:HEIGHT", "Path to a socket from where to read trackpad input events and write status updates to, optionally followed by screen width and height (defaults to 800x1280)."), Argument::value("mouse", "PATH", "Path to a socket from where to read mouse input events and write status updates to."), Argument::value("keyboard", "PATH", "Path to a socket from where to read keyboard input events and write status updates to."), + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + Argument::flag("split-irqchip", "(EXPERIMENTAL) enable split-irqchip support"), Argument::short_flag('h', "help", "Print help message.")]; let mut cfg = Config::default(); diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index ed5637d..b65fe46 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -83,7 +83,7 @@ use io_jail::Minijail; use kvm::*; use resources::{AddressRanges, SystemAllocator}; use sync::Mutex; -use sys_util::{EventFd, GuestAddress, GuestMemory}; +use sys_util::{Clock, EventFd, GuestAddress, GuestMemory}; #[derive(Debug)] pub enum Error { @@ -95,6 +95,8 @@ pub enum Error { Cmdline(kernel_cmdline::Error), /// Unable to make an EventFd CreateEventFd(sys_util::Error), + /// Unable to create PIT device. + CreatePit(devices::PitError), /// Unable to create Kvm. CreateKvm(sys_util::Error), /// Unable to create a PciRoot hub. @@ -126,6 +128,7 @@ impl error::Error for Error { Error::CloneEventFd(_) => "Unable to clone an EventFd", Error::Cmdline(_) => "the given kernel command line was invalid", Error::CreateEventFd(_) => "Unable to make an EventFd", + Error::CreatePit(_) => "Unable to make Pit device", Error::CreateKvm(_) => "failed to open /dev/kvm", Error::CreatePciRoot(_) => "failed to create a PCI root hub", Error::CreateSocket(_) => "failed to create socket", @@ -286,7 +289,11 @@ fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> { } impl arch::LinuxArch for X8664arch { - fn build_vm<F>(mut components: VmComponents, virtio_devs: F) -> Result<RunnableLinuxVm> + fn build_vm<F>( + mut components: VmComponents, + split_irqchip: bool, + virtio_devs: F, + ) -> Result<RunnableLinuxVm> where F: FnOnce( &GuestMemory, @@ -297,7 +304,7 @@ impl arch::LinuxArch for X8664arch { Self::get_resource_allocator(components.memory_mb, components.wayland_dmabuf); let mem = Self::setup_memory(components.memory_mb)?; let kvm = Kvm::new().map_err(Error::CreateKvm)?; - let mut vm = Self::create_vm(&kvm, mem.clone())?; + let mut vm = Self::create_vm(&kvm, split_irqchip, mem.clone())?; let vcpu_count = components.vcpu_count; let mut vcpus = Vec::with_capacity(vcpu_count as usize); @@ -329,6 +336,7 @@ impl arch::LinuxArch for X8664arch { let (io_bus, stdio_serial) = Self::setup_io_bus( &mut vm, + split_irqchip, exit_evt.try_clone().map_err(Error::CloneEventFd)?, Some(pci_bus.clone()), )?; @@ -418,13 +426,16 @@ impl X8664arch { /// # Arguments /// /// * `kvm` - The opened /dev/kvm object. + /// * `split_irqchip` - Whether to use a split IRQ chip. /// * `mem` - The memory to be used by the guest. - fn create_vm(kvm: &Kvm, mem: GuestMemory) -> Result<Vm> { + fn create_vm(kvm: &Kvm, split_irqchip: bool, mem: GuestMemory) -> Result<Vm> { let vm = Vm::new(&kvm, mem)?; let tss_addr = GuestAddress(0xfffbd000); vm.set_tss_addr(tss_addr).expect("set tss addr failed"); - vm.create_pit().expect("create pit failed"); - vm.create_irq_chip()?; + if !split_irqchip { + vm.create_pit().expect("create pit failed"); + vm.create_irq_chip()?; + } Ok(vm) } @@ -490,9 +501,11 @@ impl X8664arch { /// # Arguments /// /// * - `vm` the vm object + /// * - `split_irqchip`: whether to use a split IRQ chip (i.e. userspace PIT/PIC/IOAPIC) /// * - `exit_evt` - the event fd object which should receive exit events fn setup_io_bus( vm: &mut Vm, + split_irqchip: bool, exit_evt: EventFd, pci: Option<Arc<Mutex<devices::PciConfigIo>>>, ) -> Result<(devices::Bus, Arc<Mutex<devices::Serial>>)> { @@ -558,9 +571,26 @@ impl X8664arch { false, ) .unwrap(); - io_bus - .insert(nul_device.clone(), 0x040, 0x8, false) - .unwrap(); // ignore pit + + if split_irqchip { + let pit_evt = EventFd::new().map_err(Error::CreateEventFd)?; + let pit = Arc::new(Mutex::new( + devices::Pit::new( + pit_evt.try_clone().map_err(Error::CloneEventFd)?, + Arc::new(Mutex::new(Clock::new())), + ) + .map_err(Error::CreatePit)?, + )); + // Reserve from 0x40 to 0x61 (the speaker). + io_bus.insert(pit.clone(), 0x040, 0x22, false).unwrap(); + vm.register_irqfd(&pit_evt, 0) + .map_err(Error::RegisterIrqfd)?; + } else { + io_bus + .insert(nul_device.clone(), 0x040, 0x8, false) + .unwrap(); // ignore pit + } + io_bus .insert(nul_device.clone(), 0x0ed, 0x1, false) .unwrap(); // most likely this one does nothing |