1#![cfg_attr(windows, allow(unused))]
6
7pub 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#[derive(Serialize, Deserialize, Debug)]
185pub struct UnpinRequest {
186 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
209pub 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 .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 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 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 return Ok(());
392 }
393 return Err(anyhow!("Failed to receive: {}", e));
394 }
395 }
396 }
397}