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