• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #![cfg_attr(windows, allow(unused))]
6 
7 //! Emulates virtual and hardware devices.
8 
9 pub mod ac_adapter;
10 pub mod acpi;
11 pub mod bat;
12 mod bus;
13 #[cfg(feature = "stats")]
14 mod bus_stats;
15 pub mod cmos;
16 #[cfg(target_arch = "x86_64")]
17 mod debugcon;
18 mod fw_cfg;
19 mod i8042;
20 mod irq_event;
21 pub mod irqchip;
22 mod pci;
23 mod pflash;
24 pub mod pl030;
25 pub mod pmc_virt;
26 mod serial;
27 pub mod serial_device;
28 mod suspendable;
29 mod sys;
30 #[cfg(any(target_os = "android", target_os = "linux"))]
31 mod virtcpufreq;
32 pub mod virtio;
33 #[cfg(feature = "vtpm")]
34 mod vtpm_proxy;
35 
36 cfg_if::cfg_if! {
37     if #[cfg(target_arch = "x86_64")] {
38         mod pit;
39         pub use self::pit::{Pit, PitError};
40         pub mod tsc;
41     }
42 }
43 
44 use std::sync::Arc;
45 
46 use anyhow::anyhow;
47 use anyhow::Context;
48 use base::debug;
49 use base::error;
50 use base::info;
51 use base::Tube;
52 use base::TubeError;
53 use cros_async::AsyncTube;
54 use cros_async::Executor;
55 use vm_control::DeviceControlCommand;
56 use vm_control::DevicesState;
57 use vm_control::VmResponse;
58 use vm_memory::GuestMemory;
59 
60 pub use self::acpi::ACPIPMFixedEvent;
61 pub use self::acpi::ACPIPMResource;
62 pub use self::bat::BatteryError;
63 pub use self::bat::GoldfishBattery;
64 pub use self::bus::Bus;
65 pub use self::bus::BusAccessInfo;
66 pub use self::bus::BusDevice;
67 pub use self::bus::BusDeviceObj;
68 pub use self::bus::BusDeviceSync;
69 pub use self::bus::BusRange;
70 pub use self::bus::BusResumeDevice;
71 pub use self::bus::BusType;
72 pub use self::bus::Error as BusError;
73 pub use self::bus::HotPlugBus;
74 pub use self::bus::HotPlugKey;
75 #[cfg(feature = "stats")]
76 pub use self::bus_stats::BusStatistics;
77 #[cfg(target_arch = "x86_64")]
78 pub use self::debugcon::Debugcon;
79 pub use self::fw_cfg::Error as FwCfgError;
80 pub use self::fw_cfg::FwCfgDevice;
81 pub use self::fw_cfg::FwCfgItemType;
82 pub use self::fw_cfg::FwCfgParameters;
83 pub use self::fw_cfg::FW_CFG_BASE_PORT;
84 pub use self::fw_cfg::FW_CFG_MAX_FILE_SLOTS;
85 pub use self::fw_cfg::FW_CFG_WIDTH;
86 pub use self::i8042::I8042Device;
87 pub use self::irq_event::IrqEdgeEvent;
88 pub use self::irq_event::IrqLevelEvent;
89 pub use self::irqchip::*;
90 pub use self::pci::BarRange;
91 pub use self::pci::CrosvmDeviceId;
92 pub use self::pci::GpeScope;
93 #[cfg(feature = "pci-hotplug")]
94 pub use self::pci::HotPluggable;
95 #[cfg(feature = "pci-hotplug")]
96 pub use self::pci::IntxParameter;
97 #[cfg(feature = "pci-hotplug")]
98 pub use self::pci::NetResourceCarrier;
99 pub use self::pci::PciAddress;
100 pub use self::pci::PciAddressError;
101 pub use self::pci::PciBarConfiguration;
102 pub use self::pci::PciBarIndex;
103 pub use self::pci::PciBus;
104 pub use self::pci::PciClassCode;
105 pub use self::pci::PciConfigIo;
106 pub use self::pci::PciConfigMmio;
107 pub use self::pci::PciDevice;
108 pub use self::pci::PciDeviceError;
109 pub use self::pci::PciInterruptPin;
110 pub use self::pci::PciMmioMapper;
111 pub use self::pci::PciRoot;
112 pub use self::pci::PciRootCommand;
113 pub use self::pci::PciVirtualConfigMmio;
114 pub use self::pci::PreferredIrq;
115 #[cfg(feature = "pci-hotplug")]
116 pub use self::pci::ResourceCarrier;
117 pub use self::pci::StubPciDevice;
118 pub use self::pci::StubPciParameters;
119 pub use self::pflash::Pflash;
120 pub use self::pflash::PflashParameters;
121 pub use self::pl030::Pl030;
122 pub use self::serial::Serial;
123 pub use self::serial_device::Error as SerialError;
124 pub use self::serial_device::SerialDevice;
125 pub use self::serial_device::SerialHardware;
126 pub use self::serial_device::SerialParameters;
127 pub use self::serial_device::SerialType;
128 pub use self::suspendable::DeviceState;
129 pub use self::suspendable::Suspendable;
130 #[cfg(any(target_os = "android", target_os = "linux"))]
131 pub use self::virtcpufreq::VirtCpufreq;
132 pub use self::virtio::VirtioMmioDevice;
133 pub use self::virtio::VirtioPciDevice;
134 #[cfg(feature = "vtpm")]
135 pub use self::vtpm_proxy::VtpmProxy;
136 
137 cfg_if::cfg_if! {
138     if #[cfg(any(target_os = "android", target_os = "linux"))] {
139         mod platform;
140         mod proxy;
141         pub mod vmwdt;
142         pub mod vfio;
143         #[cfg(feature = "usb")]
144         #[macro_use]
145         mod register_space;
146         #[cfg(feature = "usb")]
147         pub mod usb;
148         #[cfg(feature = "usb")]
149         mod utils;
150 
151         pub use self::pci::{
152             CoIommuDev, CoIommuParameters, CoIommuUnpinPolicy, PciBridge, PcieDownstreamPort,
153             PcieHostPort, PcieRootPort, PcieUpstreamPort, PvPanicCode, PvPanicPciDevice,
154             VfioPciDevice,
155         };
156         pub use self::platform::VfioPlatformDevice;
157         pub use self::ac_adapter::AcAdapter;
158         pub use self::pmc_virt::VirtualPmc;
159         pub use self::proxy::ChildProcIntf;
160         pub use self::proxy::Error as ProxyError;
161         pub use self::proxy::ProxyDevice;
162         #[cfg(feature = "usb")]
163         pub use self::usb::backend::device_provider::DeviceProvider;
164         #[cfg(feature = "usb")]
165         pub use self::usb::xhci::xhci_controller::XhciController;
166         pub use self::vfio::VfioContainer;
167         pub use self::vfio::VfioDevice;
168         pub use self::vfio::VfioDeviceType;
169         pub use self::virtio::vfio_wrapper;
170 
171     } else if #[cfg(windows)] {
172     } else {
173         compile_error!("Unsupported platform");
174     }
175 }
176 
177 /// Request CoIOMMU to unpin a specific range.
178 use serde::Deserialize;
179 /// Request CoIOMMU to unpin a specific range.
180 use serde::Serialize;
181 #[derive(Serialize, Deserialize, Debug)]
182 pub struct UnpinRequest {
183     /// The ranges presents (start gfn, count).
184     ranges: Vec<(u64, u64)>,
185 }
186 
187 #[derive(Serialize, Deserialize, Debug)]
188 pub enum UnpinResponse {
189     Success,
190     Failed,
191 }
192 
193 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
194 pub enum IommuDevType {
195     #[serde(rename = "off")]
196     #[default]
197     NoIommu,
198     #[serde(rename = "viommu")]
199     VirtioIommu,
200     #[serde(rename = "coiommu")]
201     CoIommu,
202     #[serde(rename = "pkvm-iommu")]
203     PkvmPviommu,
204 }
205 
206 // Thread that handles commands sent to devices - such as snapshot, sleep, suspend
207 // Created when the VM is first created, and re-created on resumption of the VM.
create_devices_worker_thread( guest_memory: GuestMemory, io_bus: Arc<Bus>, mmio_bus: Arc<Bus>, device_ctrl_resp: Tube, ) -> std::io::Result<std::thread::JoinHandle<()>>208 pub fn create_devices_worker_thread(
209     guest_memory: GuestMemory,
210     io_bus: Arc<Bus>,
211     mmio_bus: Arc<Bus>,
212     device_ctrl_resp: Tube,
213 ) -> std::io::Result<std::thread::JoinHandle<()>> {
214     std::thread::Builder::new()
215         .name("device_control".to_string())
216         .spawn(move || {
217             let ex = Executor::new().expect("Failed to create an executor");
218 
219             let async_control = AsyncTube::new(&ex, device_ctrl_resp).unwrap();
220             match ex.run_until(async move {
221                 handle_command_tube(async_control, guest_memory, io_bus, mmio_bus).await
222             }) {
223                 Ok(_) => {}
224                 Err(e) => {
225                     error!("Device control thread exited with error: {}", e);
226                 }
227             };
228         })
229 }
230 
sleep_buses(buses: &[&Bus]) -> anyhow::Result<()>231 fn sleep_buses(buses: &[&Bus]) -> anyhow::Result<()> {
232     for bus in buses {
233         bus.sleep_devices()
234             .with_context(|| format!("failed to sleep devices on {:?} bus", bus.get_bus_type()))?;
235         debug!("Devices slept successfully on {:?} bus", bus.get_bus_type());
236     }
237     Ok(())
238 }
239 
wake_buses(buses: &[&Bus])240 fn wake_buses(buses: &[&Bus]) {
241     for bus in buses {
242         bus.wake_devices()
243             .with_context(|| format!("failed to wake devices on {:?} bus", bus.get_bus_type()))
244             // Some devices may have slept. Eternally.
245             // Recovery - impossible.
246             // Shut down VM.
247             .expect("VM panicked to avoid unexpected behavior");
248         debug!(
249             "Devices awoken successfully on {:?} Bus",
250             bus.get_bus_type()
251         );
252     }
253 }
254 
255 // Use 64MB chunks when writing the memory snapshot (if encryption is used).
256 const MEMORY_SNAP_ENCRYPTED_CHUNK_SIZE_BYTES: usize = 1024 * 1024 * 64;
257 
snapshot_handler( snapshot_writer: vm_control::SnapshotWriter, guest_memory: &GuestMemory, buses: &[&Bus], compress_memory: bool, ) -> anyhow::Result<()>258 async fn snapshot_handler(
259     snapshot_writer: vm_control::SnapshotWriter,
260     guest_memory: &GuestMemory,
261     buses: &[&Bus],
262     compress_memory: bool,
263 ) -> anyhow::Result<()> {
264     // SAFETY:
265     // VM & devices are stopped.
266     let guest_memory_metadata = unsafe {
267         guest_memory
268             .snapshot(
269                 &mut snapshot_writer
270                     .raw_fragment_with_chunk_size("mem", MEMORY_SNAP_ENCRYPTED_CHUNK_SIZE_BYTES)?,
271                 compress_memory,
272             )
273             .context("failed to snapshot memory")?
274     };
275     snapshot_writer.write_fragment("mem_metadata", &guest_memory_metadata)?;
276     for (i, bus) in buses.iter().enumerate() {
277         bus.snapshot_devices(&snapshot_writer.add_namespace(&format!("bus{i}"))?)
278             .context("failed to snapshot bus devices")?;
279         debug!(
280             "Devices snapshot successfully for {:?} Bus",
281             bus.get_bus_type()
282         );
283     }
284     Ok(())
285 }
286 
restore_handler( snapshot_reader: vm_control::SnapshotReader, guest_memory: &GuestMemory, buses: &[&Bus], ) -> anyhow::Result<()>287 async fn restore_handler(
288     snapshot_reader: vm_control::SnapshotReader,
289     guest_memory: &GuestMemory,
290     buses: &[&Bus],
291 ) -> anyhow::Result<()> {
292     let guest_memory_metadata = snapshot_reader.read_fragment("mem_metadata")?;
293     // SAFETY:
294     // VM & devices are stopped.
295     unsafe {
296         guest_memory.restore(
297             guest_memory_metadata,
298             &mut snapshot_reader.raw_fragment("mem")?,
299         )?
300     };
301     for (i, bus) in buses.iter().enumerate() {
302         bus.restore_devices(&snapshot_reader.namespace(&format!("bus{i}"))?)
303             .context("failed to restore bus devices")?;
304         debug!(
305             "Devices restore successfully for {:?} Bus",
306             bus.get_bus_type()
307         );
308     }
309     Ok(())
310 }
311 
handle_command_tube( command_tube: AsyncTube, guest_memory: GuestMemory, io_bus: Arc<Bus>, mmio_bus: Arc<Bus>, ) -> anyhow::Result<()>312 async fn handle_command_tube(
313     command_tube: AsyncTube,
314     guest_memory: GuestMemory,
315     io_bus: Arc<Bus>,
316     mmio_bus: Arc<Bus>,
317 ) -> anyhow::Result<()> {
318     let buses = &[&*io_bus, &*mmio_bus];
319 
320     // We assume devices are awake. This is safe because if the VM starts the
321     // sleeping state, run_control will ask us to sleep devices.
322     let mut devices_state = DevicesState::Wake;
323 
324     loop {
325         match command_tube.next().await {
326             Ok(command) => {
327                 match command {
328                     DeviceControlCommand::SleepDevices => {
329                         if let DevicesState::Wake = devices_state {
330                             match sleep_buses(buses) {
331                                 Ok(()) => {
332                                     devices_state = DevicesState::Sleep;
333                                 }
334                                 Err(e) => {
335                                     error!("failed to sleep: {:#}", e);
336 
337                                     // Failing to sleep could mean a single device failing to sleep.
338                                     // Wake up devices to resume functionality of the VM.
339                                     info!("Attempting to wake devices after failed sleep");
340                                     wake_buses(buses);
341 
342                                     command_tube
343                                         .send(VmResponse::ErrString(e.to_string()))
344                                         .await
345                                         .context("failed to send response.")?;
346                                     continue;
347                                 }
348                             }
349                         }
350                         command_tube
351                             .send(VmResponse::Ok)
352                             .await
353                             .context("failed to reply to sleep command")?;
354                     }
355                     DeviceControlCommand::WakeDevices => {
356                         if let DevicesState::Sleep = devices_state {
357                             wake_buses(buses);
358                             devices_state = DevicesState::Wake;
359                         }
360                         command_tube
361                             .send(VmResponse::Ok)
362                             .await
363                             .context("failed to reply to wake devices request")?;
364                     }
365                     DeviceControlCommand::SnapshotDevices {
366                         snapshot_writer,
367                         compress_memory,
368                     } => {
369                         assert!(
370                             matches!(devices_state, DevicesState::Sleep),
371                             "devices must be sleeping to snapshot"
372                         );
373                         if let Err(e) =
374                             snapshot_handler(snapshot_writer, &guest_memory, buses, compress_memory)
375                                 .await
376                         {
377                             error!("failed to snapshot: {:#}", e);
378                             command_tube
379                                 .send(VmResponse::ErrString(e.to_string()))
380                                 .await
381                                 .context("Failed to send response")?;
382                             continue;
383                         }
384                         command_tube
385                             .send(VmResponse::Ok)
386                             .await
387                             .context("Failed to send response")?;
388                     }
389                     DeviceControlCommand::RestoreDevices { snapshot_reader } => {
390                         assert!(
391                             matches!(devices_state, DevicesState::Sleep),
392                             "devices must be sleeping to restore"
393                         );
394                         if let Err(e) =
395                             restore_handler(snapshot_reader, &guest_memory, &[&*io_bus, &*mmio_bus])
396                                 .await
397                         {
398                             error!("failed to restore: {:#}", e);
399                             command_tube
400                                 .send(VmResponse::ErrString(e.to_string()))
401                                 .await
402                                 .context("Failed to send response")?;
403                             continue;
404                         }
405                         command_tube
406                             .send(VmResponse::Ok)
407                             .await
408                             .context("Failed to send response")?;
409                     }
410                     DeviceControlCommand::GetDevicesState => {
411                         command_tube
412                             .send(VmResponse::DevicesState(devices_state.clone()))
413                             .await
414                             .context("failed to send response")?;
415                     }
416                     DeviceControlCommand::Exit => {
417                         return Ok(());
418                     }
419                 };
420             }
421             Err(e) => {
422                 if matches!(e, TubeError::Disconnected) {
423                     // Tube disconnected - shut down thread.
424                     return Ok(());
425                 }
426                 return Err(anyhow!("Failed to receive: {}", e));
427             }
428         }
429     }
430 }
431