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 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::serial::Serial;
129pub use self::serial_device::Error as SerialError;
130pub use self::serial_device::SerialDevice;
131pub use self::serial_device::SerialHardware;
132pub use self::serial_device::SerialParameters;
133pub use self::serial_device::SerialType;
134pub use self::smccc_trng::SmcccTrng;
135pub use self::suspendable::DeviceState;
136pub use self::suspendable::Suspendable;
137#[cfg(any(target_os = "android", target_os = "linux"))]
138pub use self::virtcpufreq::VirtCpufreq;
139#[cfg(any(target_os = "android", target_os = "linux"))]
140pub use self::virtcpufreq_v2::VirtCpufreqV2;
141pub use self::virtio::VirtioMmioDevice;
142pub use self::virtio::VirtioPciDevice;
143#[cfg(feature = "vtpm")]
144pub use self::vtpm_proxy::VtpmProxy;
145
146cfg_if::cfg_if! {
147 if #[cfg(any(target_os = "android", target_os = "linux"))] {
148 mod platform;
149 mod proxy;
150 pub mod vmwdt;
151 pub mod vfio;
152 #[cfg(feature = "usb")]
153 #[macro_use]
154 mod register_space;
155 #[cfg(feature = "usb")]
156 pub mod usb;
157 #[cfg(feature = "usb")]
158 mod utils;
159
160 pub use self::pci::{
161 CoIommuDev, CoIommuParameters, CoIommuUnpinPolicy, PciBridge, PcieDownstreamPort,
162 PcieHostPort, PcieRootPort, PcieUpstreamPort, PvPanicCode, PvPanicPciDevice,
163 VfioPciDevice,
164 };
165 pub use self::platform::VfioPlatformDevice;
166 pub use self::ac_adapter::AcAdapter;
167 pub use self::proxy::ChildProcIntf;
168 pub use self::proxy::Error as ProxyError;
169 pub use self::proxy::ProxyDevice;
170 #[cfg(feature = "usb")]
171 pub use self::usb::backend::device_provider::DeviceProvider;
172 #[cfg(feature = "usb")]
173 pub use self::usb::xhci::xhci_controller::XhciController;
174 pub use self::vfio::VfioContainer;
175 pub use self::vfio::VfioDevice;
176 pub use self::vfio::VfioDeviceType;
177 pub use self::virtio::vfio_wrapper;
178
179 } else if #[cfg(windows)] {
180 } else {
181 compile_error!("Unsupported platform");
182 }
183}
184
185#[derive(Serialize, Deserialize, Debug)]
187pub struct UnpinRequest {
188 ranges: Vec<(u64, u64)>,
190}
191
192#[derive(Serialize, Deserialize, Debug)]
193pub enum UnpinResponse {
194 Success,
195 Failed,
196}
197
198#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
199pub enum IommuDevType {
200 #[serde(rename = "off")]
201 #[default]
202 NoIommu,
203 #[serde(rename = "viommu")]
204 VirtioIommu,
205 #[serde(rename = "coiommu")]
206 CoIommu,
207 #[serde(rename = "pkvm-iommu")]
208 PkvmPviommu,
209}
210
211pub fn create_devices_worker_thread(
214 io_bus: Arc<Bus>,
215 mmio_bus: Arc<Bus>,
216 device_ctrl_resp: Tube,
217) -> std::io::Result<std::thread::JoinHandle<()>> {
218 std::thread::Builder::new()
219 .name("device_control".to_string())
220 .spawn(move || {
221 let ex = Executor::new().expect("Failed to create an executor");
222
223 let async_control = AsyncTube::new(&ex, device_ctrl_resp).unwrap();
224 match ex.run_until(
225 async move { handle_command_tube(async_control, io_bus, mmio_bus).await },
226 ) {
227 Ok(_) => {}
228 Err(e) => {
229 error!("Device control thread exited with error: {}", e);
230 }
231 };
232 })
233}
234
235fn sleep_buses(buses: &[&Bus]) -> anyhow::Result<()> {
236 for bus in buses {
237 bus.sleep_devices()
238 .with_context(|| format!("failed to sleep devices on {:?} bus", bus.get_bus_type()))?;
239 debug!("Devices slept successfully on {:?} bus", bus.get_bus_type());
240 }
241 Ok(())
242}
243
244fn wake_buses(buses: &[&Bus]) {
245 for bus in buses {
246 bus.wake_devices()
247 .with_context(|| format!("failed to wake devices on {:?} bus", bus.get_bus_type()))
248 .expect("VM panicked to avoid unexpected behavior");
252 debug!(
253 "Devices awoken successfully on {:?} Bus",
254 bus.get_bus_type()
255 );
256 }
257}
258
259async fn snapshot_handler(
260 snapshot_writer: snapshot::SnapshotWriter,
261 buses: &[&Bus],
262) -> anyhow::Result<()> {
263 for (i, bus) in buses.iter().enumerate() {
264 bus.snapshot_devices(&snapshot_writer.add_namespace(&format!("bus{i}"))?)
265 .context("failed to snapshot bus devices")?;
266 debug!(
267 "Devices snapshot successfully for {:?} Bus",
268 bus.get_bus_type()
269 );
270 }
271 Ok(())
272}
273
274async fn restore_devices(
275 snapshot_reader: snapshot::SnapshotReader,
276 buses: &[&Bus],
277) -> anyhow::Result<()> {
278 for (i, bus) in buses.iter().enumerate() {
279 bus.restore_devices(&snapshot_reader.namespace(&format!("bus{i}"))?)
280 .context("failed to restore bus devices")?;
281 debug!(
282 "Devices restore successfully for {:?} Bus",
283 bus.get_bus_type()
284 );
285 }
286 Ok(())
287}
288
289async fn handle_command_tube(
290 command_tube: AsyncTube,
291 io_bus: Arc<Bus>,
292 mmio_bus: Arc<Bus>,
293) -> anyhow::Result<()> {
294 let buses = &[&*io_bus, &*mmio_bus];
295
296 let mut devices_state = DevicesState::Wake;
299
300 loop {
301 match command_tube.next().await {
302 Ok(command) => {
303 match command {
304 DeviceControlCommand::SleepDevices => {
305 if let DevicesState::Wake = devices_state {
306 match sleep_buses(buses) {
307 Ok(()) => {
308 devices_state = DevicesState::Sleep;
309 }
310 Err(e) => {
311 error!("failed to sleep: {:#}", e);
312
313 info!("Attempting to wake devices after failed sleep");
316 wake_buses(buses);
317
318 command_tube
319 .send(VmResponse::ErrString(e.to_string()))
320 .await
321 .context("failed to send response.")?;
322 continue;
323 }
324 }
325 }
326 command_tube
327 .send(VmResponse::Ok)
328 .await
329 .context("failed to reply to sleep command")?;
330 }
331 DeviceControlCommand::WakeDevices => {
332 if let DevicesState::Sleep = devices_state {
333 wake_buses(buses);
334 devices_state = DevicesState::Wake;
335 }
336 command_tube
337 .send(VmResponse::Ok)
338 .await
339 .context("failed to reply to wake devices request")?;
340 }
341 DeviceControlCommand::SnapshotDevices { snapshot_writer } => {
342 assert!(
343 matches!(devices_state, DevicesState::Sleep),
344 "devices must be sleeping to snapshot"
345 );
346 if let Err(e) = snapshot_handler(snapshot_writer, buses).await {
347 error!("failed to snapshot: {:#}", e);
348 command_tube
349 .send(VmResponse::ErrString(e.to_string()))
350 .await
351 .context("Failed to send response")?;
352 continue;
353 }
354 command_tube
355 .send(VmResponse::Ok)
356 .await
357 .context("Failed to send response")?;
358 }
359 DeviceControlCommand::RestoreDevices { snapshot_reader } => {
360 assert!(
361 matches!(devices_state, DevicesState::Sleep),
362 "devices must be sleeping to restore"
363 );
364 if let Err(e) =
365 restore_devices(snapshot_reader, &[&*io_bus, &*mmio_bus]).await
366 {
367 error!("failed to restore: {:#}", e);
368 command_tube
369 .send(VmResponse::ErrString(e.to_string()))
370 .await
371 .context("Failed to send response")?;
372 continue;
373 }
374 command_tube
375 .send(VmResponse::Ok)
376 .await
377 .context("Failed to send response")?;
378 }
379 DeviceControlCommand::GetDevicesState => {
380 command_tube
381 .send(VmResponse::DevicesState(devices_state.clone()))
382 .await
383 .context("failed to send response")?;
384 }
385 DeviceControlCommand::Exit => {
386 return Ok(());
387 }
388 };
389 }
390 Err(e) => {
391 if matches!(e, TubeError::Disconnected) {
392 return Ok(());
394 }
395 return Err(anyhow!("Failed to receive: {}", e));
396 }
397 }
398 }
399}