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