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