diff options
-rw-r--r-- | aarch64/src/fdt.rs | 27 | ||||
-rw-r--r-- | aarch64/src/lib.rs | 110 | ||||
-rw-r--r-- | arch/src/fdt.rs | 54 | ||||
-rw-r--r-- | arch/src/lib.rs | 30 | ||||
-rw-r--r-- | src/linux.rs | 7 | ||||
-rw-r--r-- | x86_64/src/fdt.rs | 4 | ||||
-rw-r--r-- | x86_64/src/lib.rs | 136 |
7 files changed, 187 insertions, 181 deletions
diff --git a/aarch64/src/fdt.rs b/aarch64/src/fdt.rs index ff3274f..b03d039 100644 --- a/aarch64/src/fdt.rs +++ b/aarch64/src/fdt.rs @@ -6,7 +6,7 @@ use std::ffi::CStr; use arch::fdt::{ begin_node, end_node, finish_fdt, generate_prop32, generate_prop64, property, property_cstring, - property_null, property_string, property_u32, property_u64, start_fdt, Error, + property_null, property_string, property_u32, property_u64, start_fdt, Error, Result, }; use devices::PciInterruptPin; use sys_util::{GuestAddress, GuestMemory}; @@ -54,7 +54,7 @@ const IRQ_TYPE_EDGE_RISING: u32 = 0x00000001; const IRQ_TYPE_LEVEL_HIGH: u32 = 0x00000004; const IRQ_TYPE_LEVEL_LOW: u32 = 0x00000008; -fn create_memory_node(fdt: &mut Vec<u8>, guest_mem: &GuestMemory) -> Result<(), Box<Error>> { +fn create_memory_node(fdt: &mut Vec<u8>, guest_mem: &GuestMemory) -> Result<()> { let mem_size = guest_mem.memory_size(); let mem_reg_prop = generate_prop64(&[AARCH64_PHYS_MEM_START, mem_size]); @@ -65,7 +65,7 @@ fn create_memory_node(fdt: &mut Vec<u8>, guest_mem: &GuestMemory) -> Result<(), Ok(()) } -fn create_cpu_nodes(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<(), Box<Error>> { +fn create_cpu_nodes(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<()> { begin_node(fdt, "cpus")?; property_u32(fdt, "#address-cells", 0x1)?; property_u32(fdt, "#size-cells", 0x0)?; @@ -85,7 +85,7 @@ fn create_cpu_nodes(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<(), Box<Error>> Ok(()) } -fn create_gic_node(fdt: &mut Vec<u8>) -> Result<(), Box<Error>> { +fn create_gic_node(fdt: &mut Vec<u8>) -> Result<()> { let gic_reg_prop = generate_prop64(&[ AARCH64_GIC_DIST_BASE, AARCH64_GIC_DIST_SIZE, @@ -106,7 +106,7 @@ fn create_gic_node(fdt: &mut Vec<u8>) -> Result<(), Box<Error>> { Ok(()) } -fn create_timer_node(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<(), Box<Error>> { +fn create_timer_node(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<()> { // These are fixed interrupt numbers for the timer device. let irqs = [13, 14, 11, 10]; let compatible = "arm,armv8-timer"; @@ -130,7 +130,7 @@ fn create_timer_node(fdt: &mut Vec<u8>, num_cpus: u32) -> Result<(), Box<Error>> Ok(()) } -fn create_serial_node(fdt: &mut Vec<u8>) -> Result<(), Box<Error>> { +fn create_serial_node(fdt: &mut Vec<u8>) -> Result<()> { let serial_reg_prop = generate_prop64(&[AARCH64_SERIAL_ADDR, AARCH64_SERIAL_SIZE]); let irq = generate_prop32(&[ GIC_FDT_IRQ_TYPE_SPI, @@ -149,7 +149,7 @@ fn create_serial_node(fdt: &mut Vec<u8>) -> Result<(), Box<Error>> { } // TODO(sonnyrao) -- check to see if host kernel supports PSCI 0_2 -fn create_psci_node(fdt: &mut Vec<u8>) -> Result<(), Box<Error>> { +fn create_psci_node(fdt: &mut Vec<u8>) -> Result<()> { let compatible = "arm,psci-0.2"; begin_node(fdt, "psci")?; property_string(fdt, "compatible", compatible)?; @@ -169,7 +169,7 @@ fn create_chosen_node( fdt: &mut Vec<u8>, cmdline: &CStr, initrd: Option<(GuestAddress, usize)>, -) -> Result<(), Box<Error>> { +) -> Result<()> { begin_node(fdt, "chosen")?; property_u32(fdt, "linux,pci-probe-only", 1)?; property_cstring(fdt, "bootargs", cmdline)?; @@ -185,10 +185,7 @@ fn create_chosen_node( Ok(()) } -fn create_pci_nodes( - fdt: &mut Vec<u8>, - pci_irqs: Vec<(u32, PciInterruptPin)>, -) -> Result<(), Box<Error>> { +fn create_pci_nodes(fdt: &mut Vec<u8>, pci_irqs: Vec<(u32, PciInterruptPin)>) -> Result<()> { // Add devicetree nodes describing a PCI generic host controller. // See Documentation/devicetree/bindings/pci/host-generic-pci.txt in the kernel // and "PCI Bus Binding to IEEE Std 1275-1994". @@ -258,7 +255,7 @@ fn create_pci_nodes( Ok(()) } -fn create_rtc_node(fdt: &mut Vec<u8>) -> Result<(), Box<Error>> { +fn create_rtc_node(fdt: &mut Vec<u8>) -> Result<()> { // the kernel driver for pl030 really really wants a clock node // associated with an AMBA device or it will fail to probe, so we // need to make up a clock node to associate with the pl030 rtc @@ -306,7 +303,7 @@ pub fn create_fdt( fdt_load_offset: u64, cmdline: &CStr, initrd: Option<(GuestAddress, usize)>, -) -> Result<(), Box<Error>> { +) -> Result<()> { let mut fdt = vec![0; fdt_max_size]; start_fdt(&mut fdt, fdt_max_size)?; @@ -338,7 +335,7 @@ pub fn create_fdt( .write_at_addr(fdt_final.as_slice(), fdt_address) .map_err(|_| Error::FdtGuestMemoryWriteError)?; if written < fdt_max_size { - return Err(Box::new(Error::FdtGuestMemoryWriteError)); + return Err(Error::FdtGuestMemoryWriteError); } Ok(()) } diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs index 58496ec..85e1076 100644 --- a/aarch64/src/lib.rs +++ b/aarch64/src/lib.rs @@ -14,6 +14,7 @@ extern crate resources; extern crate sync; extern crate sys_util; +use std::error::Error as StdError; use std::ffi::{CStr, CString}; use std::fmt::{self, Display}; use std::fs::File; @@ -26,12 +27,11 @@ use devices::{Bus, BusError, PciConfigMmio, PciDevice, PciInterruptPin}; use io_jail::Minijail; use resources::{AddressRanges, SystemAllocator}; use sync::Mutex; -use sys_util::{EventFd, GuestAddress, GuestMemory}; +use sys_util::{EventFd, GuestAddress, GuestMemory, GuestMemoryError}; use kvm::*; use kvm_sys::kvm_device_attr; -use arch::Result; mod fdt; // We place the kernel at offset 8MB @@ -117,40 +117,29 @@ const AARCH64_IRQ_BASE: u32 = 2; #[derive(Debug)] pub enum Error { - /// Unable to clone an EventFd CloneEventFd(sys_util::Error), - /// Error creating kernel command line. Cmdline(kernel_cmdline::Error), - /// Unable to make an EventFd + CreateDevices(Box<dyn StdError>), CreateEventFd(sys_util::Error), - /// Unable to create Kvm. + CreateFdt(arch::fdt::Error), + CreateGICFailure(sys_util::Error), CreateKvm(sys_util::Error), - /// Unable to create a PciRoot hub. CreatePciRoot(arch::DeviceRegistrationError), - /// Unable to create socket. CreateSocket(io::Error), - /// Unable to create Vcpu. CreateVcpu(sys_util::Error), - /// FDT could not be created - FDTCreateFailure(Box<std::error::Error>), - /// Kernel could not be loaded - KernelLoadFailure(arch::LoadImageError), - /// Initrd could not be loaded + CreateVm(sys_util::Error), InitrdLoadFailure(arch::LoadImageError), - /// Failure to Create GIC - CreateGICFailure(sys_util::Error), - /// Couldn't register PCI bus. + KernelLoadFailure(arch::LoadImageError), + ReadPreferredTarget(sys_util::Error), + RegisterIrqfd(sys_util::Error), RegisterPci(BusError), - /// Couldn't register virtio socket. RegisterVsock(arch::DeviceRegistrationError), - /// VCPU Init failed - VCPUInitFailure, - /// VCPU Set one reg failed - VCPUSetRegFailure, + SetDeviceAttr(sys_util::Error), + SetReg(sys_util::Error), + SetupGuestMemory(GuestMemoryError), + VcpuInit(sys_util::Error), } -impl std::error::Error for Error {} - impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; @@ -158,23 +147,33 @@ impl Display for Error { match self { CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e), Cmdline(e) => write!(f, "the given kernel command line was invalid: {}", e), + CreateDevices(e) => write!(f, "error creating devices: {}", e), CreateEventFd(e) => write!(f, "unable to make an EventFd: {}", e), + CreateFdt(e) => write!(f, "FDT could not be created: {}", e), + CreateGICFailure(e) => write!(f, "failed to create GIC: {}", e), CreateKvm(e) => write!(f, "failed to open /dev/kvm: {}", e), CreatePciRoot(e) => write!(f, "failed to create a PCI root hub: {}", e), CreateSocket(e) => write!(f, "failed to create socket: {}", e), CreateVcpu(e) => write!(f, "failed to create VCPU: {}", e), - FDTCreateFailure(e) => write!(f, "FDT could not be created: {}", e), - KernelLoadFailure(e) => write!(f, "kernel cound not be loaded: {}", e), + CreateVm(e) => write!(f, "failed to create vm: {}", e), InitrdLoadFailure(e) => write!(f, "initrd cound not be loaded: {}", e), - CreateGICFailure(e) => write!(f, "failed to create GIC: {}", e), + KernelLoadFailure(e) => write!(f, "kernel cound not be loaded: {}", e), + ReadPreferredTarget(e) => write!(f, "failed to read preferred target: {}", e), + RegisterIrqfd(e) => write!(f, "failed to register irq fd: {}", e), RegisterPci(e) => write!(f, "error registering PCI bus: {}", e), RegisterVsock(e) => write!(f, "error registering virtual socket device: {}", e), - VCPUInitFailure => write!(f, "failed to initialize VCPU"), - VCPUSetRegFailure => write!(f, "failed to set register"), + SetDeviceAttr(e) => write!(f, "failed to set device attr: {}", e), + SetReg(e) => write!(f, "failed to set register: {}", e), + SetupGuestMemory(e) => write!(f, "failed to set up guest memory: {}", e), + VcpuInit(e) => write!(f, "failed to initialize VCPU: {}", e), } } } +pub type Result<T> = std::result::Result<T, Error>; + +impl std::error::Error for Error {} + /// Returns a Vec of the valid memory addresses. /// These should be used to configure the GuestMemory structure for the platfrom. pub fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> { @@ -191,7 +190,9 @@ fn fdt_offset(mem_size: u64) -> u64 { pub struct AArch64; impl arch::LinuxArch for AArch64 { - fn build_vm<F>( + type Error = Error; + + fn build_vm<F, E>( mut components: VmComponents, _split_irqchip: bool, create_devices: F, @@ -200,13 +201,14 @@ impl arch::LinuxArch for AArch64 { F: FnOnce( &GuestMemory, &EventFd, - ) -> Result<Vec<(Box<PciDevice + 'static>, Option<Minijail>)>>, + ) -> std::result::Result<Vec<(Box<PciDevice>, Option<Minijail>)>, E>, + E: StdError + 'static, { let mut resources = 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 = Vm::new(&kvm, mem.clone()).map_err(Error::CreateVm)?; let vcpu_count = components.vcpu_count; let mut vcpus = Vec::with_capacity(vcpu_count as usize); @@ -230,7 +232,8 @@ impl arch::LinuxArch for AArch64 { let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?; - let pci_devices = create_devices(&mem, &exit_evt)?; + let pci_devices = + create_devices(&mem, &exit_evt).map_err(|e| Error::CreateDevices(Box::new(e)))?; let (pci, pci_irqs, pid_debug_label_map) = arch::generate_pci_root(pci_devices, &mut mmio_bus, &mut resources, &mut vm) .map_err(Error::CreatePciRoot)?; @@ -321,18 +324,14 @@ impl AArch64 { fdt_offset(mem_size), cmdline, initrd, - )?; + ) + .map_err(Error::CreateFdt)?; Ok(()) } - fn create_vm(kvm: &Kvm, mem: GuestMemory) -> Result<Vm> { - let vm = Vm::new(&kvm, mem)?; - Ok(vm) - } - fn setup_memory(mem_size: u64) -> Result<GuestMemory> { let arch_mem_regions = arch_memory_regions(mem_size); - let mem = GuestMemory::new(&arch_mem_regions)?; + let mem = GuestMemory::new(&arch_mem_regions).map_err(Error::SetupGuestMemory)?; Ok(mem) } @@ -364,13 +363,15 @@ impl AArch64 { /// * `vm` - The vm to add irqs to. /// * `bus` - The bus to add devices to. fn add_arch_devs(vm: &mut Vm, bus: &mut Bus) -> Result<Arc<Mutex<devices::Serial>>> { - let rtc_evt = EventFd::new()?; - vm.register_irqfd(&rtc_evt, AARCH64_RTC_IRQ)?; + let rtc_evt = EventFd::new().map_err(Error::CreateEventFd)?; + vm.register_irqfd(&rtc_evt, AARCH64_RTC_IRQ) + .map_err(Error::RegisterIrqfd)?; - let com_evt_1_3 = EventFd::new()?; - vm.register_irqfd(&com_evt_1_3, AARCH64_SERIAL_IRQ)?; + let com_evt_1_3 = EventFd::new().map_err(Error::CreateEventFd)?; + vm.register_irqfd(&com_evt_1_3, AARCH64_SERIAL_IRQ) + .map_err(Error::RegisterIrqfd)?; let serial = Arc::new(Mutex::new(devices::Serial::new_out( - com_evt_1_3.try_clone()?, + com_evt_1_3.try_clone().map_err(Error::CloneEventFd)?, Box::new(stdout()), ))); bus.insert( @@ -429,7 +430,7 @@ impl AArch64 { sys_util::ioctl_with_ref(&vgic_fd, kvm_sys::KVM_SET_DEVICE_ATTR(), &cpu_if_attr) }; if ret != 0 { - return Err(Box::new(Error::CreateGICFailure(sys_util::Error::new(ret)))); + return Err(Error::CreateGICFailure(sys_util::Error::new(ret))); } // Safe because we allocated the struct that's being passed in @@ -437,7 +438,7 @@ impl AArch64 { sys_util::ioctl_with_ref(&vgic_fd, kvm_sys::KVM_SET_DEVICE_ATTR(), &dist_attr) }; if ret != 0 { - return Err(Box::new(Error::CreateGICFailure(sys_util::Error::new(ret)))); + return Err(Error::CreateGICFailure(sys_util::Error::new(ret))); } // We need to tell the kernel how many irqs to support with this vgic @@ -454,7 +455,7 @@ impl AArch64 { sys_util::ioctl_with_ref(&vgic_fd, kvm_sys::KVM_SET_DEVICE_ATTR(), &nr_irqs_attr) }; if ret != 0 { - return Err(Box::new(Error::CreateGICFailure(sys_util::Error::new(ret)))); + return Err(Error::CreateGICFailure(sys_util::Error::new(ret))); } // Finalize the GIC @@ -470,7 +471,7 @@ impl AArch64 { sys_util::ioctl_with_ref(&vgic_fd, kvm_sys::KVM_SET_DEVICE_ATTR(), &init_gic_attr) }; if ret != 0 { - return Err(Box::new(sys_util::Error::new(ret))); + return Err(Error::SetDeviceAttr(sys_util::Error::new(ret))); } Ok(Some(vgic_fd)) } @@ -489,7 +490,8 @@ impl AArch64 { }; // This reads back the kernel's preferred target type. - vm.arm_preferred_target(&mut kvi)?; + vm.arm_preferred_target(&mut kvi) + .map_err(Error::ReadPreferredTarget)?; // TODO(sonnyrao): need to verify this feature is supported by host kernel kvi.features[0] |= 1 << kvm_sys::KVM_ARM_VCPU_PSCI_0_2; @@ -498,7 +500,7 @@ impl AArch64 { if cpu_id > 0 { kvi.features[0] |= 1 << kvm_sys::KVM_ARM_VCPU_POWER_OFF; } - vcpu.arm_vcpu_init(&kvi)?; + vcpu.arm_vcpu_init(&kvi).map_err(Error::VcpuInit)?; // set up registers let mut data: u64; @@ -507,20 +509,20 @@ impl AArch64 { // All interrupts masked data = PSR_D_BIT | PSR_A_BIT | PSR_I_BIT | PSR_F_BIT | PSR_MODE_EL1H; reg_id = arm64_core_reg!(pstate); - vcpu.set_one_reg(reg_id, data)?; + vcpu.set_one_reg(reg_id, data).map_err(Error::SetReg)?; // Other cpus are powered off initially if cpu_id == 0 { data = AARCH64_PHYS_MEM_START + AARCH64_KERNEL_OFFSET; reg_id = arm64_core_reg!(pc); - vcpu.set_one_reg(reg_id, data)?; + vcpu.set_one_reg(reg_id, data).map_err(Error::SetReg)?; /* X0 -- fdt address */ let mem_size = guest_mem.memory_size(); data = (AARCH64_PHYS_MEM_START + fdt_offset(mem_size)) as u64; // hack -- can't get this to do offsetof(regs[0]) but luckily it's at offset 0 reg_id = arm64_core_reg!(regs); - vcpu.set_one_reg(reg_id, data)?; + vcpu.set_one_reg(reg_id, data).map_err(Error::SetReg)?; } Ok(()) } diff --git a/arch/src/fdt.rs b/arch/src/fdt.rs index 5b4961d..7761def 100644 --- a/arch/src/fdt.rs +++ b/arch/src/fdt.rs @@ -37,8 +37,6 @@ pub enum Error { FdtGuestMemoryWriteError, } -impl std::error::Error for Error {} - impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; @@ -59,27 +57,31 @@ impl Display for Error { } } -pub fn begin_node(fdt: &mut Vec<u8>, name: &str) -> Result<(), Box<Error>> { +pub type Result<T> = std::result::Result<T, Error>; + +impl std::error::Error for Error {} + +pub fn begin_node(fdt: &mut Vec<u8>, name: &str) -> Result<()> { let cstr_name = CString::new(name).unwrap(); // Safe because we allocated fdt and converted name to a CString let fdt_ret = unsafe { fdt_begin_node(fdt.as_mut_ptr() as *mut c_void, cstr_name.as_ptr()) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtBeginNodeError(fdt_ret))); + return Err(Error::FdtBeginNodeError(fdt_ret)); } Ok(()) } -pub fn end_node(fdt: &mut Vec<u8>) -> Result<(), Box<Error>> { +pub fn end_node(fdt: &mut Vec<u8>) -> Result<()> { // Safe because we allocated fdt let fdt_ret = unsafe { fdt_end_node(fdt.as_mut_ptr() as *mut c_void) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtEndNodeError(fdt_ret))); + return Err(Error::FdtEndNodeError(fdt_ret)); } Ok(()) } -pub fn property(fdt: &mut Vec<u8>, name: &str, val: &[u8]) -> Result<(), Box<Error>> { +pub fn property(fdt: &mut Vec<u8>, name: &str, val: &[u8]) -> Result<()> { let cstr_name = CString::new(name).unwrap(); let val_ptr = val.as_ptr() as *const c_void; @@ -93,7 +95,7 @@ pub fn property(fdt: &mut Vec<u8>, name: &str, val: &[u8]) -> Result<(), Box<Err ) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtPropertyError(fdt_ret))); + return Err(Error::FdtPropertyError(fdt_ret)); } Ok(()) } @@ -110,11 +112,11 @@ fn cpu_to_fdt64(input: u64) -> [u8; 8] { buf } -pub fn property_u32(fdt: &mut Vec<u8>, name: &str, val: u32) -> Result<(), Box<Error>> { +pub fn property_u32(fdt: &mut Vec<u8>, name: &str, val: u32) -> Result<()> { property(fdt, name, &cpu_to_fdt32(val)) } -pub fn property_u64(fdt: &mut Vec<u8>, name: &str, val: u64) -> Result<(), Box<Error>> { +pub fn property_u64(fdt: &mut Vec<u8>, name: &str, val: u64) -> Result<()> { property(fdt, name, &cpu_to_fdt64(val)) } @@ -136,7 +138,7 @@ pub fn generate_prop64(cells: &[u64]) -> Vec<u8> { ret } -pub fn property_null(fdt: &mut Vec<u8>, name: &str) -> Result<(), Box<Error>> { +pub fn property_null(fdt: &mut Vec<u8>, name: &str) -> Result<()> { let cstr_name = CString::new(name).unwrap(); // Safe because we allocated fdt, converted name to a CString @@ -149,16 +151,12 @@ pub fn property_null(fdt: &mut Vec<u8>, name: &str) -> Result<(), Box<Error>> { ) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtPropertyError(fdt_ret))); + return Err(Error::FdtPropertyError(fdt_ret)); } Ok(()) } -pub fn property_cstring( - fdt: &mut Vec<u8>, - name: &str, - cstr_value: &CStr, -) -> Result<(), Box<Error>> { +pub fn property_cstring(fdt: &mut Vec<u8>, name: &str, cstr_value: &CStr) -> Result<()> { let value_bytes = cstr_value.to_bytes_with_nul(); let cstr_name = CString::new(name).unwrap(); @@ -172,40 +170,36 @@ pub fn property_cstring( ) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtPropertyError(fdt_ret))); + return Err(Error::FdtPropertyError(fdt_ret)); } Ok(()) } -pub fn property_string(fdt: &mut Vec<u8>, name: &str, value: &str) -> Result<(), Box<Error>> { +pub fn property_string(fdt: &mut Vec<u8>, name: &str, value: &str) -> Result<()> { let cstr_value = CString::new(value).unwrap(); property_cstring(fdt, name, &cstr_value) } -pub fn start_fdt(fdt: &mut Vec<u8>, fdt_max_size: usize) -> Result<(), Box<Error>> { +pub fn start_fdt(fdt: &mut Vec<u8>, fdt_max_size: usize) -> Result<()> { // Safe since we allocated this array with fdt_max_size let mut fdt_ret = unsafe { fdt_create(fdt.as_mut_ptr() as *mut c_void, fdt_max_size as c_int) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtCreateError(fdt_ret))); + return Err(Error::FdtCreateError(fdt_ret)); } // Safe since we allocated this array fdt_ret = unsafe { fdt_finish_reservemap(fdt.as_mut_ptr() as *mut c_void) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtFinishReservemapError(fdt_ret))); + return Err(Error::FdtFinishReservemapError(fdt_ret)); } Ok(()) } -pub fn finish_fdt( - fdt: &mut Vec<u8>, - fdt_final: &mut Vec<u8>, - fdt_max_size: usize, -) -> Result<(), Box<Error>> { +pub fn finish_fdt(fdt: &mut Vec<u8>, fdt_final: &mut Vec<u8>, fdt_max_size: usize) -> Result<()> { // Safe since we allocated fdt_final and previously passed in it's size let mut fdt_ret = unsafe { fdt_finish(fdt.as_mut_ptr() as *mut c_void) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtFinishError(fdt_ret))); + return Err(Error::FdtFinishError(fdt_ret)); } // Safe because we allocated both arrays with the correct size @@ -217,13 +211,13 @@ pub fn finish_fdt( ) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtOpenIntoError(fdt_ret))); + return Err(Error::FdtOpenIntoError(fdt_ret)); } // Safe since we allocated fdt_final fdt_ret = unsafe { fdt_pack(fdt_final.as_mut_ptr() as *mut c_void) }; if fdt_ret != 0 { - return Err(Box::new(Error::FdtPackError(fdt_ret))); + return Err(Error::FdtPackError(fdt_ret)); } Ok(()) } diff --git a/arch/src/lib.rs b/arch/src/lib.rs index d725baa..aa6c8a3 100644 --- a/arch/src/lib.rs +++ b/arch/src/lib.rs @@ -15,11 +15,11 @@ extern crate sync; extern crate sys_util; use std::collections::BTreeMap; +use std::error::Error as StdError; use std::fmt::{self, Display}; use std::fs::File; -use std::io::{Read, Seek, SeekFrom}; +use std::io::{self, Read, Seek, SeekFrom}; use std::os::unix::io::AsRawFd; -use std::result; use std::sync::Arc; use devices::virtio::VirtioDevice; @@ -33,8 +33,6 @@ use resources::SystemAllocator; use sync::Mutex; use sys_util::{syslog, EventFd, GuestAddress, GuestMemory, GuestMemoryError}; -pub type Result<T> = result::Result<T, Box<std::error::Error>>; - /// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to /// create a `RunnableLinuxVm`. pub struct VmComponents { @@ -70,6 +68,8 @@ pub struct VirtioDeviceStub { /// Trait which is implemented for each Linux Architecture in order to /// set up the memory, cpus, and system devices and to boot the kernel. pub trait LinuxArch { + type Error: StdError; + /// Takes `VmComponents` and generates a `RunnableLinuxVm`. /// /// # Arguments @@ -77,16 +77,14 @@ pub trait LinuxArch { /// * `components` - Parts to use to build the VM. /// * `split_irqchip` - whether to use a split IRQ chip (i.e. userspace PIT/PIC/IOAPIC) /// * `create_devices` - Function to generate a list of devices. - fn build_vm<F>( + fn build_vm<F, E>( components: VmComponents, split_irqchip: bool, create_devices: F, - ) -> Result<RunnableLinuxVm> + ) -> Result<RunnableLinuxVm, Self::Error> where - F: FnOnce( - &GuestMemory, - &EventFd, - ) -> Result<Vec<(Box<PciDevice + 'static>, Option<Minijail>)>>; + F: FnOnce(&GuestMemory, &EventFd) -> Result<Vec<(Box<PciDevice>, Option<Minijail>)>, E>, + E: StdError + 'static; } /// Errors for device manager. @@ -141,14 +139,12 @@ impl Display for DeviceRegistrationError { /// Creates a root PCI device for use by this Vm. pub fn generate_pci_root( - devices: Vec<(Box<PciDevice + 'static>, Option<Minijail>)>, + devices: Vec<(Box<PciDevice>, Option<Minijail>)>, mmio_bus: &mut Bus, resources: &mut SystemAllocator, vm: &mut Vm, -) -> std::result::Result< - (PciRoot, Vec<(u32, PciInterruptPin)>, BTreeMap<u32, String>), - DeviceRegistrationError, -> { +) -> Result<(PciRoot, Vec<(u32, PciInterruptPin)>, BTreeMap<u32, String>), DeviceRegistrationError> +{ let mut root = PciRoot::new(); let mut pci_irqs = Vec::new(); let mut pid_labels = BTreeMap::new(); @@ -214,7 +210,7 @@ pub fn generate_pci_root( /// Errors for image loading. #[derive(Debug)] pub enum LoadImageError { - Seek(std::io::Error), + Seek(io::Error), ImageSizeTooLarge(u64), ReadToMemory(GuestMemoryError), } @@ -246,7 +242,7 @@ pub fn load_image<F>( image: &mut F, guest_addr: GuestAddress, max_size: u64, -) -> std::result::Result<usize, LoadImageError> +) -> Result<usize, LoadImageError> where F: Read + Seek, { diff --git a/src/linux.rs b/src/linux.rs index acea1de..a0cb968 100644 --- a/src/linux.rs +++ b/src/linux.rs @@ -58,7 +58,7 @@ pub enum Error { BalloonDeviceNew(virtio::BalloonError), BlockDeviceNew(sys_util::Error), BlockSignal(sys_util::signal::Error), - BuildingVm(Box<error::Error>), + BuildVm(<Arch as LinuxArch>::Error), ChownTpmStorage(sys_util::Error), CloneEventFd(sys_util::Error), CreateCrasClient(libcras::Error), @@ -123,7 +123,7 @@ impl Display for Error { BalloonDeviceNew(e) => write!(f, "failed to create balloon: {}", e), BlockDeviceNew(e) => write!(f, "failed to create block device: {}", e), BlockSignal(e) => write!(f, "failed to block signal: {}", e), - BuildingVm(e) => write!(f, "The architecture failed to build the vm: {}", e), + BuildVm(e) => write!(f, "The architecture failed to build the vm: {}", e), ChownTpmStorage(e) => write!(f, "failed to chown tpm storage: {}", e), CloneEventFd(e) => write!(f, "failed to clone eventfd: {}", e), CreateCrasClient(e) => write!(f, "failed to create cras client: {}", e), @@ -1113,9 +1113,8 @@ pub fn run_config(cfg: Config) -> Result<()> { balloon_device_socket, &mut disk_device_sockets, ) - .map_err(|e| Box::new(e) as Box<dyn std::error::Error>) }) - .map_err(Error::BuildingVm)?; + .map_err(Error::BuildVm)?; run_control( linux, control_server_socket, diff --git a/x86_64/src/fdt.rs b/x86_64/src/fdt.rs index 4f3084f..d725ffe 100644 --- a/x86_64/src/fdt.rs +++ b/x86_64/src/fdt.rs @@ -29,7 +29,7 @@ pub fn create_fdt( guest_mem: &GuestMemory, fdt_load_offset: u64, android_fstab: &mut File, -) -> Result<usize, Box<Error>> { +) -> Result<usize, Error> { // Reserve space for the setup_data let fdt_data_size = fdt_max_size - mem::size_of::<setup_data>(); @@ -85,7 +85,7 @@ pub fn create_fdt( .write_at_addr(fdt_final.as_slice(), fdt_data_address) .map_err(|_| Error::FdtGuestMemoryWriteError)?; if written < fdt_data_size { - return Err(Box::new(Error::FdtGuestMemoryWriteError)); + return Err(Error::FdtGuestMemoryWriteError); } Ok(fdt_data_size) } diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs index fb4825c..0038a25 100644 --- a/x86_64/src/lib.rs +++ b/x86_64/src/lib.rs @@ -66,12 +66,12 @@ mod interrupts; mod mptable; mod regs; +use std::error::Error as StdError; use std::ffi::{CStr, CString}; use std::fmt::{self, Display}; use std::fs::File; use std::io::{self, stdout}; use std::mem; -use std::result; use std::sync::Arc; use arch::{RunnableLinuxVm, VmComponents}; @@ -82,76 +82,90 @@ use io_jail::Minijail; use kvm::*; use resources::{AddressRanges, SystemAllocator}; use sync::Mutex; -use sys_util::{Clock, EventFd, GuestAddress, GuestMemory}; +use sys_util::{Clock, EventFd, GuestAddress, GuestMemory, GuestMemoryError}; #[derive(Debug)] pub enum Error { - /// Error configuring the system - ConfigureSystem, - /// Unable to clone an EventFd CloneEventFd(sys_util::Error), - /// Error creating kernel command line. Cmdline(kernel_cmdline::Error), - /// Unable to make an EventFd + ConfigureSystem, + CreateDevices(Box<dyn StdError>), CreateEventFd(sys_util::Error), - /// Unable to create PIT device. - CreatePit(devices::PitError), - /// Unable to create Kvm. + CreateFdt(arch::fdt::Error), + CreateIrqChip(sys_util::Error), CreateKvm(sys_util::Error), - /// Unable to create a PciRoot hub. CreatePciRoot(arch::DeviceRegistrationError), - /// Unable to create socket. + CreatePit(sys_util::Error), + CreatePitDevice(devices::PitError), CreateSocket(io::Error), - /// Unable to create Vcpu. CreateVcpu(sys_util::Error), - /// The kernel extends past the end of RAM + CreateVm(sys_util::Error), + E820Configuration, KernelOffsetPastEnd, - /// Error registering an IrqFd - RegisterIrqfd(sys_util::Error), - /// Couldn't register virtio socket. - RegisterVsock(arch::DeviceRegistrationError), LoadCmdline(kernel_loader::Error), - LoadKernel(kernel_loader::Error), LoadInitrd(arch::LoadImageError), - /// Error writing the zero page of guest memory. - ZeroPageSetup, - /// The zero page extends past the end of guest_mem. + LoadKernel(kernel_loader::Error), + RegisterIrqfd(sys_util::Error), + RegisterVsock(arch::DeviceRegistrationError), + SetLint(interrupts::Error), + SetTssAddr(sys_util::Error), + SetupCpuid(cpuid::Error), + SetupFpu(regs::Error), + SetupGuestMemory(GuestMemoryError), + SetupMptable(mptable::Error), + SetupMsrs(regs::Error), + SetupRegs(regs::Error), + SetupSregs(regs::Error), ZeroPagePastRamEnd, - /// Invalid e820 setup params. - E820Configuration, + ZeroPageSetup, } -impl std::error::Error for Error {} - impl Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Error::*; match self { - ConfigureSystem => write!(f, "error configuring the system"), CloneEventFd(e) => write!(f, "unable to clone an EventFd: {}", e), Cmdline(e) => write!(f, "the given kernel command line was invalid: {}", e), + ConfigureSystem => write!(f, "error configuring the system"), + CreateDevices(e) => write!(f, "error creating devices: {}", e), CreateEventFd(e) => write!(f, "unable to make an EventFd: {}", e), - CreatePit(e) => write!(f, "unable to make Pit device: {}", e), + CreateFdt(e) => write!(f, "failed to create fdt: {}", 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), + CreatePit(e) => write!(f, "unable to create PIT: {}", e), + CreatePitDevice(e) => write!(f, "unable to make PIT device: {}", e), CreateSocket(e) => write!(f, "failed to create socket: {}", e), CreateVcpu(e) => write!(f, "failed to create VCPU: {}", e), + CreateVm(e) => write!(f, "failed to create VM: {}", e), + E820Configuration => write!(f, "invalid e820 setup params"), KernelOffsetPastEnd => write!(f, "the kernel extends past the end of RAM"), + LoadCmdline(e) => write!(f, "error loading command line: {}", e), + LoadInitrd(e) => write!(f, "error loading initrd: {}", e), + LoadKernel(e) => write!(f, "error loading Kernel: {}", e), RegisterIrqfd(e) => write!(f, "error registering an IrqFd: {}", e), RegisterVsock(e) => write!(f, "error registering virtual socket device: {}", e), - LoadCmdline(e) => write!(f, "error Loading command line: {}", e), - LoadKernel(e) => write!(f, "error Loading Kernel: {}", e), - LoadInitrd(e) => write!(f, "error loading initrd: {}", e), - ZeroPageSetup => write!(f, "error writing the zero page of guest memory"), + SetLint(e) => write!(f, "failed to set interrupts: {}", e), + SetTssAddr(e) => write!(f, "failed to set tss addr: {}", e), + SetupCpuid(e) => write!(f, "failed to set up cpuid: {}", e), + SetupFpu(e) => write!(f, "failed to set up FPU: {}", e), + SetupGuestMemory(e) => write!(f, "failed to set up guest memory: {}", e), + SetupMptable(e) => write!(f, "failed to set up mptable: {}", e), + SetupMsrs(e) => write!(f, "failed to set up MSRs: {}", e), + SetupRegs(e) => write!(f, "failed to set up registers: {}", e), + SetupSregs(e) => write!(f, "failed to set up sregs: {}", e), ZeroPagePastRamEnd => write!(f, "the zero page extends past the end of guest_mem"), - E820Configuration => write!(f, "invalid e820 setup params"), + ZeroPageSetup => write!(f, "error writing the zero page of guest memory"), } } } +pub type Result<T> = std::result::Result<T, Error>; + +impl std::error::Error for Error {} + pub struct X8664arch; -pub type Result<T> = result::Result<T, Box<std::error::Error>>; const BOOT_STACK_POINTER: u64 = 0x8000; const MEM_32BIT_GAP_SIZE: u64 = (768 << 20); @@ -184,7 +198,7 @@ fn configure_system( let end_32bit_gap_start = GuestAddress(FIRST_ADDR_PAST_32BITS - MEM_32BIT_GAP_SIZE); // Note that this puts the mptable at 0x0 in guest physical memory. - mptable::setup_mptable(guest_mem, num_cpus, pci_irqs)?; + mptable::setup_mptable(guest_mem, num_cpus, pci_irqs).map_err(Error::SetupMptable)?; let mut params: boot_params = Default::default(); @@ -243,7 +257,7 @@ fn configure_system( /// Returns Ok(()) if successful, or an error if there is no space left in the map. fn add_e820_entry(params: &mut boot_params, addr: u64, size: u64, mem_type: u32) -> Result<()> { if params.e820_entries >= params.e820_map.len() as u8 { - return Err(Box::new(Error::E820Configuration)); + return Err(Error::E820Configuration); } params.e820_map[params.e820_entries as usize].addr = addr; @@ -280,7 +294,9 @@ fn arch_memory_regions(size: u64) -> Vec<(GuestAddress, u64)> { } impl arch::LinuxArch for X8664arch { - fn build_vm<F>( + type Error = Error; + + fn build_vm<F, E>( mut components: VmComponents, split_irqchip: bool, create_devices: F, @@ -289,7 +305,8 @@ impl arch::LinuxArch for X8664arch { F: FnOnce( &GuestMemory, &EventFd, - ) -> Result<Vec<(Box<PciDevice + 'static>, Option<Minijail>)>>, + ) -> std::result::Result<Vec<(Box<PciDevice>, Option<Minijail>)>, E>, + E: StdError + 'static, { let mut resources = Self::get_resource_allocator(components.memory_mb, components.wayland_dmabuf); @@ -319,7 +336,8 @@ impl arch::LinuxArch for X8664arch { let exit_evt = EventFd::new().map_err(Error::CreateEventFd)?; - let pci_devices = create_devices(&mem, &exit_evt)?; + let pci_devices = + create_devices(&mem, &exit_evt).map_err(|e| Error::CreateDevices(Box::new(e)))?; let (pci, pci_irqs, pid_debug_label_map) = arch::generate_pci_root(pci_devices, &mut mmio_bus, &mut resources, &mut vm) .map_err(Error::CreatePciRoot)?; @@ -374,11 +392,8 @@ impl X8664arch { /// * `mem` - The memory to be used by the guest. /// * `kernel_image` - the File object for the specified kernel. fn load_kernel(mem: &GuestMemory, mut kernel_image: &mut File) -> Result<u64> { - Ok(kernel_loader::load_kernel( - mem, - GuestAddress(KERNEL_START_OFFSET), - &mut kernel_image, - )?) + kernel_loader::load_kernel(mem, GuestAddress(KERNEL_START_OFFSET), &mut kernel_image) + .map_err(Error::LoadKernel) } /// Configures the system memory space should be called once per vm before @@ -400,7 +415,8 @@ impl X8664arch { android_fstab: Option<File>, kernel_end: u64, ) -> Result<()> { - kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline)?; + kernel_loader::load_cmdline(mem, GuestAddress(CMDLINE_OFFSET), cmdline) + .map_err(Error::LoadCmdline)?; // Track the first free address after the kernel - this is where extra // data like the device tree blob and initrd will be loaded. @@ -415,7 +431,8 @@ impl X8664arch { mem, dtb_start.offset(), &mut fstab, - )?; + ) + .map_err(Error::CreateFdt)?; free_addr = dtb_start.offset() + dtb_size as u64; Some(dtb_start) } else { @@ -460,12 +477,12 @@ impl X8664arch { /// * `split_irqchip` - Whether to use a split IRQ chip. /// * `mem` - The memory to be used by the guest. fn create_vm(kvm: &Kvm, split_irqchip: bool, mem: GuestMemory) -> Result<Vm> { - let vm = Vm::new(&kvm, mem)?; + let vm = Vm::new(&kvm, mem).map_err(Error::CreateVm)?; let tss_addr = GuestAddress(0xfffbd000); - vm.set_tss_addr(tss_addr).expect("set tss addr failed"); + vm.set_tss_addr(tss_addr).map_err(Error::SetTssAddr)?; if !split_irqchip { - vm.create_pit().expect("create pit failed"); - vm.create_irq_chip()?; + vm.create_pit().map_err(Error::CreatePit)?; + vm.create_irq_chip().map_err(Error::CreateIrqChip)?; } Ok(vm) } @@ -473,9 +490,9 @@ impl X8664arch { /// This creates a GuestMemory object for this VM /// /// * `mem_size` - Desired physical memory size in bytes for this VM - fn setup_memory(mem_size: u64) -> Result<sys_util::GuestMemory> { + fn setup_memory(mem_size: u64) -> Result<GuestMemory> { let arch_mem_regions = arch_memory_regions(mem_size); - let mem = GuestMemory::new(&arch_mem_regions)?; + let mem = GuestMemory::new(&arch_mem_regions).map_err(Error::SetupGuestMemory)?; Ok(mem) } @@ -610,7 +627,7 @@ impl X8664arch { pit_evt.try_clone().map_err(Error::CloneEventFd)?, Arc::new(Mutex::new(Clock::new())), ) - .map_err(Error::CreatePit)?, + .map_err(Error::CreatePitDevice)?, )); // Reserve from 0x40 to 0x61 (the speaker). io_bus.insert(pit.clone(), 0x040, 0x22, false).unwrap(); @@ -667,8 +684,8 @@ impl X8664arch { num_cpus: u64, ) -> Result<()> { let kernel_load_addr = GuestAddress(KERNEL_START_OFFSET); - cpuid::setup_cpuid(kvm, vcpu, cpu_id, num_cpus)?; - regs::setup_msrs(vcpu)?; + cpuid::setup_cpuid(kvm, vcpu, cpu_id, num_cpus).map_err(Error::SetupCpuid)?; + regs::setup_msrs(vcpu).map_err(Error::SetupMsrs)?; let kernel_end = guest_mem .checked_offset(kernel_load_addr, KERNEL_64BIT_ENTRY_OFFSET) .ok_or(Error::KernelOffsetPastEnd)?; @@ -677,10 +694,11 @@ impl X8664arch { (kernel_end).offset() as u64, BOOT_STACK_POINTER as u64, ZERO_PAGE_OFFSET as u64, - )?; - regs::setup_fpu(vcpu)?; - regs::setup_sregs(guest_mem, vcpu)?; - interrupts::set_lint(vcpu)?; + ) + .map_err(Error::SetupRegs)?; + regs::setup_fpu(vcpu).map_err(Error::SetupFpu)?; + regs::setup_sregs(guest_mem, vcpu).map_err(Error::SetupSregs)?; + interrupts::set_lint(vcpu).map_err(Error::SetLint)?; Ok(()) } } |