• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 use std::collections::BTreeMap;
9 use std::error::Error as StdError;
10 use std::fmt::{self, Display};
11 use std::fs::File;
12 use std::io::{self, Read, Seek, SeekFrom};
13 use std::os::unix::io::AsRawFd;
14 use std::sync::Arc;
15 
16 use devices::virtio::VirtioDevice;
17 use devices::{
18     Bus, BusDevice, BusError, PciDevice, PciDeviceError, PciInterruptPin, PciRoot, ProxyDevice,
19     Serial, SerialParameters, DEFAULT_SERIAL_PARAMS, SERIAL_ADDR,
20 };
21 use io_jail::Minijail;
22 use kvm::{IoeventAddress, Kvm, Vcpu, Vm};
23 use resources::SystemAllocator;
24 use sync::Mutex;
25 use sys_util::{syslog, EventFd, GuestAddress, GuestMemory, GuestMemoryError};
26 
27 pub enum VmImage {
28     Kernel(File),
29     Bios(File),
30 }
31 
32 /// Holds the pieces needed to build a VM. Passed to `build_vm` in the `LinuxArch` trait below to
33 /// create a `RunnableLinuxVm`.
34 pub struct VmComponents {
35     pub memory_size: u64,
36     pub vcpu_count: u32,
37     pub vcpu_affinity: Vec<usize>,
38     pub vm_image: VmImage,
39     pub android_fstab: Option<File>,
40     pub initrd_image: Option<File>,
41     pub extra_kernel_params: Vec<String>,
42     pub wayland_dmabuf: bool,
43 }
44 
45 /// Holds the elements needed to run a Linux VM. Created by `build_vm`.
46 pub struct RunnableLinuxVm {
47     pub vm: Vm,
48     pub kvm: Kvm,
49     pub resources: SystemAllocator,
50     pub stdio_serial: Option<Arc<Mutex<Serial>>>,
51     pub exit_evt: EventFd,
52     pub vcpus: Vec<Vcpu>,
53     pub vcpu_affinity: Vec<usize>,
54     pub irq_chip: Option<File>,
55     pub io_bus: Bus,
56     pub mmio_bus: Bus,
57     pub pid_debug_label_map: BTreeMap<u32, String>,
58 }
59 
60 /// The device and optional jail.
61 pub struct VirtioDeviceStub {
62     pub dev: Box<dyn VirtioDevice>,
63     pub jail: Option<Minijail>,
64 }
65 
66 /// Trait which is implemented for each Linux Architecture in order to
67 /// set up the memory, cpus, and system devices and to boot the kernel.
68 pub trait LinuxArch {
69     type Error: StdError;
70 
71     /// Takes `VmComponents` and generates a `RunnableLinuxVm`.
72     ///
73     /// # Arguments
74     ///
75     /// * `components` - Parts to use to build the VM.
76     /// * `split_irqchip` - whether to use a split IRQ chip (i.e. userspace PIT/PIC/IOAPIC)
77     /// * `serial_parameters` - definitions for how the serial devices should be configured.
78     /// * `create_devices` - Function to generate a list of devices.
build_vm<F, E>( components: VmComponents, split_irqchip: bool, serial_parameters: &BTreeMap<u8, SerialParameters>, create_devices: F, ) -> Result<RunnableLinuxVm, Self::Error> where F: FnOnce( &GuestMemory, &mut Vm, &mut SystemAllocator, &EventFd, ) -> Result<Vec<(Box<dyn PciDevice>, Option<Minijail>)>, E>, E: StdError + 'static79     fn build_vm<F, E>(
80         components: VmComponents,
81         split_irqchip: bool,
82         serial_parameters: &BTreeMap<u8, SerialParameters>,
83         create_devices: F,
84     ) -> Result<RunnableLinuxVm, Self::Error>
85     where
86         F: FnOnce(
87             &GuestMemory,
88             &mut Vm,
89             &mut SystemAllocator,
90             &EventFd,
91         ) -> Result<Vec<(Box<dyn PciDevice>, Option<Minijail>)>, E>,
92         E: StdError + 'static;
93 }
94 
95 /// Errors for device manager.
96 #[derive(Debug)]
97 pub enum DeviceRegistrationError {
98     /// Could not allocate IO space for the device.
99     AllocateIoAddrs(PciDeviceError),
100     /// Could not allocate device address space for the device.
101     AllocateDeviceAddrs(PciDeviceError),
102     /// Could not allocate an IRQ number.
103     AllocateIrq,
104     /// Could not create the mmio device to wrap a VirtioDevice.
105     CreateMmioDevice(sys_util::Error),
106     //  Unable to create serial device from serial parameters
107     CreateSerialDevice(devices::SerialError),
108     /// Could not create an event fd.
109     EventFdCreate(sys_util::Error),
110     /// Could not add a device to the mmio bus.
111     MmioInsert(BusError),
112     /// Failed to register ioevent with VM.
113     RegisterIoevent(sys_util::Error),
114     /// Failed to register irq eventfd with VM.
115     RegisterIrqfd(sys_util::Error),
116     /// Failed to initialize proxy device for jailed device.
117     ProxyDeviceCreation(devices::ProxyError),
118     /// Appending to kernel command line failed.
119     Cmdline(kernel_cmdline::Error),
120     /// No more IRQs are available.
121     IrqsExhausted,
122     /// No more MMIO space available.
123     AddrsExhausted,
124     /// Could not register PCI device capabilities.
125     RegisterDeviceCapabilities(PciDeviceError),
126 }
127 
128 impl Display for DeviceRegistrationError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result129     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
130         use self::DeviceRegistrationError::*;
131 
132         match self {
133             AllocateIoAddrs(e) => write!(f, "Allocating IO addresses: {}", e),
134             AllocateDeviceAddrs(e) => write!(f, "Allocating device addresses: {}", e),
135             AllocateIrq => write!(f, "Allocating IRQ number"),
136             CreateMmioDevice(e) => write!(f, "failed to create mmio device: {}", e),
137             CreateSerialDevice(e) => write!(f, "failed to create serial device: {}", e),
138             Cmdline(e) => write!(f, "unable to add device to kernel command line: {}", e),
139             EventFdCreate(e) => write!(f, "failed to create eventfd: {}", e),
140             MmioInsert(e) => write!(f, "failed to add to mmio bus: {}", e),
141             RegisterIoevent(e) => write!(f, "failed to register ioevent to VM: {}", e),
142             RegisterIrqfd(e) => write!(f, "failed to register irq eventfd to VM: {}", e),
143             ProxyDeviceCreation(e) => write!(f, "failed to create proxy device: {}", e),
144             IrqsExhausted => write!(f, "no more IRQs are available"),
145             AddrsExhausted => write!(f, "no more addresses are available"),
146             RegisterDeviceCapabilities(e) => {
147                 write!(f, "could not register PCI device capabilities: {}", e)
148             }
149         }
150     }
151 }
152 
153 /// Creates a root PCI device for use by this Vm.
generate_pci_root( devices: Vec<(Box<dyn PciDevice>, Option<Minijail>)>, mmio_bus: &mut Bus, resources: &mut SystemAllocator, vm: &mut Vm, ) -> Result<(PciRoot, Vec<(u32, PciInterruptPin)>, BTreeMap<u32, String>), DeviceRegistrationError>154 pub fn generate_pci_root(
155     devices: Vec<(Box<dyn PciDevice>, Option<Minijail>)>,
156     mmio_bus: &mut Bus,
157     resources: &mut SystemAllocator,
158     vm: &mut Vm,
159 ) -> Result<(PciRoot, Vec<(u32, PciInterruptPin)>, BTreeMap<u32, String>), DeviceRegistrationError>
160 {
161     let mut root = PciRoot::new();
162     let mut pci_irqs = Vec::new();
163     let mut pid_labels = BTreeMap::new();
164     for (dev_idx, (mut device, jail)) in devices.into_iter().enumerate() {
165         // Only support one bus.
166         device.assign_bus_dev(0, dev_idx as u8);
167 
168         let mut keep_fds = device.keep_fds();
169         syslog::push_fds(&mut keep_fds);
170 
171         let irqfd = EventFd::new().map_err(DeviceRegistrationError::EventFdCreate)?;
172         let irq_resample_fd = EventFd::new().map_err(DeviceRegistrationError::EventFdCreate)?;
173         let irq_num = resources
174             .allocate_irq()
175             .ok_or(DeviceRegistrationError::AllocateIrq)? as u32;
176         let pci_irq_pin = match dev_idx % 4 {
177             0 => PciInterruptPin::IntA,
178             1 => PciInterruptPin::IntB,
179             2 => PciInterruptPin::IntC,
180             3 => PciInterruptPin::IntD,
181             _ => panic!(""), // Obviously not possible, but the compiler is not smart enough.
182         };
183         vm.register_irqfd_resample(&irqfd, &irq_resample_fd, irq_num)
184             .map_err(DeviceRegistrationError::RegisterIrqfd)?;
185         keep_fds.push(irqfd.as_raw_fd());
186         keep_fds.push(irq_resample_fd.as_raw_fd());
187         device.assign_irq(irqfd, irq_resample_fd, irq_num, pci_irq_pin);
188         pci_irqs.push((dev_idx as u32, pci_irq_pin));
189 
190         let ranges = device
191             .allocate_io_bars(resources)
192             .map_err(DeviceRegistrationError::AllocateIoAddrs)?;
193         let device_ranges = device
194             .allocate_device_bars(resources)
195             .map_err(DeviceRegistrationError::AllocateDeviceAddrs)?;
196         device
197             .register_device_capabilities()
198             .map_err(DeviceRegistrationError::RegisterDeviceCapabilities)?;
199         for (event, addr, datamatch) in device.ioeventfds() {
200             let io_addr = IoeventAddress::Mmio(addr);
201             vm.register_ioevent(&event, io_addr, datamatch)
202                 .map_err(DeviceRegistrationError::RegisterIoevent)?;
203             keep_fds.push(event.as_raw_fd());
204         }
205         let arced_dev: Arc<Mutex<dyn BusDevice>> = if let Some(jail) = jail {
206             let proxy = ProxyDevice::new(device, &jail, keep_fds)
207                 .map_err(DeviceRegistrationError::ProxyDeviceCreation)?;
208             pid_labels.insert(proxy.pid() as u32, proxy.debug_label());
209             Arc::new(Mutex::new(proxy))
210         } else {
211             device.on_sandboxed();
212             Arc::new(Mutex::new(device))
213         };
214         root.add_device(arced_dev.clone());
215         for range in &ranges {
216             mmio_bus
217                 .insert(arced_dev.clone(), range.0, range.1, true)
218                 .map_err(DeviceRegistrationError::MmioInsert)?;
219         }
220 
221         for range in &device_ranges {
222             mmio_bus
223                 .insert(arced_dev.clone(), range.0, range.1, true)
224                 .map_err(DeviceRegistrationError::MmioInsert)?;
225         }
226     }
227     Ok((root, pci_irqs, pid_labels))
228 }
229 
230 /// Adds serial devices to the provided bus based on the serial parameters given. Returns the serial
231 ///  port number and serial device to be used for stdout if defined.
232 ///
233 /// # Arguments
234 ///
235 /// * `io_bus` - Bus to add the devices to
236 /// * `com_evt_1_3` - eventfd for com1 and com3
237 /// * `com_evt_1_4` - eventfd for com2 and com4
238 /// * `io_bus` - Bus to add the devices to
239 /// * `serial_parameters` - definitions of serial parameter configuationis. If a setting is not
240 ///     provided for a port, then it will use the default configuation.
add_serial_devices( io_bus: &mut Bus, com_evt_1_3: &EventFd, com_evt_2_4: &EventFd, serial_parameters: &BTreeMap<u8, SerialParameters>, ) -> Result<(Option<u8>, Option<Arc<Mutex<Serial>>>), DeviceRegistrationError>241 pub fn add_serial_devices(
242     io_bus: &mut Bus,
243     com_evt_1_3: &EventFd,
244     com_evt_2_4: &EventFd,
245     serial_parameters: &BTreeMap<u8, SerialParameters>,
246 ) -> Result<(Option<u8>, Option<Arc<Mutex<Serial>>>), DeviceRegistrationError> {
247     let mut stdio_serial_num = None;
248     let mut stdio_serial = None;
249 
250     for x in 0..=3 {
251         let com_evt = match x {
252             0 => com_evt_1_3,
253             1 => com_evt_2_4,
254             2 => com_evt_1_3,
255             3 => com_evt_2_4,
256             _ => com_evt_1_3,
257         };
258 
259         let param = serial_parameters
260             .get(&(x + 1))
261             .unwrap_or(&DEFAULT_SERIAL_PARAMS[x as usize]);
262 
263         let com = Arc::new(Mutex::new(
264             param
265                 .create_serial_device(&com_evt)
266                 .map_err(DeviceRegistrationError::CreateSerialDevice)?,
267         ));
268         io_bus
269             .insert(com.clone(), SERIAL_ADDR[x as usize], 0x8, false)
270             .unwrap();
271 
272         if param.console {
273             stdio_serial_num = Some(x + 1);
274             stdio_serial = Some(com.clone());
275         }
276     }
277 
278     Ok((stdio_serial_num, stdio_serial))
279 }
280 
281 /// Errors for image loading.
282 #[derive(Debug)]
283 pub enum LoadImageError {
284     BadAlignment(u64),
285     Seek(io::Error),
286     ImageSizeTooLarge(u64),
287     ReadToMemory(GuestMemoryError),
288 }
289 
290 impl Display for LoadImageError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result291     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
292         use self::LoadImageError::*;
293 
294         match self {
295             BadAlignment(a) => write!(f, "Alignment not a power of two: {}", a),
296             Seek(e) => write!(f, "Seek failed: {}", e),
297             ImageSizeTooLarge(size) => write!(f, "Image size too large: {}", size),
298             ReadToMemory(e) => write!(f, "Reading image into memory failed: {}", e),
299         }
300     }
301 }
302 
303 /// Load an image from a file into guest memory.
304 ///
305 /// # Arguments
306 ///
307 /// * `guest_mem` - The memory to be used by the guest.
308 /// * `guest_addr` - The starting address to load the image in the guest memory.
309 /// * `max_size` - The amount of space in bytes available in the guest memory for the image.
310 /// * `image` - The file containing the image to be loaded.
311 ///
312 /// 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 + AsRawFd,313 pub fn load_image<F>(
314     guest_mem: &GuestMemory,
315     image: &mut F,
316     guest_addr: GuestAddress,
317     max_size: u64,
318 ) -> Result<usize, LoadImageError>
319 where
320     F: Read + Seek + AsRawFd,
321 {
322     let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
323 
324     if size > usize::max_value() as u64 || size > max_size {
325         return Err(LoadImageError::ImageSizeTooLarge(size));
326     }
327 
328     // This is safe due to the bounds check above.
329     let size = size as usize;
330 
331     image
332         .seek(SeekFrom::Start(0))
333         .map_err(LoadImageError::Seek)?;
334 
335     guest_mem
336         .read_to_memory(guest_addr, image, size)
337         .map_err(LoadImageError::ReadToMemory)?;
338 
339     Ok(size)
340 }
341 
342 /// Load an image from a file into guest memory at the highest possible address.
343 ///
344 /// # Arguments
345 ///
346 /// * `guest_mem` - The memory to be used by the guest.
347 /// * `image` - The file containing the image to be loaded.
348 /// * `min_guest_addr` - The minimum address of the start of the image.
349 /// * `max_guest_addr` - The address to load the last byte of the image.
350 /// * `align` - The minimum alignment of the start address of the image in bytes
351 ///   (must be a power of two).
352 ///
353 /// 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 + AsRawFd,354 pub fn load_image_high<F>(
355     guest_mem: &GuestMemory,
356     image: &mut F,
357     min_guest_addr: GuestAddress,
358     max_guest_addr: GuestAddress,
359     align: u64,
360 ) -> Result<(GuestAddress, usize), LoadImageError>
361 where
362     F: Read + Seek + AsRawFd,
363 {
364     if !align.is_power_of_two() {
365         return Err(LoadImageError::BadAlignment(align));
366     }
367 
368     let max_size = max_guest_addr.offset_from(min_guest_addr) & !(align - 1);
369     let size = image.seek(SeekFrom::End(0)).map_err(LoadImageError::Seek)?;
370 
371     if size > usize::max_value() as u64 || size > max_size {
372         return Err(LoadImageError::ImageSizeTooLarge(size));
373     }
374 
375     image
376         .seek(SeekFrom::Start(0))
377         .map_err(LoadImageError::Seek)?;
378 
379     // Load image at the maximum aligned address allowed.
380     // The subtraction cannot underflow because of the size checks above.
381     let guest_addr = GuestAddress((max_guest_addr.offset() - size) & !(align - 1));
382 
383     // This is safe due to the bounds check above.
384     let size = size as usize;
385 
386     guest_mem
387         .read_to_memory(guest_addr, image, size)
388         .map_err(LoadImageError::ReadToMemory)?;
389 
390     Ok((guest_addr, size))
391 }
392