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 ac_adapter;
10pub mod acpi;
11pub mod bat;
12mod bus;
13#[cfg(feature = "stats")]
14mod bus_stats;
15pub mod cmos;
16#[cfg(target_arch = "x86_64")]
17mod debugcon;
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 serial;
28pub mod serial_device;
29mod suspendable;
30mod sys;
31#[cfg(any(target_os = "android", target_os = "linux"))]
32mod virtcpufreq;
33#[cfg(any(target_os = "android", target_os = "linux"))]
34mod virtcpufreq_v2;
35pub mod virtio;
36#[cfg(feature = "vtpm")]
37mod vtpm_proxy;
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::fw_cfg::Error as FwCfgError;
84pub use self::fw_cfg::FwCfgDevice;
85pub use self::fw_cfg::FwCfgItemType;
86pub use self::fw_cfg::FwCfgParameters;
87pub use self::fw_cfg::FW_CFG_BASE_PORT;
88pub use self::fw_cfg::FW_CFG_MAX_FILE_SLOTS;
89pub use self::fw_cfg::FW_CFG_WIDTH;
90pub use self::i8042::I8042Device;
91pub use self::irq_event::IrqEdgeEvent;
92pub use self::irq_event::IrqLevelEvent;
93pub use self::irqchip::*;
94pub use self::mock::MockDevice;
95pub use self::pci::BarRange;
96pub use self::pci::GpeScope;
97#[cfg(feature = "pci-hotplug")]
98pub use self::pci::HotPluggable;
99#[cfg(feature = "pci-hotplug")]
100pub use self::pci::IntxParameter;
101#[cfg(feature = "pci-hotplug")]
102pub use self::pci::NetResourceCarrier;
103pub use self::pci::PciAddress;
104pub use self::pci::PciAddressError;
105pub use self::pci::PciBarConfiguration;
106pub use self::pci::PciBarIndex;
107pub use self::pci::PciBus;
108pub use self::pci::PciClassCode;
109pub use self::pci::PciConfigIo;
110pub use self::pci::PciConfigMmio;
111pub use self::pci::PciDevice;
112pub use self::pci::PciDeviceError;
113pub use self::pci::PciInterruptPin;
114pub use self::pci::PciMmioMapper;
115pub use self::pci::PciRoot;
116pub use self::pci::PciRootCommand;
117pub use self::pci::PciVirtualConfigMmio;
118pub use self::pci::PreferredIrq;
119#[cfg(feature = "pci-hotplug")]
120pub use self::pci::ResourceCarrier;
121pub use self::pci::StubPciDevice;
122pub use self::pci::StubPciParameters;
123pub use self::pflash::Pflash;
124pub use self::pflash::PflashParameters;
125pub use self::pl030::Pl030;
126pub use self::pmc_virt::VirtualPmc;
127pub use self::serial::Serial;
128pub use self::serial_device::Error as SerialError;
129pub use self::serial_device::SerialDevice;
130pub use self::serial_device::SerialHardware;
131pub use self::serial_device::SerialParameters;
132pub use self::serial_device::SerialType;
133pub use self::suspendable::DeviceState;
134pub use self::suspendable::Suspendable;
135#[cfg(any(target_os = "android", target_os = "linux"))]
136pub use self::virtcpufreq::VirtCpufreq;
137#[cfg(any(target_os = "android", target_os = "linux"))]
138pub use self::virtcpufreq_v2::VirtCpufreqV2;
139pub use self::virtio::VirtioMmioDevice;
140pub use self::virtio::VirtioPciDevice;
141#[cfg(feature = "vtpm")]
142pub use self::vtpm_proxy::VtpmProxy;
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::ac_adapter::AcAdapter;
165        pub use self::proxy::ChildProcIntf;
166        pub use self::proxy::Error as ProxyError;
167        pub use self::proxy::ProxyDevice;
168        #[cfg(feature = "usb")]
169        pub use self::usb::backend::device_provider::DeviceProvider;
170        #[cfg(feature = "usb")]
171        pub use self::usb::xhci::xhci_controller::XhciController;
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
209// Thread that handles commands sent to devices - such as snapshot, sleep, suspend
210// Created when the VM is first created, and re-created on resumption of the VM.
211pub fn create_devices_worker_thread(
212    io_bus: Arc<Bus>,
213    mmio_bus: Arc<Bus>,
214    device_ctrl_resp: Tube,
215) -> std::io::Result<std::thread::JoinHandle<()>> {
216    std::thread::Builder::new()
217        .name("device_control".to_string())
218        .spawn(move || {
219            let ex = Executor::new().expect("Failed to create an executor");
220
221            let async_control = AsyncTube::new(&ex, device_ctrl_resp).unwrap();
222            match ex.run_until(
223                async move { handle_command_tube(async_control, io_bus, mmio_bus).await },
224            ) {
225                Ok(_) => {}
226                Err(e) => {
227                    error!("Device control thread exited with error: {}", e);
228                }
229            };
230        })
231}
232
233fn sleep_buses(buses: &[&Bus]) -> anyhow::Result<()> {
234    for bus in buses {
235        bus.sleep_devices()
236            .with_context(|| format!("failed to sleep devices on {:?} bus", bus.get_bus_type()))?;
237        debug!("Devices slept successfully on {:?} bus", bus.get_bus_type());
238    }
239    Ok(())
240}
241
242fn wake_buses(buses: &[&Bus]) {
243    for bus in buses {
244        bus.wake_devices()
245            .with_context(|| format!("failed to wake devices on {:?} bus", bus.get_bus_type()))
246            // Some devices may have slept. Eternally.
247            // Recovery - impossible.
248            // Shut down VM.
249            .expect("VM panicked to avoid unexpected behavior");
250        debug!(
251            "Devices awoken successfully on {:?} Bus",
252            bus.get_bus_type()
253        );
254    }
255}
256
257async fn snapshot_handler(
258    snapshot_writer: snapshot::SnapshotWriter,
259    buses: &[&Bus],
260) -> anyhow::Result<()> {
261    for (i, bus) in buses.iter().enumerate() {
262        bus.snapshot_devices(&snapshot_writer.add_namespace(&format!("bus{i}"))?)
263            .context("failed to snapshot bus devices")?;
264        debug!(
265            "Devices snapshot successfully for {:?} Bus",
266            bus.get_bus_type()
267        );
268    }
269    Ok(())
270}
271
272async fn restore_devices(
273    snapshot_reader: snapshot::SnapshotReader,
274    buses: &[&Bus],
275) -> anyhow::Result<()> {
276    for (i, bus) in buses.iter().enumerate() {
277        bus.restore_devices(&snapshot_reader.namespace(&format!("bus{i}"))?)
278            .context("failed to restore bus devices")?;
279        debug!(
280            "Devices restore successfully for {:?} Bus",
281            bus.get_bus_type()
282        );
283    }
284    Ok(())
285}
286
287async fn handle_command_tube(
288    command_tube: AsyncTube,
289    io_bus: Arc<Bus>,
290    mmio_bus: Arc<Bus>,
291) -> anyhow::Result<()> {
292    let buses = &[&*io_bus, &*mmio_bus];
293
294    // We assume devices are awake. This is safe because if the VM starts the
295    // sleeping state, run_control will ask us to sleep devices.
296    let mut devices_state = DevicesState::Wake;
297
298    loop {
299        match command_tube.next().await {
300            Ok(command) => {
301                match command {
302                    DeviceControlCommand::SleepDevices => {
303                        if let DevicesState::Wake = devices_state {
304                            match sleep_buses(buses) {
305                                Ok(()) => {
306                                    devices_state = DevicesState::Sleep;
307                                }
308                                Err(e) => {
309                                    error!("failed to sleep: {:#}", e);
310
311                                    // Failing to sleep could mean a single device failing to sleep.
312                                    // Wake up devices to resume functionality of the VM.
313                                    info!("Attempting to wake devices after failed sleep");
314                                    wake_buses(buses);
315
316                                    command_tube
317                                        .send(VmResponse::ErrString(e.to_string()))
318                                        .await
319                                        .context("failed to send response.")?;
320                                    continue;
321                                }
322                            }
323                        }
324                        command_tube
325                            .send(VmResponse::Ok)
326                            .await
327                            .context("failed to reply to sleep command")?;
328                    }
329                    DeviceControlCommand::WakeDevices => {
330                        if let DevicesState::Sleep = devices_state {
331                            wake_buses(buses);
332                            devices_state = DevicesState::Wake;
333                        }
334                        command_tube
335                            .send(VmResponse::Ok)
336                            .await
337                            .context("failed to reply to wake devices request")?;
338                    }
339                    DeviceControlCommand::SnapshotDevices { snapshot_writer } => {
340                        assert!(
341                            matches!(devices_state, DevicesState::Sleep),
342                            "devices must be sleeping to snapshot"
343                        );
344                        if let Err(e) = snapshot_handler(snapshot_writer, buses).await {
345                            error!("failed to snapshot: {:#}", e);
346                            command_tube
347                                .send(VmResponse::ErrString(e.to_string()))
348                                .await
349                                .context("Failed to send response")?;
350                            continue;
351                        }
352                        command_tube
353                            .send(VmResponse::Ok)
354                            .await
355                            .context("Failed to send response")?;
356                    }
357                    DeviceControlCommand::RestoreDevices { snapshot_reader } => {
358                        assert!(
359                            matches!(devices_state, DevicesState::Sleep),
360                            "devices must be sleeping to restore"
361                        );
362                        if let Err(e) =
363                            restore_devices(snapshot_reader, &[&*io_bus, &*mmio_bus]).await
364                        {
365                            error!("failed to restore: {:#}", e);
366                            command_tube
367                                .send(VmResponse::ErrString(e.to_string()))
368                                .await
369                                .context("Failed to send response")?;
370                            continue;
371                        }
372                        command_tube
373                            .send(VmResponse::Ok)
374                            .await
375                            .context("Failed to send response")?;
376                    }
377                    DeviceControlCommand::GetDevicesState => {
378                        command_tube
379                            .send(VmResponse::DevicesState(devices_state.clone()))
380                            .await
381                            .context("failed to send response")?;
382                    }
383                    DeviceControlCommand::Exit => {
384                        return Ok(());
385                    }
386                };
387            }
388            Err(e) => {
389                if matches!(e, TubeError::Disconnected) {
390                    // Tube disconnected - shut down thread.
391                    return Ok(());
392                }
393                return Err(anyhow!("Failed to receive: {}", e));
394            }
395        }
396    }
397}