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