1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 pub mod android;
6 pub mod fdt;
7 pub mod pstore;
8 pub mod serial;
9 
10 use std::collections::BTreeMap;
11 use std::error::Error as StdError;
12 use std::fmt::{self, Display};
13 use std::fs::File;
14 use std::io::{self, Read, Seek, SeekFrom};
15 use std::path::PathBuf;
16 use std::sync::Arc;
17 
18 use acpi_tables::aml::Aml;
19 use acpi_tables::sdt::SDT;
20 use base::{syslog, AsRawDescriptor, Event, Tube};
21 use devices::virtio::VirtioDevice;
22 use devices::{
23     Bus, BusDevice, BusError, IrqChip, PciAddress, PciDevice, PciDeviceError, PciInterruptPin,
24     PciRoot, ProtectionType, ProxyDevice,
25 };
26 use hypervisor::{IoEventAddress, Vm};
27 use minijail::Minijail;
28 use resources::{MmioType, SystemAllocator};
29 use sync::Mutex;
30 use vm_control::{BatControl, BatteryType};
31 use vm_memory::{GuestAddress, GuestMemory, GuestMemoryError};
32 
33 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
34 use gdbstub::arch::x86::reg::X86_64CoreRegs as GdbStubRegs;
35 
36 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
37 use {
38     devices::IrqChipAArch64 as IrqChipArch,
39     hypervisor::{Hypervisor as HypervisorArch, VcpuAArch64 as VcpuArch, VmAArch64 as VmArch},
40 };
41 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
42 use {
43     devices::IrqChipX86_64 as IrqChipArch,
44     hypervisor::{HypervisorX86_64 as HypervisorArch, VcpuX86_64 as VcpuArch, VmX86_64 as VmArch},
45 };
46 
47 pub use serial::{
48     add_serial_devices, get_serial_cmdline, set_default_serial_parameters, GetSerialCmdlineError,
49     SerialHardware, SerialParameters, SerialType, SERIAL_ADDR,
50 };
51 
52 pub enum VmImage {
53     Kernel(File),
54     Bios(File),
55 }
56 
57 #[derive(Clone)]
58 pub struct Pstore {
59     pub path: PathBuf,
60     pub size: u32,
61 }
62 
63 /// Mapping of guest VCPU threads to host CPU cores.
64 #[derive(Clone, Debug, PartialEq)]
65 pub enum VcpuAffinity {
66     /// All VCPU threads will be pinned to the same set of host CPU cores.
67     Global(Vec<usize>),
68     /// Each VCPU may be pinned to a set of host CPU cores.
69     /// The map key is a guest VCPU index, and the corresponding value is the set of
70     /// host CPU indices that the VCPU thread will be allowed to run on.
71     /// If a VCPU index is not present in the map, its affinity will not be set.
72     PerVcpu(BTreeMap<usize, Vec<usize>>),
73 }
74 
75 /// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to
76 /// create a `RunnableLinuxVm`.
77 pub struct VmComponents {
78     pub memory_size: u64,
79     pub vcpu_count: usize,
80     pub vcpu_affinity: Option<VcpuAffinity>,
81     pub no_smt: bool,
82     pub hugepages: bool,
83     pub vm_image: VmImage,
84     pub android_fstab: Option<File>,
85     pub pstore: Option<Pstore>,
86     pub initrd_image: Option<File>,
87     pub extra_kernel_params: Vec<String>,
88     pub wayland_dmabuf: bool,
89     pub acpi_sdts: Vec<SDT>,
90     pub rt_cpus: Vec<usize>,
91     pub protected_vm: ProtectionType,
92     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
93     pub gdb: Option<(u32, Tube)>, // port and control tube.
94     pub dmi_path: Option<PathBuf>,
95 }
96 
97 /// Holds the elements needed to run a Linux VM. Created by `build_vm`.
98 pub struct RunnableLinuxVm<V: VmArch, Vcpu: VcpuArch, I: IrqChipArch> {
99     pub vm: V,
100     pub resources: SystemAllocator,
101     pub exit_evt: Event,
102     pub vcpu_count: usize,
103     /// If vcpus is None, then it's the responsibility of the vcpu thread to create vcpus.
104     /// If it's Some, then `build_vm` already created the vcpus.
105     pub vcpus: Option<Vec<Vcpu>>,
106     pub vcpu_affinity: Option<VcpuAffinity>,
107     pub no_smt: bool,
108     pub irq_chip: I,
109     pub has_bios: bool,
110     pub io_bus: Bus,
111     pub mmio_bus: Bus,
112     pub pid_debug_label_map: BTreeMap<u32, String>,
113     pub suspend_evt: Event,
114     pub rt_cpus: Vec<usize>,
115     pub bat_control: Option<BatControl>,
116     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
117     pub gdb: Option<(u32, Tube)>,
118 }
119 
120 /// The device and optional jail.
121 pub struct VirtioDeviceStub {
122     pub dev: Box<dyn VirtioDevice>,
123     pub jail: Option<Minijail>,
124 }
125 
126 /// Trait which is implemented for each Linux Architecture in order to
127 /// set up the memory, cpus, and system devices and to boot the kernel.
128 pub trait LinuxArch {
129     type Error: StdError;
130 
131     /// Returns a Vec of the valid memory addresses as pairs of address and length. These should be
132     /// used to configure the `GuestMemory` structure for the platform.
133     ///
134     /// # Arguments
135     ///
136     /// * `components` - Parts used to determine the memory layout.
guest_memory_layout( components: &VmComponents, ) -> std::result::Result<Vec<(GuestAddress, u64)>, Self::Error>137     fn guest_memory_layout(
138         components: &VmComponents,
139     ) -> std::result::Result<Vec<(GuestAddress, u64)>, Self::Error>;
140 
141     /// Takes `VmComponents` and generates a `RunnableLinuxVm`.
142     ///
143     /// # Arguments
144     ///
145     /// * `components` - Parts to use to build the VM.
146     /// * `serial_parameters` - definitions for how the serial devices should be configured.
147     /// * `battery` - defines what battery device will be created.
148     /// * `create_devices` - Function to generate a list of devices.
149     /// * `create_irq_chip` - Function to generate an IRQ chip.
build_vm<V, Vcpu, I, FD, FI, E1, E2>( components: VmComponents, serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>, serial_jail: Option<Minijail>, battery: (&Option<BatteryType>, Option<Minijail>), vm: V, create_devices: FD, create_irq_chip: FI, ) -> std::result::Result<RunnableLinuxVm<V, Vcpu, I>, Self::Error> where V: VmArch, Vcpu: VcpuArch, I: IrqChipArch, FD: FnOnce( &GuestMemory, &mut V, &mut SystemAllocator, &Event, ) -> std::result::Result<Vec<(Box<dyn PciDevice>, Option<Minijail>)>, E1>, FI: FnOnce(&V, usize) -> std::result::Result<I, E2>, E1: StdError + 'static, E2: StdError + 'static150     fn build_vm<V, Vcpu, I, FD, FI, E1, E2>(
151         components: VmComponents,
152         serial_parameters: &BTreeMap<(SerialHardware, u8), SerialParameters>,
153         serial_jail: Option<Minijail>,
154         battery: (&Option<BatteryType>, Option<Minijail>),
155         vm: V,
156         create_devices: FD,
157         create_irq_chip: FI,
158     ) -> std::result::Result<RunnableLinuxVm<V, Vcpu, I>, Self::Error>
159     where
160         V: VmArch,
161         Vcpu: VcpuArch,
162         I: IrqChipArch,
163         FD: FnOnce(
164             &GuestMemory,
165             &mut V,
166             &mut SystemAllocator,
167             &Event,
168         ) -> std::result::Result<Vec<(Box<dyn PciDevice>, Option<Minijail>)>, E1>,
169         FI: FnOnce(&V, /* vcpu_count: */ usize) -> std::result::Result<I, E2>,
170         E1: StdError + 'static,
171         E2: StdError + 'static;
172 
173     /// Configures the vcpu and should be called once per vcpu from the vcpu's thread.
174     ///
175     /// # Arguments
176     ///
177     /// * `guest_mem` - The memory to be used by the guest.
178     /// * `hypervisor` - The `Hypervisor` that created the vcpu.
179     /// * `irq_chip` - The `IrqChip` associated with this vm.
180     /// * `vcpu` - The VCPU object to configure.
181     /// * `vcpu_id` - The id of the given `vcpu`.
182     /// * `num_cpus` - Number of virtual CPUs the guest will have.
183     /// * `has_bios` - Whether the `VmImage` is a `Bios` image
configure_vcpu( guest_mem: &GuestMemory, hypervisor: &dyn HypervisorArch, irq_chip: &mut dyn IrqChipArch, vcpu: &mut dyn VcpuArch, vcpu_id: usize, num_cpus: usize, has_bios: bool, no_smt: bool, ) -> Result<(), Self::Error>184     fn configure_vcpu(
185         guest_mem: &GuestMemory,
186         hypervisor: &dyn HypervisorArch,
187         irq_chip: &mut dyn IrqChipArch,
188         vcpu: &mut dyn VcpuArch,
189         vcpu_id: usize,
190         num_cpus: usize,
191         has_bios: bool,
192         no_smt: bool,
193     ) -> Result<(), Self::Error>;
194 
195     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
196     /// Reads vCPU's registers.
debug_read_registers<T: VcpuArch>(vcpu: &T) -> Result<GdbStubRegs, Self::Error>197     fn debug_read_registers<T: VcpuArch>(vcpu: &T) -> Result<GdbStubRegs, Self::Error>;
198 
199     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
200     /// Writes vCPU's registers.
debug_write_registers<T: VcpuArch>(vcpu: &T, regs: &GdbStubRegs) -> Result<(), Self::Error>201     fn debug_write_registers<T: VcpuArch>(vcpu: &T, regs: &GdbStubRegs) -> Result<(), Self::Error>;
202 
203     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
204     /// Reads bytes from the guest memory.
debug_read_memory<T: VcpuArch>( vcpu: &T, guest_mem: &GuestMemory, vaddr: GuestAddress, len: usize, ) -> Result<Vec<u8>, Self::Error>205     fn debug_read_memory<T: VcpuArch>(
206         vcpu: &T,
207         guest_mem: &GuestMemory,
208         vaddr: GuestAddress,
209         len: usize,
210     ) -> Result<Vec<u8>, Self::Error>;
211 
212     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
213     /// Writes bytes to the specified guest memory.
debug_write_memory<T: VcpuArch>( vcpu: &T, guest_mem: &GuestMemory, vaddr: GuestAddress, buf: &[u8], ) -> Result<(), Self::Error>214     fn debug_write_memory<T: VcpuArch>(
215         vcpu: &T,
216         guest_mem: &GuestMemory,
217         vaddr: GuestAddress,
218         buf: &[u8],
219     ) -> Result<(), Self::Error>;
220 
221     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
222     /// Make the next vCPU's run single-step.
debug_enable_singlestep<T: VcpuArch>(vcpu: &T) -> Result<(), Self::Error>223     fn debug_enable_singlestep<T: VcpuArch>(vcpu: &T) -> Result<(), Self::Error>;
224 
225     #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
226     /// Set hardware breakpoints at the given addresses.
debug_set_hw_breakpoints<T: VcpuArch>( vcpu: &T, breakpoints: &[GuestAddress], ) -> Result<(), Self::Error>227     fn debug_set_hw_breakpoints<T: VcpuArch>(
228         vcpu: &T,
229         breakpoints: &[GuestAddress],
230     ) -> Result<(), Self::Error>;
231 }
232 
233 /// Errors for device manager.
234 #[derive(Debug)]
235 pub enum DeviceRegistrationError {
236     /// Could not allocate IO space for the device.
237     AllocateIoAddrs(PciDeviceError),
238     /// Could not allocate MMIO or IO resource for the device.
239     AllocateIoResource(resources::Error),
240     /// Could not allocate device address space for the device.
241     AllocateDeviceAddrs(PciDeviceError),
242     /// Could not allocate an IRQ number.
243     AllocateIrq,
244     // Unable to create a pipe.
245     CreatePipe(base::Error),
246     // Unable to create serial device from serial parameters
247     CreateSerialDevice(serial::Error),
248     // Unable to create tube
249     CreateTube(base::TubeError),
250     /// Could not clone an event.
251     EventClone(base::Error),
252     /// Could not create an event.
253     EventCreate(base::Error),
254     /// Missing a required serial device.
255     MissingRequiredSerialDevice(u8),
256     /// Could not add a device to the mmio bus.
257     MmioInsert(BusError),
258     /// Failed to register ioevent with VM.
259     RegisterIoevent(base::Error),
260     /// Failed to register irq event with VM.
261     RegisterIrqfd(base::Error),
262     /// Failed to initialize proxy device for jailed device.
263     ProxyDeviceCreation(devices::ProxyError),
264     /// Appending to kernel command line failed.
265     Cmdline(kernel_cmdline::Error),
266     /// No more IRQs are available.
267     IrqsExhausted,
268     /// No more MMIO space available.
269     AddrsExhausted,
270     /// Could not register PCI device capabilities.
271     RegisterDeviceCapabilities(PciDeviceError),
272     // Failed to register battery device.
273     RegisterBattery(devices::BatteryError),
274 }
275 
276 impl Display for DeviceRegistrationError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result277     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
278         use self::DeviceRegistrationError::*;
279 
280         match self {
281             AllocateIoAddrs(e) => write!(f, "Allocating IO addresses: {}", e),
282             AllocateIoResource(e) => write!(f, "Allocating IO resource: {}", e),
283             AllocateDeviceAddrs(e) => write!(f, "Allocating device addresses: {}", e),
284             AllocateIrq => write!(f, "Allocating IRQ number"),
285             CreatePipe(e) => write!(f, "failed to create pipe: {}", e),
286             CreateSerialDevice(e) => write!(f, "failed to create serial device: {}", e),
287             CreateTube(e) => write!(f, "failed to create tube: {}", e),
288             Cmdline(e) => write!(f, "unable to add device to kernel command line: {}", e),
289             EventClone(e) => write!(f, "failed to clone event: {}", e),
290             EventCreate(e) => write!(f, "failed to create event: {}", e),
291             MissingRequiredSerialDevice(n) => write!(f, "missing required serial device {}", n),
292             MmioInsert(e) => write!(f, "failed to add to mmio bus: {}", e),
293             RegisterIoevent(e) => write!(f, "failed to register ioevent to VM: {}", e),
294             RegisterIrqfd(e) => write!(f, "failed to register irq event to VM: {}", e),
295             ProxyDeviceCreation(e) => write!(f, "failed to create proxy device: {}", e),
296             IrqsExhausted => write!(f, "no more IRQs are available"),
297             AddrsExhausted => write!(f, "no more addresses are available"),
298             RegisterDeviceCapabilities(e) => {
299                 write!(f, "could not register PCI device capabilities: {}", e)
300             }
301             RegisterBattery(e) => write!(f, "failed to register battery device to VM: {}", e),
302         }
303     }
304 }
305 
306 /// Creates a root PCI device for use by this Vm.
generate_pci_root( mut devices: Vec<(Box<dyn PciDevice>, Option<Minijail>)>, irq_chip: &mut impl IrqChip, mmio_bus: &mut Bus, resources: &mut SystemAllocator, vm: &mut impl Vm, max_irqs: usize, ) -> Result< ( PciRoot, Vec<(PciAddress, u32, PciInterruptPin)>, BTreeMap<u32, String>, ), DeviceRegistrationError, >307 pub fn generate_pci_root(
308     mut devices: Vec<(Box<dyn PciDevice>, Option<Minijail>)>,
309     irq_chip: &mut impl IrqChip,
310     mmio_bus: &mut Bus,
311     resources: &mut SystemAllocator,
312     vm: &mut impl Vm,
313     max_irqs: usize,
314 ) -> Result<
315     (
316         PciRoot,
317         Vec<(PciAddress, u32, PciInterruptPin)>,
318         BTreeMap<u32, String>,
319     ),
320     DeviceRegistrationError,
321 > {
322     let mut root = PciRoot::new();
323     let mut pci_irqs = Vec::new();
324     let mut pid_labels = BTreeMap::new();
325 
326     let mut irqs: Vec<Option<u32>> = vec![None; max_irqs];
327 
328     // Allocate PCI device address before allocating BARs.
329     let mut device_addrs = Vec::<PciAddress>::new();
330     for (device, _jail) in devices.iter_mut() {
331         let address = device
332             .allocate_address(resources)
333             .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
334         device_addrs.push(address);
335     }
336 
337     // Allocate ranges that may need to be in the low MMIO region (MmioType::Low).
338     let mut io_ranges = BTreeMap::new();
339     for (dev_idx, (device, _jail)) in devices.iter_mut().enumerate() {
340         let ranges = device
341             .allocate_io_bars(resources)
342             .map_err(DeviceRegistrationError::AllocateIoAddrs)?;
343         io_ranges.insert(dev_idx, ranges);
344     }
345 
346     // Allocate device ranges that may be in low or high MMIO after low-only ranges.
347     let mut device_ranges = BTreeMap::new();
348     for (dev_idx, (device, _jail)) in devices.iter_mut().enumerate() {
349         let ranges = device
350             .allocate_device_bars(resources)
351             .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
352         device_ranges.insert(dev_idx, ranges);
353     }
354 
355     for (dev_idx, (mut device, jail)) in devices.into_iter().enumerate() {
356         let address = device_addrs[dev_idx];
357         let mut keep_rds = device.keep_rds();
358         syslog::push_descriptors(&mut keep_rds);
359 
360         let irqfd = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
361         let irq_resample_fd = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
362         let irq_num = if let Some(irq) = irqs[dev_idx % max_irqs] {
363             irq
364         } else {
365             let irq = resources
366                 .allocate_irq()
367                 .ok_or(DeviceRegistrationError::AllocateIrq)?;
368             irqs[dev_idx % max_irqs] = Some(irq);
369             irq
370         };
371         // Rotate interrupt pins across PCI logical functions.
372         let pci_irq_pin = match address.func % 4 {
373             0 => PciInterruptPin::IntA,
374             1 => PciInterruptPin::IntB,
375             2 => PciInterruptPin::IntC,
376             3 => PciInterruptPin::IntD,
377             _ => unreachable!(), // Obviously not possible, but the compiler is not smart enough.
378         };
379 
380         irq_chip
381             .register_irq_event(irq_num, &irqfd, Some(&irq_resample_fd))
382             .map_err(DeviceRegistrationError::RegisterIrqfd)?;
383 
384         keep_rds.push(irqfd.as_raw_descriptor());
385         keep_rds.push(irq_resample_fd.as_raw_descriptor());
386         device.assign_irq(irqfd, irq_resample_fd, irq_num, pci_irq_pin);
387         pci_irqs.push((address, irq_num, pci_irq_pin));
388         let ranges = io_ranges.remove(&dev_idx).unwrap_or_default();
389         let device_ranges = device_ranges.remove(&dev_idx).unwrap_or_default();
390         device
391             .register_device_capabilities()
392             .map_err(DeviceRegistrationError::RegisterDeviceCapabilities)?;
393         for (event, addr, datamatch) in device.ioevents() {
394             let io_addr = IoEventAddress::Mmio(addr);
395             vm.register_ioevent(&event, io_addr, datamatch)
396                 .map_err(DeviceRegistrationError::RegisterIoevent)?;
397             keep_rds.push(event.as_raw_descriptor());
398         }
399         let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
400             let proxy = ProxyDevice::new(device, &jail, keep_rds)
401                 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
402             pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
403             Arc::new(Mutex::new(proxy))
404         } else {
405             device.on_sandboxed();
406             Arc::new(Mutex::new(device))
407         };
408         root.add_device(address, arced_dev.clone());
409         for range in &ranges {
410             mmio_bus
411                 .insert(arced_dev.clone(), range.0, range.1)
412                 .map_err(DeviceRegistrationError::MmioInsert)?;
413         }
414 
415         for range in &device_ranges {
416             mmio_bus
417                 .insert(arced_dev.clone(), range.0, range.1)
418                 .map_err(DeviceRegistrationError::MmioInsert)?;
419         }
420     }
421     Ok((root, pci_irqs, pid_labels))
422 }
423 
424 /// Adds goldfish battery
425 /// return the platform needed resouces include its AML data, irq number
426 ///
427 /// # Arguments
428 ///
429 /// * `amls` - the vector to put the goldfish battery AML
430 /// * `battery_jail` - used when sandbox is enabled
431 /// * `mmio_bus` - bus to add the devices to
432 /// * `irq_chip` - the IrqChip object for registering irq events
433 /// * `irq_num` - assigned interrupt to use
434 /// * `resources` - the SystemAllocator to allocate IO and MMIO for acpi
add_goldfish_battery( amls: &mut Vec<u8>, battery_jail: Option<Minijail>, mmio_bus: &mut Bus, irq_chip: &mut impl IrqChip, irq_num: u32, resources: &mut SystemAllocator, ) -> Result<Tube, DeviceRegistrationError>435 pub fn add_goldfish_battery(
436     amls: &mut Vec<u8>,
437     battery_jail: Option<Minijail>,
438     mmio_bus: &mut Bus,
439     irq_chip: &mut impl IrqChip,
440     irq_num: u32,
441     resources: &mut SystemAllocator,
442 ) -> Result<Tube, DeviceRegistrationError> {
443     let alloc = resources.get_anon_alloc();
444     let mmio_base = resources
445         .mmio_allocator(MmioType::Low)
446         .allocate_with_align(
447             devices::bat::GOLDFISHBAT_MMIO_LEN,
448             alloc,
449             "GoldfishBattery".to_string(),
450             devices::bat::GOLDFISHBAT_MMIO_LEN,
451         )
452         .map_err(DeviceRegistrationError::AllocateIoResource)?;
453 
454     let irq_evt = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
455     let irq_resample_evt = Event::new().map_err(DeviceRegistrationError::EventCreate)?;
456 
457     irq_chip
458         .register_irq_event(irq_num, &irq_evt, Some(&irq_resample_evt))
459         .map_err(DeviceRegistrationError::RegisterIrqfd)?;
460 
461     let (control_tube, response_tube) =
462         Tube::pair().map_err(DeviceRegistrationError::CreateTube)?;
463 
464     #[cfg(feature = "power-monitor-powerd")]
465     let create_monitor = Some(Box::new(power_monitor::powerd::DBusMonitor::connect)
466         as Box<dyn power_monitor::CreatePowerMonitorFn>);
467 
468     #[cfg(not(feature = "power-monitor-powerd"))]
469     let create_monitor = None;
470 
471     let goldfish_bat = devices::GoldfishBattery::new(
472         mmio_base,
473         irq_num,
474         irq_evt,
475         irq_resample_evt,
476         response_tube,
477         create_monitor,
478     )
479     .map_err(DeviceRegistrationError::RegisterBattery)?;
480     Aml::to_aml_bytes(&goldfish_bat, amls);
481 
482     match battery_jail.as_ref() {
483         Some(jail) => {
484             let mut keep_rds = goldfish_bat.keep_rds();
485             syslog::push_fds(&mut keep_rds);
486             mmio_bus
487                 .insert(
488                     Arc::new(Mutex::new(
489                         ProxyDevice::new(goldfish_bat, &jail, keep_rds)
490                             .map_err(DeviceRegistrationError::ProxyDeviceCreation)?,
491                     )),
492                     mmio_base,
493                     devices::bat::GOLDFISHBAT_MMIO_LEN,
494                 )
495                 .map_err(DeviceRegistrationError::MmioInsert)?;
496         }
497         None => {
498             mmio_bus
499                 .insert(
500                     Arc::new(Mutex::new(goldfish_bat)),
501                     mmio_base,
502                     devices::bat::GOLDFISHBAT_MMIO_LEN,
503                 )
504                 .map_err(DeviceRegistrationError::MmioInsert)?;
505         }
506     }
507 
508     Ok(control_tube)
509 }
510 
511 /// Errors for image loading.
512 #[derive(Debug)]
513 pub enum LoadImageError {
514     BadAlignment(u64),
515     Seek(io::Error),
516     ImageSizeTooLarge(u64),
517     ReadToMemory(GuestMemoryError),
518 }
519 
520 impl Display for LoadImageError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result521     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
522         use self::LoadImageError::*;
523 
524         match self {
525             BadAlignment(a) => write!(f, "Alignment not a power of two: {}", a),
526             Seek(e) => write!(f, "Seek failed: {}", e),
527             ImageSizeTooLarge(size) => write!(f, "Image size too large: {}", size),
528             ReadToMemory(e) => write!(f, "Reading image into memory failed: {}", e),
529         }
530     }
531 }
532 
533 /// Load an image from a file into guest memory.
534 ///
535 /// # Arguments
536 ///
537 /// * `guest_mem` - The memory to be used by the guest.
538 /// * `guest_addr` - The starting address to load the image in the guest memory.
539 /// * `max_size` - The amount of space in bytes available in the guest memory for the image.
540 /// * `image` - The file containing the image to be loaded.
541 ///
542 /// The size in bytes of the loaded image is returned.
load_image<F>( guest_mem: &GuestMemory, image: &mut F, guest_addr: GuestAddress, max_size: u64, ) -> Result<usize, LoadImageError> where F: Read + Seek + AsRawDescriptor,543 pub fn load_image<F>(
544     guest_mem: &GuestMemory,
545     image: &mut F,
546     guest_addr: GuestAddress,
547     max_size: u64,
548 ) -> Result<usize, LoadImageError>
549 where
550     F: Read + Seek + AsRawDescriptor,
551 {
552     let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
553 
554     if size > usize::max_value() as u64 || size > max_size {
555         return Err(LoadImageError::ImageSizeTooLarge(size));
556     }
557 
558     // This is safe due to the bounds check above.
559     let size = size as usize;
560 
561     image
562         .seek(SeekFrom::Start(0))
563         .map_err(LoadImageError::Seek)?;
564 
565     guest_mem
566         .read_to_memory(guest_addr, image, size)
567         .map_err(LoadImageError::ReadToMemory)?;
568 
569     Ok(size)
570 }
571 
572 /// Load an image from a file into guest memory at the highest possible address.
573 ///
574 /// # Arguments
575 ///
576 /// * `guest_mem` - The memory to be used by the guest.
577 /// * `image` - The file containing the image to be loaded.
578 /// * `min_guest_addr` - The minimum address of the start of the image.
579 /// * `max_guest_addr` - The address to load the last byte of the image.
580 /// * `align` - The minimum alignment of the start address of the image in bytes
581 ///   (must be a power of two).
582 ///
583 /// The guest address and size in bytes of the loaded image are returned.
load_image_high<F>( guest_mem: &GuestMemory, image: &mut F, min_guest_addr: GuestAddress, max_guest_addr: GuestAddress, align: u64, ) -> Result<(GuestAddress, usize), LoadImageError> where F: Read + Seek + AsRawDescriptor,584 pub fn load_image_high<F>(
585     guest_mem: &GuestMemory,
586     image: &mut F,
587     min_guest_addr: GuestAddress,
588     max_guest_addr: GuestAddress,
589     align: u64,
590 ) -> Result<(GuestAddress, usize), LoadImageError>
591 where
592     F: Read + Seek + AsRawDescriptor,
593 {
594     if !align.is_power_of_two() {
595         return Err(LoadImageError::BadAlignment(align));
596     }
597 
598     let max_size = max_guest_addr.offset_from(min_guest_addr) & !(align - 1);
599     let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
600 
601     if size > usize::max_value() as u64 || size > max_size {
602         return Err(LoadImageError::ImageSizeTooLarge(size));
603     }
604 
605     image
606         .seek(SeekFrom::Start(0))
607         .map_err(LoadImageError::Seek)?;
608 
609     // Load image at the maximum aligned address allowed.
610     // The subtraction cannot underflow because of the size checks above.
611     let guest_addr = GuestAddress((max_guest_addr.offset() - size) & !(align - 1));
612 
613     // This is safe due to the bounds check above.
614     let size = size as usize;
615 
616     guest_mem
617         .read_to_memory(guest_addr, image, size)
618         .map_err(LoadImageError::ReadToMemory)?;
619 
620     Ok((guest_addr, size))
621 }
622