devices/
lib.rs

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