arch: Replace Box<dyn Error> with error enum

Avoiding Box<dyn Error> makes it less likely that we display errors with
insufficient context by accident.

Many of the errors touched in this CL already had helpful message
written! But those corresponding enum variants were never being
instantiated, and that bug was masked by Box<dyn Error>. For example see
the Error::LoadCmdline and Error::LoadKernel.

    pub enum Error {
        LoadCmdline(kernel_loader::Error),
        ...
    }

Before this CL:

    // Bug: boxes the underlying error without adding LoadCmdline
    kernel_loader::load_cmdline(...)?;

After this CL:

    kernel_loader::load_cmdline(...).map_err(Error::LoadCmdline)?;

TEST=cargo check
TEST=cargo check --all-features
TEST=cargo check --target aarch64-unknown-linux-gnu

Change-Id: I7c0cff843c2211565226b9dfb4142ad6b7fa15ac
Reviewed-on: https://chromium-review.googlesource.com/1502112
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: David Tolnay <dtolnay@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Zach Reizner <zachr@chromium.org>
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 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_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 @@
     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 @@
     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 @@
     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 @@
     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 @@
 }
 
 // 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 @@
     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 @@
     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 @@
     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 @@
     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 @@
         .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 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 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 @@
 
 #[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.
-    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
-    InitrdLoadFailure(arch::LoadImageError),
-    /// Failure to Create GIC
+    CreateFdt(arch::fdt::Error),
     CreateGICFailure(sys_util::Error),
-    /// Couldn't register PCI bus.
+    CreateKvm(sys_util::Error),
+    CreatePciRoot(arch::DeviceRegistrationError),
+    CreateSocket(io::Error),
+    CreateVcpu(sys_util::Error),
+    CreateVm(sys_util::Error),
+    InitrdLoadFailure(arch::LoadImageError),
+    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 @@
         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 @@
 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 @@
         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 @@
 
         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 @@
             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 @@
     /// * `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 @@
             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 @@
             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 @@
             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 @@
             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 @@
         };
 
         // 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 @@
         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 @@
         // 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 @@
     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 @@
     }
 }
 
-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 @@
         )
     };
     if fdt_ret != 0 {
-        return Err(Box::new(Error::FdtPropertyError(fdt_ret)));
+        return Err(Error::FdtPropertyError(fdt_ret));
     }
     Ok(())
 }
@@ -110,11 +112,11 @@
     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 @@
     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 @@
         )
     };
     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 @@
         )
     };
     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 @@
         )
     };
     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 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 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 @@
 /// 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 @@
     /// * `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 @@
 
 /// 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 @@
 /// Errors for image loading.
 #[derive(Debug)]
 pub enum LoadImageError {
-    Seek(std::io::Error),
+    Seek(io::Error),
     ImageSizeTooLarge(u64),
     ReadToMemory(GuestMemoryError),
 }
@@ -246,7 +242,7 @@
     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 @@
     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 @@
             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 @@
             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 @@
     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 @@
         .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 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 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
-    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.
-    ZeroPagePastRamEnd,
-    /// Invalid e820 setup params.
+    CreateVm(sys_util::Error),
     E820Configuration,
+    KernelOffsetPastEnd,
+    LoadCmdline(kernel_loader::Error),
+    LoadInitrd(arch::LoadImageError),
+    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,
+    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 @@
     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 @@
 /// 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 @@
 }
 
 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 @@
         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 @@
 
         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 @@
     /// * `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 @@
         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 @@
                 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 @@
     /// * `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 @@
     /// 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 @@
                     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 @@
         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 @@
             (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(())
     }
 }