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 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::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#[cfg(feature = "vtpm")]
147pub use self::vtpm_proxy::VtpmProxy;
148
149cfg_if::cfg_if! {
150    if #[cfg(any(target_os = "android", target_os = "linux"))] {
151        mod platform;
152        mod proxy;
153        pub mod vmwdt;
154        pub mod vfio;
155        #[cfg(feature = "usb")]
156        #[macro_use]
157        mod register_space;
158        #[cfg(feature = "usb")]
159        pub mod usb;
160        #[cfg(feature = "usb")]
161        mod utils;
162
163        pub use self::pci::{
164            CoIommuDev, CoIommuParameters, CoIommuUnpinPolicy, PciBridge, PcieDownstreamPort,
165            PcieHostPort, PcieRootPort, PcieUpstreamPort, PvPanicCode, PvPanicPciDevice,
166            VfioPciDevice,
167        };
168        pub use self::platform::VfioPlatformDevice;
169        pub use self::ac_adapter::AcAdapter;
170        pub use self::proxy::ChildProcIntf;
171        pub use self::proxy::Error as ProxyError;
172        pub use self::proxy::ProxyDevice;
173        #[cfg(feature = "usb")]
174        pub use self::usb::backend::device_provider::DeviceProvider;
175        #[cfg(feature = "usb")]
176        pub use self::usb::xhci::xhci_controller::XhciController;
177        pub use self::vfio::VfioContainer;
178        pub use self::vfio::VfioDevice;
179        pub use self::vfio::VfioDeviceType;
180        pub use self::virtio::vfio_wrapper;
181
182    } else if #[cfg(windows)] {
183    } else {
184        compile_error!("Unsupported platform");
185    }
186}
187
188/// Request CoIOMMU to unpin a specific range.
189#[derive(Serialize, Deserialize, Debug)]
190pub struct UnpinRequest {
191    /// The ranges presents (start gfn, count).
192    ranges: Vec<(u64, u64)>,
193}
194
195#[derive(Serialize, Deserialize, Debug)]
196pub enum UnpinResponse {
197    Success,
198    Failed,
199}
200
201#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
202pub enum IommuDevType {
203    #[serde(rename = "off")]
204    #[default]
205    NoIommu,
206    #[serde(rename = "viommu")]
207    VirtioIommu,
208    #[serde(rename = "coiommu")]
209    CoIommu,
210    #[serde(rename = "pkvm-iommu")]
211    PkvmPviommu,
212}
213
214// Thread that handles commands sent to devices - such as snapshot, sleep, suspend
215// Created when the VM is first created, and re-created on resumption of the VM.
216pub fn create_devices_worker_thread(
217    io_bus: Arc<Bus>,
218    mmio_bus: Arc<Bus>,
219    device_ctrl_resp: Tube,
220) -> std::io::Result<std::thread::JoinHandle<()>> {
221    std::thread::Builder::new()
222        .name("device_control".to_string())
223        .spawn(move || {
224            let ex = Executor::new().expect("Failed to create an executor");
225
226            let async_control = AsyncTube::new(&ex, device_ctrl_resp).unwrap();
227            match ex.run_until(
228                async move { handle_command_tube(async_control, io_bus, mmio_bus).await },
229            ) {
230                Ok(_) => {}
231                Err(e) => {
232                    error!("Device control thread exited with error: {}", e);
233                }
234            };
235        })
236}
237
238fn sleep_buses(buses: &[&Bus]) -> anyhow::Result<()> {
239    for bus in buses {
240        bus.sleep_devices()
241            .with_context(|| format!("failed to sleep devices on {:?} bus", bus.get_bus_type()))?;
242        debug!("Devices slept successfully on {:?} bus", bus.get_bus_type());
243    }
244    Ok(())
245}
246
247fn wake_buses(buses: &[&Bus]) {
248    for bus in buses {
249        bus.wake_devices()
250            .with_context(|| format!("failed to wake devices on {:?} bus", bus.get_bus_type()))
251            // Some devices may have slept. Eternally.
252            // Recovery - impossible.
253            // Shut down VM.
254            .expect("VM panicked to avoid unexpected behavior");
255        debug!(
256            "Devices awoken successfully on {:?} Bus",
257            bus.get_bus_type()
258        );
259    }
260}
261
262async fn snapshot_handler(
263    snapshot_writer: snapshot::SnapshotWriter,
264    buses: &[&Bus],
265) -> anyhow::Result<()> {
266    for (i, bus) in buses.iter().enumerate() {
267        bus.snapshot_devices(&snapshot_writer.add_namespace(&format!("bus{i}"))?)
268            .context("failed to snapshot bus devices")?;
269        debug!(
270            "Devices snapshot successfully for {:?} Bus",
271            bus.get_bus_type()
272        );
273    }
274    Ok(())
275}
276
277async fn restore_devices(
278    snapshot_reader: snapshot::SnapshotReader,
279    buses: &[&Bus],
280) -> anyhow::Result<()> {
281    for (i, bus) in buses.iter().enumerate() {
282        bus.restore_devices(&snapshot_reader.namespace(&format!("bus{i}"))?)
283            .context("failed to restore bus devices")?;
284        debug!(
285            "Devices restore successfully for {:?} Bus",
286            bus.get_bus_type()
287        );
288    }
289    Ok(())
290}
291
292async fn handle_command_tube(
293    command_tube: AsyncTube,
294    io_bus: Arc<Bus>,
295    mmio_bus: Arc<Bus>,
296) -> anyhow::Result<()> {
297    let buses = &[&*io_bus, &*mmio_bus];
298
299    // We assume devices are awake. This is safe because if the VM starts the
300    // sleeping state, run_control will ask us to sleep devices.
301    let mut devices_state = DevicesState::Wake;
302
303    loop {
304        match command_tube.next().await {
305            Ok(command) => {
306                match command {
307                    DeviceControlCommand::SleepDevices => {
308                        if let DevicesState::Wake = devices_state {
309                            match sleep_buses(buses) {
310                                Ok(()) => {
311                                    devices_state = DevicesState::Sleep;
312                                }
313                                Err(e) => {
314                                    error!("failed to sleep: {:#}", e);
315
316                                    // Failing to sleep could mean a single device failing to sleep.
317                                    // Wake up devices to resume functionality of the VM.
318                                    info!("Attempting to wake devices after failed sleep");
319                                    wake_buses(buses);
320
321                                    command_tube
322                                        .send(VmResponse::ErrString(e.to_string()))
323                                        .await
324                                        .context("failed to send response.")?;
325                                    continue;
326                                }
327                            }
328                        }
329                        command_tube
330                            .send(VmResponse::Ok)
331                            .await
332                            .context("failed to reply to sleep command")?;
333                    }
334                    DeviceControlCommand::WakeDevices => {
335                        if let DevicesState::Sleep = devices_state {
336                            wake_buses(buses);
337                            devices_state = DevicesState::Wake;
338                        }
339                        command_tube
340                            .send(VmResponse::Ok)
341                            .await
342                            .context("failed to reply to wake devices request")?;
343                    }
344                    DeviceControlCommand::SnapshotDevices { snapshot_writer } => {
345                        assert!(
346                            matches!(devices_state, DevicesState::Sleep),
347                            "devices must be sleeping to snapshot"
348                        );
349                        if let Err(e) = snapshot_handler(snapshot_writer, buses).await {
350                            error!("failed to snapshot: {:#}", e);
351                            command_tube
352                                .send(VmResponse::ErrString(e.to_string()))
353                                .await
354                                .context("Failed to send response")?;
355                            continue;
356                        }
357                        command_tube
358                            .send(VmResponse::Ok)
359                            .await
360                            .context("Failed to send response")?;
361                    }
362                    DeviceControlCommand::RestoreDevices { snapshot_reader } => {
363                        assert!(
364                            matches!(devices_state, DevicesState::Sleep),
365                            "devices must be sleeping to restore"
366                        );
367                        if let Err(e) =
368                            restore_devices(snapshot_reader, &[&*io_bus, &*mmio_bus]).await
369                        {
370                            error!("failed to restore: {:#}", 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::GetDevicesState => {
383                        command_tube
384                            .send(VmResponse::DevicesState(devices_state.clone()))
385                            .await
386                            .context("failed to send response")?;
387                    }
388                    DeviceControlCommand::Exit => {
389                        return Ok(());
390                    }
391                };
392            }
393            Err(e) => {
394                if matches!(e, TubeError::Disconnected) {
395                    // Tube disconnected - shut down thread.
396                    return Ok(());
397                }
398                return Err(anyhow!("Failed to receive: {}", e));
399            }
400        }
401    }
402}