Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/lib.rs
5392 views
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
9
pub mod ac_adapter;
10
pub mod acpi;
11
pub mod bat;
12
mod bus;
13
#[cfg(feature = "stats")]
14
mod bus_stats;
15
pub mod cmos;
16
#[cfg(target_arch = "x86_64")]
17
mod debugcon;
18
mod fw_cfg;
19
mod i8042;
20
mod irq_event;
21
pub mod irqchip;
22
mod mock;
23
mod pci;
24
mod pflash;
25
pub mod pl030;
26
pub mod pmc_virt;
27
mod power;
28
mod serial;
29
pub mod serial_device;
30
mod smccc_trng;
31
mod suspendable;
32
mod sys;
33
#[cfg(any(target_os = "android", target_os = "linux"))]
34
mod virtcpufreq;
35
#[cfg(any(target_os = "android", target_os = "linux"))]
36
mod virtcpufreq_v2;
37
pub mod virtio;
38
#[cfg(feature = "vtpm")]
39
mod vtpm_proxy;
40
41
cfg_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
49
use std::sync::Arc;
50
51
use anyhow::anyhow;
52
use anyhow::Context;
53
use base::debug;
54
use base::error;
55
use base::info;
56
use base::Tube;
57
use base::TubeError;
58
use cros_async::AsyncTube;
59
use cros_async::Executor;
60
use serde::Deserialize;
61
use serde::Serialize;
62
use vm_control::DeviceControlCommand;
63
use vm_control::DevicesState;
64
use vm_control::VmResponse;
65
66
pub use self::acpi::ACPIPMFixedEvent;
67
pub use self::acpi::ACPIPMResource;
68
pub use self::bat::BatteryError;
69
pub use self::bat::GoldfishBattery;
70
pub use self::bus::Bus;
71
pub use self::bus::BusAccessInfo;
72
pub use self::bus::BusDevice;
73
pub use self::bus::BusDeviceObj;
74
pub use self::bus::BusDeviceSync;
75
pub use self::bus::BusRange;
76
pub use self::bus::BusResumeDevice;
77
pub use self::bus::BusType;
78
pub use self::bus::Error as BusError;
79
pub use self::bus::HotPlugBus;
80
pub use self::bus::HotPlugKey;
81
#[cfg(feature = "stats")]
82
pub use self::bus_stats::BusStatistics;
83
#[cfg(target_arch = "x86_64")]
84
pub use self::debugcon::Debugcon;
85
pub use self::fw_cfg::Error as FwCfgError;
86
pub use self::fw_cfg::FwCfgDevice;
87
pub use self::fw_cfg::FwCfgItemType;
88
pub use self::fw_cfg::FwCfgParameters;
89
pub use self::fw_cfg::FW_CFG_BASE_PORT;
90
pub use self::fw_cfg::FW_CFG_MAX_FILE_SLOTS;
91
pub use self::fw_cfg::FW_CFG_WIDTH;
92
pub use self::i8042::I8042Device;
93
pub use self::irq_event::IrqEdgeEvent;
94
pub use self::irq_event::IrqLevelEvent;
95
pub use self::irqchip::*;
96
pub use self::mock::MockDevice;
97
pub use self::pci::BarRange;
98
pub use self::pci::GpeScope;
99
#[cfg(feature = "pci-hotplug")]
100
pub use self::pci::HotPluggable;
101
#[cfg(feature = "pci-hotplug")]
102
pub use self::pci::IntxParameter;
103
#[cfg(feature = "pci-hotplug")]
104
pub use self::pci::NetResourceCarrier;
105
pub use self::pci::PciAddress;
106
pub use self::pci::PciAddressError;
107
pub use self::pci::PciBarConfiguration;
108
pub use self::pci::PciBarIndex;
109
pub use self::pci::PciBus;
110
pub use self::pci::PciClassCode;
111
pub use self::pci::PciConfigIo;
112
pub use self::pci::PciConfigMmio;
113
pub use self::pci::PciDevice;
114
pub use self::pci::PciDeviceError;
115
pub use self::pci::PciInterruptPin;
116
pub use self::pci::PciMmioMapper;
117
pub use self::pci::PciRoot;
118
pub use self::pci::PciRootCommand;
119
pub use self::pci::PciVirtualConfigMmio;
120
pub use self::pci::PreferredIrq;
121
#[cfg(feature = "pci-hotplug")]
122
pub use self::pci::ResourceCarrier;
123
pub use self::pci::StubPciDevice;
124
pub use self::pci::StubPciParameters;
125
pub use self::pflash::Pflash;
126
pub use self::pflash::PflashParameters;
127
pub use self::pl030::Pl030;
128
pub use self::pmc_virt::VirtualPmc;
129
pub use self::power::hvc::HvcDevicePowerManager;
130
pub use self::power::DevicePowerManager;
131
pub use self::serial::Serial;
132
pub use self::serial_device::Error as SerialError;
133
pub use self::serial_device::SerialDevice;
134
pub use self::serial_device::SerialHardware;
135
pub use self::serial_device::SerialParameters;
136
pub use self::serial_device::SerialType;
137
pub use self::smccc_trng::SmcccTrng;
138
pub use self::suspendable::DeviceState;
139
pub use self::suspendable::Suspendable;
140
#[cfg(any(target_os = "android", target_os = "linux"))]
141
pub use self::virtcpufreq::VirtCpufreq;
142
#[cfg(any(target_os = "android", target_os = "linux"))]
143
pub use self::virtcpufreq_v2::VirtCpufreqV2;
144
pub use self::virtio::VirtioMmioDevice;
145
pub use self::virtio::VirtioPciDevice;
146
#[cfg(feature = "vtpm")]
147
pub use self::vtpm_proxy::VtpmProxy;
148
149
cfg_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)]
190
pub struct UnpinRequest {
191
/// The ranges presents (start gfn, count).
192
ranges: Vec<(u64, u64)>,
193
}
194
195
#[derive(Serialize, Deserialize, Debug)]
196
pub enum UnpinResponse {
197
Success,
198
Failed,
199
}
200
201
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
202
pub 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.
216
pub 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
238
fn 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
247
fn 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
262
async 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
277
async 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
292
async 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
}
403
404