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