From 43724a239b057e48eefd29489c57fd08cdfa8b8f Mon Sep 17 00:00:00 2001 From: Sonny Rao Date: Thu, 1 Feb 2018 15:52:58 -0800 Subject: [PATCH] crosvm: move x86_64 arch specific stuff into the x86_64 crate This is in preparation to make different architectures implement a trait, but for now it's just moving code out of linux.rs and into x86_64 trait. A few new functions were required which will become part of the trait interface. There's still a lot of ugly ifdefs everywhere that should go away in subsequent CLs. BUG=chromium:797868 TEST=./build_test TEST=run crosvm on caroline Change-Id: Ifc95d4eb84f64ebacb4481a172524d94dc96b7bb Signed-off-by: Sonny Rao Reviewed-on: https://chromium-review.googlesource.com/942084 Reviewed-by: Zach Reizner --- Cargo.lock | 4 + src/linux.rs | 188 +++++++++++++------------------------------ x86_64/Cargo.toml | 4 + x86_64/src/lib.rs | 198 +++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 244 insertions(+), 150 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fda25e90a7..59a26d03e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -286,6 +286,10 @@ version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "data_model 0.1.0", + "device_manager 0.1.0", + "devices 0.1.0", + "kernel_cmdline 0.1.0", + "kernel_loader 0.1.0", "kvm 0.1.0", "kvm_sys 0.1.0", "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/src/linux.rs b/src/linux.rs index f2d3d0328c..4b03743f66 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -20,7 +20,6 @@ use device_manager; use devices; use io_jail::{self, Minijail}; use kernel_cmdline; -use kernel_loader; use kvm::*; use net_util::Tap; use qcow::{self, QcowFile}; @@ -55,8 +54,6 @@ pub enum Error { Disk(io::Error), DiskImageLock(sys_util::Error), GetWaylandGroup(sys_util::Error), - LoadCmdline(kernel_loader::Error), - LoadKernel(kernel_loader::Error), NetDeviceNew(devices::virtio::NetError), NoVarEmpty, OpenKernel(PathBuf, io::Error), @@ -79,9 +76,13 @@ pub enum Error { WaylandDeviceNew(sys_util::Error), WaylandTempDir(sys_util::Error), #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - ConfigureSystem(x86_64::Error), + SetupSystemMemory(x86_64::Error), #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ConfigureVcpu(x86_64::Error), + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + LoadKernel(x86_64::Error), + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + SetupIoBus(x86_64::Error), } impl fmt::Display for Error { @@ -112,8 +113,6 @@ impl fmt::Display for Error { &Error::GetWaylandGroup(ref e) => { write!(f, "could not find gid for wayland group: {:?}", e) } - &Error::LoadCmdline(ref e) => write!(f, "error loading kernel command line: {:?}", e), - &Error::LoadKernel(ref e) => write!(f, "error loading kernel: {:?}", e), &Error::NetDeviceNew(ref e) => write!(f, "failed to set up virtio networking: {:?}", e), &Error::NoVarEmpty => write!(f, "/var/empty doesn't exist, can't jail devices."), &Error::OpenKernel(ref p, ref e) => { @@ -152,9 +151,14 @@ impl fmt::Display for Error { write!(f, "failed to create wayland device jail directroy: {:?}", e) } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - &Error::ConfigureSystem(ref e) => write!(f, "error configuring system: {:?}", e), + &Error::SetupSystemMemory(ref e) => write!(f, "error setting up system memory: {:?}", e), #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] &Error::ConfigureVcpu(ref e) => write!(f, "failed to configure vcpu: {:?}", e), + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + &Error::LoadKernel(ref e) => write!(f, "failed to load kernel: {:?}", e), + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + &Error::SetupIoBus(ref e) => write!(f, "failed to setup iobus: {:?}", e), + } } } @@ -179,10 +183,6 @@ impl Drop for UnlinkUnixDatagram { } } -const KERNEL_START_OFFSET: u64 = 0x200000; -const CMDLINE_OFFSET: u64 = 0x20000; -const CMDLINE_MAX_SIZE: u64 = KERNEL_START_OFFSET - CMDLINE_OFFSET; - fn create_base_minijail(root: &Path, seccomp_policy: &Path) -> Result { // All child jails run in a new user namespace without any users mapped, // they run as nobody unless otherwise configured. @@ -211,75 +211,6 @@ fn create_base_minijail(root: &Path, seccomp_policy: &Path) -> Result Ok(j) } -fn setup_memory(mem_size: usize) -> Result { - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - let arch_mem_regions = vec![(GuestAddress(0), mem_size as u64)]; - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - let arch_mem_regions = x86_64::arch_memory_regions(mem_size as u64); - GuestMemory::new(&arch_mem_regions).map_err(Error::CreateGuestMemory) -} - -fn setup_io_bus(vm: &mut Vm, - exit_evt: EventFd) - -> Result<(devices::Bus, Arc>)> { - struct NoDevice; - impl devices::BusDevice for NoDevice {} - - let mut io_bus = devices::Bus::new(); - - let com_evt_1_3 = EventFd::new().map_err(Error::CreateEventFd)?; - let com_evt_2_4 = EventFd::new().map_err(Error::CreateEventFd)?; - let stdio_serial = - Arc::new(Mutex::new(devices::Serial::new_out(com_evt_1_3 - .try_clone() - .map_err(Error::CloneEventFd)?, - Box::new(stdout())))); - let nul_device = Arc::new(Mutex::new(NoDevice)); - io_bus.insert(stdio_serial.clone(), 0x3f8, 0x8).unwrap(); - io_bus - .insert(Arc::new(Mutex::new(devices::Serial::new_sink(com_evt_2_4 - .try_clone() - .map_err(Error::CloneEventFd)?))), - 0x2f8, - 0x8) - .unwrap(); - io_bus - .insert(Arc::new(Mutex::new(devices::Serial::new_sink(com_evt_1_3 - .try_clone() - .map_err(Error::CloneEventFd)?))), - 0x3e8, - 0x8) - .unwrap(); - io_bus - .insert(Arc::new(Mutex::new(devices::Serial::new_sink(com_evt_2_4 - .try_clone() - .map_err(Error::CloneEventFd)?))), - 0x2e8, - 0x8) - .unwrap(); - io_bus - .insert(Arc::new(Mutex::new(devices::Cmos::new())), 0x70, 0x2) - .unwrap(); - io_bus - .insert(Arc::new(Mutex::new(devices::I8042Device::new(exit_evt - .try_clone() - .map_err(Error::CloneEventFd)?))), - 0x061, - 0x4) - .unwrap(); - io_bus.insert(nul_device.clone(), 0x040, 0x8).unwrap(); // ignore pit - io_bus.insert(nul_device.clone(), 0x0ed, 0x1).unwrap(); // most likely this one does nothing - io_bus.insert(nul_device.clone(), 0x0f0, 0x2).unwrap(); // ignore fpu - io_bus.insert(nul_device.clone(), 0xcf8, 0x8).unwrap(); // ignore pci - - vm.register_irqfd(&com_evt_1_3, 4) - .map_err(Error::RegisterIrqfd)?; - vm.register_irqfd(&com_evt_2_4, 3) - .map_err(Error::RegisterIrqfd)?; - - Ok((io_bus, stdio_serial)) -} - fn setup_mmio_bus(cfg: &Config, vm: &mut Vm, mem: &GuestMemory, @@ -288,8 +219,10 @@ fn setup_mmio_bus(cfg: &Config, balloon_device_socket: UnixDatagram) -> Result { static DEFAULT_PIVOT_ROOT: &'static str = "/var/empty"; - let mut device_manager = - device_manager::DeviceManager::new(vm, mem.clone(), 0x1000, 0xd0000000, 5); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + let mut device_manager = x86_64::get_device_manager(vm, mem.clone()); + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + let mut device_manager = device_manager::DeviceManager::new(vm, mem.clone(), 0, 0, 0); // An empty directory for jailed device's pivot root. let empty_root_path = Path::new(DEFAULT_PIVOT_ROOT); @@ -474,38 +407,6 @@ fn setup_mmio_bus(cfg: &Config, Ok(device_manager.bus) } -fn setup_system_memory(mem: &GuestMemory, - vcpu_count: u32, - mut kernel_image: File, - cmdline: &CStr) - -> Result<()> { - let kernel_start_addr = GuestAddress(KERNEL_START_OFFSET); - let cmdline_addr = GuestAddress(CMDLINE_OFFSET); - kernel_loader::load_kernel(mem, kernel_start_addr, &mut kernel_image) - .map_err(Error::LoadKernel)?; - kernel_loader::load_cmdline(mem, cmdline_addr, cmdline) - .map_err(Error::LoadCmdline)?; - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - x86_64::configure_system(mem, - kernel_start_addr, - cmdline_addr, - cmdline.to_bytes().len() + 1, - vcpu_count as u8) - .map_err(Error::ConfigureSystem)?; - Ok(()) -} - -fn setup_vm(kvm: &Kvm, mem: GuestMemory) -> Result { - let vm = Vm::new(&kvm, mem).map_err(Error::CreateVm)?; - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - 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().map_err(Error::CreateIrqChip)?; - Ok(vm) -} fn setup_vcpu(kvm: &Kvm, vm: &Vm, @@ -517,12 +418,10 @@ fn setup_vcpu(kvm: &Kvm, io_bus: devices::Bus, mmio_bus: devices::Bus) -> Result> { - let kernel_start_addr = GuestAddress(KERNEL_START_OFFSET); let vcpu = Vcpu::new(cpu_id as libc::c_ulong, &kvm, &vm) .map_err(Error::CreateVcpu)?; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] x86_64::configure_vcpu(vm.get_memory(), - kernel_start_addr, &kvm, &vcpu, cpu_id as u64, @@ -736,21 +635,42 @@ pub fn run_config(cfg: Config) -> Result<()> { let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?; let mem_size = cfg.memory.unwrap_or(256) << 20; - let mem = setup_memory(mem_size)?; + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + let mem = x86_64::setup_memory(mem_size).map_err(|e| Error::CreateGuestMemory(e))?; + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + let mem = GuestMemory::new(&vec![(GuestAddress(0), mem_size as u64)]). + map_err(|e| Error::CreateGuestMemory(e))?; + let kvm = Kvm::new().map_err(Error::CreateKvm)?; - let mut vm = setup_vm(&kvm, mem.clone())?; + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + let mut vm = x86_64::create_vm(&kvm, mem.clone()).map_err(|e| Error::CreateVm(e))?; + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + let mut vm = Vm::new(&kvm, mem.clone()).map_err(|e| Error::CreateVm(e))?; - let mut cmdline = kernel_cmdline::Cmdline::new(CMDLINE_MAX_SIZE as usize); - cmdline - .insert_str("console=ttyS0 noacpi reboot=k panic=1 pci=off") - .unwrap(); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + let mut cmdline = x86_64::get_base_linux_cmdline(); + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + let mut cmdline = kernel_cmdline::Cmdline::new(128); - // Put device memory at nearest 2MB boundary after physical memory - const MB: u64 = 1024 * 1024; - let mem_size_round_2mb = (mem_size as u64 + 2*MB - 1) / (2*MB) * (2*MB); - let mut next_dev_pfn = mem_size_round_2mb / pagesize() as u64; - let (io_bus, stdio_serial) = setup_io_bus(&mut vm, - exit_evt.try_clone().map_err(Error::CloneEventFd)?)?; + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + let mut next_dev_pfn = x86_64::get_base_dev_pfn(mem_size as u64); + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + let mut next_dev_pfn = 0; + + let mut control_sockets = Vec::new(); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + let (io_bus, stdio_serial) = x86_64::setup_io_bus(&mut vm, + exit_evt.try_clone(). + map_err(Error::CloneEventFd)?). + map_err(|e| Error::SetupIoBus(e))?; + // The non x86 case is kind of bogus using the exit_evt as an fd for serial + // It's purpose is just to make the build happy since it doesn't actually run anyway + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + let (io_bus, stdio_serial) = (devices::Bus::new(), + Arc::new(Mutex::new( + devices::Serial::new_out(exit_evt.try_clone(). + map_err(Error::CloneEventFd)?, + Box::new(stdout()))))); let (balloon_host_socket, balloon_device_socket) = UnixDatagram::pair() .map_err(Error::CreateSocket)?; @@ -768,10 +688,14 @@ pub fn run_config(cfg: Config) -> Result<()> { let vcpu_count = cfg.vcpu_count.unwrap_or(1); let kernel_image = File::open(cfg.kernel_path.as_path()) .map_err(|e| Error::OpenKernel(cfg.kernel_path.clone(), e))?; - setup_system_memory(&mem, - vcpu_count, - kernel_image, - &CString::new(cmdline).unwrap())?; + + // separate out load_kernel from other setup to get a specific error for + // kernel loading + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + x86_64::load_kernel(&mem, kernel_image).map_err(|e| Error::LoadKernel(e))?; + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + x86_64::setup_system_memory(&mem, vcpu_count, &CString::new(cmdline).unwrap()). + map_err(|e| Error::SetupSystemMemory(e))?; let mut vcpu_handles = Vec::with_capacity(vcpu_count as usize); let vcpu_thread_barrier = Arc::new(Barrier::new((vcpu_count + 1) as usize)); diff --git a/x86_64/Cargo.toml b/x86_64/Cargo.toml index 85ff1b7d5f..edad6b6f4d 100644 --- a/x86_64/Cargo.toml +++ b/x86_64/Cargo.toml @@ -5,8 +5,12 @@ authors = ["The Chromium OS Authors"] [dependencies] data_model = { path = "../data_model" } +devices = { path = "../devices" } +device_manager = { path = "../device_manager" } kvm_sys = { path = "../kvm_sys" } kvm = { path = "../kvm" } sys_util = { path = "../sys_util" } +kernel_cmdline = { path = "../kernel_cmdline" } +kernel_loader = { path = "../kernel_loader" } libc = "*" byteorder = "*" diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index 30c4b138cf..473550e04c 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -4,10 +4,14 @@ extern crate byteorder; extern crate data_model; +extern crate devices; +extern crate device_manager; extern crate kvm; extern crate kvm_sys; extern crate libc; extern crate sys_util; +extern crate kernel_cmdline; +extern crate kernel_loader; #[allow(dead_code)] #[allow(non_upper_case_globals)] @@ -55,10 +59,15 @@ mod regs; use std::mem; use std::result; +use std::fs::File; +use std::ffi::CStr; +use std::sync::{Arc, Mutex}; +use std::io::stdout; use bootparam::boot_params; use bootparam::E820_RAM; -use sys_util::{GuestAddress, GuestMemory}; +use sys_util::{EventFd, GuestAddress, GuestMemory}; +use kvm::*; pub use regs::Error as RegError; pub use interrupts::Error as IntError; @@ -66,16 +75,26 @@ pub use mptable::Error as MpTableError; #[derive(Debug)] pub enum Error { + /// Error configuring the system + ConfigureSystem, /// Error configuring the VCPU. CpuSetup(cpuid::Error), + /// Unable to clone an EventFd + CloneEventFd(sys_util::Error), + /// Unable to make an EventFd + CreateEventFd(sys_util::Error), /// The kernel extends past the end of RAM KernelOffsetPastEnd, /// Error configuring the VCPU registers. RegisterConfiguration(RegError), /// Error configuring the VCPU floating point registers. FpuRegisterConfiguration(RegError), + /// Error registering an IrqFd + RegisterIrqfd(sys_util::Error), /// Error configuring the VCPU segment registers. SegmentRegisterConfiguration(RegError), + LoadCmdline(kernel_loader::Error), + LoadKernel(kernel_loader::Error), /// Error configuring the VCPU local interrupt. LocalIntConfiguration(IntError), /// Error writing MP table to memory. @@ -95,11 +114,163 @@ const FIRST_ADDR_PAST_32BITS: u64 = (1 << 32); const KERNEL_64BIT_ENTRY_OFFSET: u64 = 0x200; const ZERO_PAGE_OFFSET: u64 = 0x7000; +const KERNEL_START_OFFSET: u64 = 0x200000; +const CMDLINE_OFFSET: u64 = 0x20000; +const CMDLINE_MAX_SIZE: u64 = KERNEL_START_OFFSET - CMDLINE_OFFSET; + +/// Loads the kernel from an open file. +/// +/// # Arguments +/// +/// * `mem` - The memory to be used by the guest. +/// * `kernel_image` - the File object for the specified kernel. +pub fn load_kernel(mem: &GuestMemory, mut kernel_image: File) -> Result<()> { + kernel_loader::load_kernel(mem, GuestAddress(KERNEL_START_OFFSET), &mut kernel_image) + .map_err(|e| Error::LoadKernel(e))?; + Ok(()) +} + +/// Configures the system memory space should be called once per vm before +/// starting vcpu threads. +/// +/// # Arguments +/// +/// * `mem` - The memory to be used by the guest. +/// * `vcpu_count` - Number of virtual CPUs the guest will have. +/// * `cmdline` - the kernel commandline +pub fn setup_system_memory(mem: &GuestMemory, vcpu_count: u32, cmdline: &CStr) -> Result<()> { + kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline) + .map_err(|e| Error::LoadCmdline(e))?; + configure_system(mem, GuestAddress(KERNEL_START_OFFSET), GuestAddress(CMDLINE_OFFSET), + cmdline.to_bytes().len() + 1, vcpu_count as u8) + .map_err(|_| Error::ConfigureSystem)?; + Ok(()) +} + +/// Creates a new VM object and initializes architecture specific devices +/// +/// # Arguments +/// +/// * `kvm` - The opened /dev/kvm object. +/// * `mem` - The memory to be used by the guest. +pub fn create_vm(kvm: &Kvm, mem: GuestMemory) -> result::Result { + 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()?; + Ok(vm) +} + +/// This creates a GuestMemory object for this VM +/// +/// * `mem_size` - Desired physical memory size for this VM +pub fn setup_memory(mem_size: usize) -> result::Result { + let arch_mem_regions = arch_memory_regions(mem_size as u64); + GuestMemory::new(&arch_mem_regions) +} + +/// This returns the first page frame number for use by the balloon driver. +pub fn get_base_dev_pfn(mem_size: u64) -> u64 { + // Put device memory at nearest 2MB boundary after physical memory + const MB: u64 = 1024 * 1024; + let mem_size_round_2mb = (mem_size + 2*MB - 1) / (2*MB) * (2*MB); + mem_size_round_2mb / sys_util::pagesize() as u64 +} + +/// This returns a base part of the kernel command for this architecture +pub fn get_base_linux_cmdline() -> kernel_cmdline::Cmdline { + let mut cmdline = kernel_cmdline::Cmdline::new(CMDLINE_MAX_SIZE as usize); + cmdline.insert_str("console=ttyS0 noacpi reboot=k panic=1 pci=off"). + unwrap(); + cmdline +} + +/// This creates and returns a device_manager object for this vm. +/// +/// # Arguments +/// +/// * `vm` - the vm object +/// * `mem` - A copy of the GuestMemory object for this VM. +pub fn get_device_manager(vm: &mut Vm, mem: GuestMemory) -> device_manager::DeviceManager { + const MMIO_BASE: u64 = 0xd0000000; + const MMIO_LEN: u64 = 0x1000; + const IRQ_BASE: u32 = 5; + + device_manager::DeviceManager::new(vm, mem, MMIO_LEN, MMIO_BASE, IRQ_BASE) +} + +/// Sets up the IO bus for this platform +/// +/// # Arguments +/// +/// * - `vm` the vm object +/// * - `exit_evt` - the event fd object which should receive exit events +pub fn setup_io_bus(vm: &mut Vm, exit_evt: EventFd) + -> Result<(devices::Bus, Arc>)> { + struct NoDevice; + impl devices::BusDevice for NoDevice {} + + let mut io_bus = devices::Bus::new(); + + let com_evt_1_3 = EventFd::new().map_err(Error::CreateEventFd)?; + let com_evt_2_4 = EventFd::new().map_err(Error::CreateEventFd)?; + let stdio_serial = + Arc::new(Mutex::new(devices::Serial::new_out(com_evt_1_3 + .try_clone() + .map_err(Error::CloneEventFd)?, + Box::new(stdout())))); + let nul_device = Arc::new(Mutex::new(NoDevice)); + io_bus.insert(stdio_serial.clone(), 0x3f8, 0x8).unwrap(); + io_bus + .insert(Arc::new(Mutex::new(devices::Serial::new_sink(com_evt_2_4 + .try_clone() + .map_err(Error::CloneEventFd)?))), + 0x2f8, + 0x8) + .unwrap(); + io_bus + .insert(Arc::new(Mutex::new(devices::Serial::new_sink(com_evt_1_3 + .try_clone() + .map_err(Error::CloneEventFd)?))), + 0x3e8, + 0x8) + .unwrap(); + io_bus + .insert(Arc::new(Mutex::new(devices::Serial::new_sink(com_evt_2_4 + .try_clone() + .map_err(Error::CloneEventFd)?))), + 0x2e8, + 0x8) + .unwrap(); + io_bus + .insert(Arc::new(Mutex::new(devices::Cmos::new())), 0x70, 0x2) + .unwrap(); + io_bus + .insert(Arc::new(Mutex::new(devices::I8042Device::new(exit_evt + .try_clone() + .map_err(Error::CloneEventFd)?))), + 0x061, + 0x4) + .unwrap(); + io_bus.insert(nul_device.clone(), 0x040, 0x8).unwrap(); // ignore pit + io_bus.insert(nul_device.clone(), 0x0ed, 0x1).unwrap(); // most likely this one does nothing + io_bus.insert(nul_device.clone(), 0x0f0, 0x2).unwrap(); // ignore fpu + io_bus.insert(nul_device.clone(), 0xcf8, 0x8).unwrap(); // ignore pci + + vm.register_irqfd(&com_evt_1_3, 4) + .map_err(Error::RegisterIrqfd)?; + vm.register_irqfd(&com_evt_2_4, 3) + .map_err(Error::RegisterIrqfd)?; + + Ok((io_bus, stdio_serial)) +} + /// Returns a Vec of the valid memory addresses. /// These should be used to configure the GuestMemory structure for the platfrom. /// For x86_64 all addresses are valid from the start of the kenel except a /// carve out at the end of 32bit address space. -pub fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> { +fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> { let mem_end = GuestAddress(size); let first_addr_past_32bits = GuestAddress(FIRST_ADDR_PAST_32BITS); let end_32bit_gap_start = GuestAddress(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE); @@ -128,12 +299,12 @@ pub fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> { /// * `cpu_id` - The id of the given `vcpu`. /// * `num_cpus` - Number of virtual CPUs the guest will have. pub fn configure_vcpu(guest_mem: &GuestMemory, - kernel_load_addr: GuestAddress, kvm: &kvm::Kvm, vcpu: &kvm::Vcpu, cpu_id: u64, num_cpus: u64) -> Result<()> { + let kernel_load_addr = GuestAddress(KERNEL_START_OFFSET); cpuid::setup_cpuid(kvm, vcpu, cpu_id, num_cpus).map_err(Error::CpuSetup)?; regs::setup_msrs(vcpu).map_err(Error::RegisterConfiguration)?; let kernel_end = guest_mem.checked_offset(kernel_load_addr, KERNEL_64BIT_ENTRY_OFFSET) @@ -148,21 +319,12 @@ pub fn configure_vcpu(guest_mem: &GuestMemory, Ok(()) } -/// Configures the system and should be called once per vm before starting vcpu threads. -/// -/// # Arguments -/// -/// * `guest_mem` - The memory to be used by the guest. -/// * `kernel_addr` - Address in `guest_mem` where the kernel was loaded. -/// * `cmdline_addr` - Address in `guest_mem` where the kernel command line was loaded. -/// * `cmdline_size` - Size of the kernel command line in bytes including the null terminator. -/// * `num_cpus` - Number of virtual CPUs the guest will have. -pub fn configure_system(guest_mem: &GuestMemory, - kernel_addr: GuestAddress, - cmdline_addr: GuestAddress, - cmdline_size: usize, - num_cpus: u8) - -> Result<()> { +fn configure_system(guest_mem: &GuestMemory, + kernel_addr: GuestAddress, + cmdline_addr: GuestAddress, + cmdline_size: usize, + num_cpus: u8) + -> Result<()> { const EBDA_START: u64 = 0x0009fc00; const KERNEL_BOOT_FLAG_MAGIC: u16 = 0xaa55; const KERNEL_HDR_MAGIC: u32 = 0x53726448;