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(any(target_arch = "x86", target_arch = "x86_64"))]
17 mod debugcon;
18 #[cfg(feature = "direct")]
19 pub mod direct_io;
20 #[cfg(feature = "direct")]
21 pub mod direct_irq;
22 mod i8042;
23 mod irq_event;
24 pub mod irqchip;
25 mod pci;
26 mod pflash;
27 pub mod pl030;
28 mod serial;
29 pub mod serial_device;
30 #[cfg(feature = "tpm")]
31 mod software_tpm;
32 mod suspendable;
33 mod sys;
34 pub mod virtio;
35 #[cfg(all(feature = "vtpm", target_arch = "x86_64"))]
36 mod vtpm_proxy;
37
38 cfg_if::cfg_if! {
39 if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
40 mod pit;
41 pub use self::pit::{Pit, PitError};
42 pub mod tsc;
43 }
44 }
45
46 use std::collections::HashMap;
47 use std::collections::VecDeque;
48 use std::fs::File;
49 use std::sync::Arc;
50
51 use anyhow::anyhow;
52 use anyhow::Context;
53 use base::error;
54 use base::info;
55 use base::Tube;
56 use base::TubeError;
57 use cros_async::AsyncTube;
58 use cros_async::Executor;
59 use vm_control::DeviceControlCommand;
60 use vm_control::VmResponse;
61 use vm_memory::GuestMemory;
62
63 pub use self::acpi::ACPIPMFixedEvent;
64 pub use self::acpi::ACPIPMResource;
65 pub use self::bat::BatteryError;
66 pub use self::bat::GoldfishBattery;
67 pub use self::bus::Bus;
68 pub use self::bus::BusAccessInfo;
69 pub use self::bus::BusDevice;
70 pub use self::bus::BusDeviceObj;
71 pub use self::bus::BusDeviceSync;
72 pub use self::bus::BusRange;
73 pub use self::bus::BusResumeDevice;
74 pub use self::bus::BusType;
75 pub use self::bus::Error as BusError;
76 pub use self::bus::HostHotPlugKey;
77 pub use self::bus::HotPlugBus;
78 #[cfg(feature = "stats")]
79 pub use self::bus_stats::BusStatistics;
80 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
81 pub use self::debugcon::Debugcon;
82 #[cfg(feature = "direct")]
83 pub use self::direct_io::DirectIo;
84 #[cfg(feature = "direct")]
85 pub use self::direct_io::DirectMmio;
86 #[cfg(feature = "direct")]
87 pub use self::direct_irq::DirectIrq;
88 #[cfg(feature = "direct")]
89 pub use self::direct_irq::DirectIrqError;
90 pub use self::i8042::I8042Device;
91 pub use self::irq_event::IrqEdgeEvent;
92 pub use self::irq_event::IrqLevelEvent;
93 pub use self::irqchip::*;
94 #[cfg(feature = "audio")]
95 pub use self::pci::Ac97Backend;
96 #[cfg(feature = "audio")]
97 pub use self::pci::Ac97Dev;
98 #[cfg(feature = "audio")]
99 pub use self::pci::Ac97Parameters;
100 pub use self::pci::BarRange;
101 pub use self::pci::CrosvmDeviceId;
102 pub use self::pci::PciAddress;
103 pub use self::pci::PciAddressError;
104 pub use self::pci::PciBus;
105 pub use self::pci::PciClassCode;
106 pub use self::pci::PciConfigIo;
107 pub use self::pci::PciConfigMmio;
108 pub use self::pci::PciDevice;
109 pub use self::pci::PciDeviceError;
110 pub use self::pci::PciInterruptPin;
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 pub use self::pci::StubPciDevice;
116 pub use self::pci::StubPciParameters;
117 pub use self::pflash::Pflash;
118 pub use self::pflash::PflashParameters;
119 pub use self::pl030::Pl030;
120 pub use self::serial::Serial;
121 pub use self::serial_device::Error as SerialError;
122 pub use self::serial_device::SerialDevice;
123 pub use self::serial_device::SerialHardware;
124 pub use self::serial_device::SerialParameters;
125 pub use self::serial_device::SerialType;
126 #[cfg(feature = "tpm")]
127 pub use self::software_tpm::SoftwareTpm;
128 pub use self::suspendable::DeviceState;
129 pub use self::suspendable::Suspendable;
130 pub use self::virtio::VirtioMmioDevice;
131 pub use self::virtio::VirtioPciDevice;
132 #[cfg(all(feature = "vtpm", target_arch = "x86_64"))]
133 pub use self::vtpm_proxy::VtpmProxy;
134
135 cfg_if::cfg_if! {
136 if #[cfg(unix)] {
137 mod platform;
138 mod proxy;
139 pub mod vmwdt;
140 pub mod vfio;
141 #[cfg(feature = "usb")]
142 #[macro_use]
143 mod register_space;
144 #[cfg(feature = "usb")]
145 pub mod usb;
146 #[cfg(feature = "usb")]
147 mod utils;
148
149 pub use self::pci::{
150 CoIommuDev, CoIommuParameters, CoIommuUnpinPolicy, PciBridge, PcieDownstreamPort,
151 PcieHostPort, PcieRootPort, PcieUpstreamPort, PvPanicCode, PvPanicPciDevice,
152 VfioPciDevice,
153 };
154 pub use self::platform::VfioPlatformDevice;
155 pub use self::ac_adapter::AcAdapter;
156 pub use self::proxy::Error as ProxyError;
157 pub use self::proxy::ProxyDevice;
158 #[cfg(feature = "usb")]
159 pub use self::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
160 #[cfg(feature = "usb")]
161 pub use self::usb::xhci::xhci_controller::XhciController;
162 pub use self::vfio::VfioContainer;
163 pub use self::vfio::VfioDevice;
164 pub use self::vfio::VfioDeviceType;
165 pub use self::virtio::vfio_wrapper;
166
167 } else if #[cfg(windows)] {
168 } else {
169 compile_error!("Unsupported platform");
170 }
171 }
172
173 /// Request CoIOMMU to unpin a specific range.
174 use serde::Deserialize;
175 /// Request CoIOMMU to unpin a specific range.
176 use serde::Serialize;
177 #[derive(Serialize, Deserialize, Debug)]
178 pub struct UnpinRequest {
179 /// The ranges presents (start gfn, count).
180 ranges: Vec<(u64, u64)>,
181 }
182
183 #[derive(Serialize, Deserialize, Debug)]
184 pub enum UnpinResponse {
185 Success,
186 Failed,
187 }
188
189 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
190 pub enum IommuDevType {
191 #[serde(rename = "off")]
192 #[default]
193 NoIommu,
194 #[serde(rename = "viommu")]
195 VirtioIommu,
196 #[serde(rename = "coiommu")]
197 CoIommu,
198 }
199
200 // Thread that handles commands sent to devices - such as snapshot, sleep, suspend
201 // 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<()>>202 pub fn create_devices_worker_thread(
203 guest_memory: GuestMemory,
204 io_bus: Arc<Bus>,
205 mmio_bus: Arc<Bus>,
206 device_ctrl_resp: Tube,
207 ) -> std::io::Result<std::thread::JoinHandle<()>> {
208 std::thread::Builder::new()
209 .name("device_control".to_string())
210 .spawn(move || {
211 let ex = Executor::new().expect("Failed to create an executor");
212
213 let async_control = AsyncTube::new(&ex, device_ctrl_resp).unwrap();
214 match ex.run_until(async move {
215 handle_command_tube(async_control, guest_memory, io_bus, mmio_bus).await
216 }) {
217 Ok(_) => {}
218 Err(e) => {
219 error!("Device control thread exited with error: {}", e);
220 }
221 };
222 })
223 }
224
sleep_devices(bus: &Bus) -> anyhow::Result<()>225 fn sleep_devices(bus: &Bus) -> anyhow::Result<()> {
226 match bus.sleep_devices() {
227 Ok(_) => {
228 info!("Devices slept successfully");
229 Ok(())
230 }
231 Err(e) => Err(anyhow!(
232 "Failed to sleep all devices: {}. Waking up sleeping devices.",
233 e
234 )),
235 }
236 }
237
wake_devices(bus: &Bus)238 fn wake_devices(bus: &Bus) {
239 match bus.wake_devices() {
240 Ok(_) => {
241 info!("Devices awoken successfully");
242 }
243 Err(e) => {
244 // Some devices may have slept. Eternally.
245 // Recovery - impossible.
246 // Shut down VM.
247 panic!(
248 "Failed to wake devices: {}. VM panicked to avoid unexpected behavior",
249 e
250 )
251 }
252 }
253 }
254
255 /// `SleepGuard` sends the devices on all of the provided buses to sleep when it is created and
256 /// wakes them all up when it is dropped.
257 ///
258 /// This allows snapshot and restore operations to be executed while the `BusDevice`s attached to
259 /// the buses are stopped so that the VM state will not change during the snapshot process.
260 struct SleepGuard<'a> {
261 buses: &'a [&'a Bus],
262 }
263
264 impl<'a> SleepGuard<'a> {
new(buses: &'a [&'a Bus]) -> anyhow::Result<Self>265 pub fn new(buses: &'a [&'a Bus]) -> anyhow::Result<Self> {
266 for bus in buses {
267 if let Err(e) = sleep_devices(bus) {
268 // Failing to sleep could mean a single device failing to sleep.
269 // Wake up devices to resume functionality of the VM.
270 for bus in buses {
271 wake_devices(bus);
272 }
273
274 return Err(e);
275 }
276 }
277
278 Ok(SleepGuard { buses })
279 }
280 }
281
282 impl<'a> Drop for SleepGuard<'a> {
drop(&mut self)283 fn drop(&mut self) {
284 for bus in self.buses {
285 wake_devices(bus);
286 }
287 }
288 }
289
snapshot_devices( bus: &Bus, add_snapshot: impl FnMut(u32, serde_json::Value), ) -> anyhow::Result<()>290 fn snapshot_devices(
291 bus: &Bus,
292 add_snapshot: impl FnMut(u32, serde_json::Value),
293 ) -> anyhow::Result<()> {
294 match bus.snapshot_devices(add_snapshot) {
295 Ok(_) => {
296 info!("Devices snapshot successfully");
297 Ok(())
298 }
299 Err(e) => {
300 // If snapshot fails, wake devices and return error
301 error!("failed to snapshot devices: {}", e);
302 Err(e)
303 }
304 }
305 }
306
restore_devices( bus: &Bus, devices_map: &mut HashMap<u32, VecDeque<serde_json::Value>>, ) -> anyhow::Result<()>307 fn restore_devices(
308 bus: &Bus,
309 devices_map: &mut HashMap<u32, VecDeque<serde_json::Value>>,
310 ) -> anyhow::Result<()> {
311 match bus.restore_devices(devices_map) {
312 Ok(_) => {
313 info!("Devices restore successfully");
314 Ok(())
315 }
316 Err(e) => {
317 // If restore fails, wake devices and return error
318 error!("failed to restore devices: {}", e);
319 Err(e)
320 }
321 }
322 }
323
324 #[derive(serde::Serialize, serde::Deserialize)]
325 struct SnapshotRoot {
326 guest_memory_metadata: serde_json::Value,
327 devices: Vec<HashMap<u32, serde_json::Value>>,
328 }
329
snapshot_handler( path: &std::path::Path, guest_memory: &GuestMemory, buses: &[&Bus], ) -> anyhow::Result<()>330 async fn snapshot_handler(
331 path: &std::path::Path,
332 guest_memory: &GuestMemory,
333 buses: &[&Bus],
334 ) -> anyhow::Result<()> {
335 let mut snapshot_root = SnapshotRoot {
336 guest_memory_metadata: serde_json::Value::Null,
337 devices: Vec::new(),
338 };
339
340 // TODO(b/268093674): Better output file format.
341 // TODO(b/268094487): If the snapshot fail, this leaves an incomplete memory snapshot at the
342 // requested path.
343
344 let mut json_file =
345 File::create(path).with_context(|| format!("failed to open {}", path.display()))?;
346
347 let mem_path = path.with_extension("mem");
348 let mut mem_file = File::create(&mem_path)
349 .with_context(|| format!("failed to open {}", mem_path.display()))?;
350
351 snapshot_root.guest_memory_metadata = guest_memory
352 .snapshot(&mut mem_file)
353 .context("failed to snapshot memory")?;
354
355 for bus in buses {
356 snapshot_devices(bus, |id, snapshot| {
357 snapshot_root.devices.push([(id, snapshot)].into())
358 })
359 .context("failed to snapshot devices")?;
360 }
361
362 serde_json::to_writer(&mut json_file, &snapshot_root)?;
363
364 Ok(())
365 }
366
restore_handler( path: &std::path::Path, guest_memory: &GuestMemory, buses: &[&Bus], ) -> anyhow::Result<()>367 async fn restore_handler(
368 path: &std::path::Path,
369 guest_memory: &GuestMemory,
370 buses: &[&Bus],
371 ) -> anyhow::Result<()> {
372 let file = File::open(path).with_context(|| format!("failed to open {}", path.display()))?;
373
374 let mem_path = path.with_extension("mem");
375 let mut mem_file =
376 File::open(&mem_path).with_context(|| format!("failed to open {}", mem_path.display()))?;
377
378 let snapshot_root: SnapshotRoot = serde_json::from_reader(file)?;
379
380 let mut devices_map: HashMap<u32, VecDeque<serde_json::Value>> = HashMap::new();
381 for (id, device) in snapshot_root.devices.into_iter().flatten() {
382 devices_map.entry(id).or_default().push_back(device)
383 }
384
385 {
386 let _sleep_guard = SleepGuard::new(buses)?;
387
388 guest_memory.restore(snapshot_root.guest_memory_metadata, &mut mem_file)?;
389
390 for bus in buses {
391 restore_devices(bus, &mut devices_map)?;
392 }
393 }
394
395 for (key, _) in devices_map.iter().filter(|(_, v)| !v.is_empty()) {
396 info!(
397 "Unused restore data for device_id {}, device might be missing.",
398 key
399 );
400 }
401
402 Ok(())
403 }
404
handle_command_tube( command_tube: AsyncTube, guest_memory: GuestMemory, io_bus: Arc<Bus>, mmio_bus: Arc<Bus>, ) -> anyhow::Result<()>405 async fn handle_command_tube(
406 command_tube: AsyncTube,
407 guest_memory: GuestMemory,
408 io_bus: Arc<Bus>,
409 mmio_bus: Arc<Bus>,
410 ) -> anyhow::Result<()> {
411 let buses = &[&*io_bus, &*mmio_bus];
412 let mut _sleep_guard = None;
413 loop {
414 match command_tube.next().await {
415 Ok(command) => {
416 match command {
417 DeviceControlCommand::SleepDevices => match SleepGuard::new(buses) {
418 Ok(guard) => {
419 _sleep_guard = Some(guard);
420 command_tube
421 .send(VmResponse::Ok)
422 .await
423 .context("failed to reply to sleep command")?;
424 }
425 Err(e) => {
426 command_tube
427 .send(VmResponse::ErrString(e.to_string()))
428 .await
429 .context("failed to send response.")?;
430 }
431 },
432 DeviceControlCommand::WakeDevices => {
433 _sleep_guard = None;
434 command_tube
435 .send(VmResponse::Ok)
436 .await
437 .context("failed to reply to wake devices request")?;
438 }
439 DeviceControlCommand::SnapshotDevices {
440 snapshot_path: path,
441 } => {
442 assert!(
443 _sleep_guard.is_some(),
444 "devices must be sleeping to snapshot"
445 );
446 if let Err(e) = snapshot_handler(path.as_path(), &guest_memory, buses).await
447 {
448 error!("failed to snapshot: {}", e);
449 command_tube
450 .send(VmResponse::ErrString(e.to_string()))
451 .await
452 .context("Failed to send response")?;
453 continue;
454 }
455 command_tube
456 .send(VmResponse::Ok)
457 .await
458 .context("Failed to send response")?;
459 }
460 DeviceControlCommand::RestoreDevices { restore_path: path } => {
461 if let Err(e) =
462 restore_handler(path.as_path(), &guest_memory, &[&*io_bus, &*mmio_bus])
463 .await
464 {
465 error!("failed to restore: {}", e);
466 command_tube
467 .send(VmResponse::ErrString(e.to_string()))
468 .await
469 .context("Failed to send response")?;
470 continue;
471 }
472 command_tube
473 .send(VmResponse::Ok)
474 .await
475 .context("Failed to send response")?;
476 }
477 DeviceControlCommand::Exit => {
478 return Ok(());
479 }
480 };
481 }
482 Err(e) => {
483 if matches!(e, TubeError::Disconnected) {
484 // Tube disconnected - shut down thread.
485 return Ok(());
486 }
487 return Err(anyhow!("Failed to receive: {}", e));
488 }
489 }
490 }
491 }
492