• 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(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