diff --git a/devices/src/acpi.rs b/devices/src/acpi.rs index 40839465d1..b5d3d95b60 100644 --- a/devices/src/acpi.rs +++ b/devices/src/acpi.rs @@ -36,6 +36,7 @@ use crate::BusDevice; use crate::BusResumeDevice; use crate::DeviceId; use crate::IrqLevelEvent; +use crate::Suspendable; #[derive(Error, Debug)] pub enum ACPIPMError { @@ -217,6 +218,8 @@ impl ACPIPMResource { } } +impl Suspendable for ACPIPMResource {} + fn run_worker( sci_evt: IrqLevelEvent, kill_evt: Event, diff --git a/devices/src/bat.rs b/devices/src/bat.rs index ad105249a0..9822832390 100644 --- a/devices/src/bat.rs +++ b/devices/src/bat.rs @@ -28,6 +28,7 @@ use crate::BusAccessInfo; use crate::BusDevice; use crate::DeviceId; use crate::IrqLevelEvent; +use crate::Suspendable; /// Errors for battery devices. #[sorted] @@ -472,3 +473,5 @@ impl Aml for GoldfishBattery { .to_aml_bytes(bytes); } } + +impl Suspendable for GoldfishBattery {} diff --git a/devices/src/bus.rs b/devices/src/bus.rs index 408d94dfa3..884cb38179 100644 --- a/devices/src/bus.rs +++ b/devices/src/bus.rs @@ -26,6 +26,7 @@ use crate::BusStatistics; use crate::DeviceId; use crate::PciAddress; use crate::PciDevice; +use crate::Suspendable; #[cfg(unix)] use crate::VfioPlatformDevice; use crate::VirtioMmioDevice; @@ -80,7 +81,7 @@ pub enum BusType { /// The device does not care where it exists in address space as each method is only given an offset /// into its allocated portion of address space. #[allow(unused_variables)] -pub trait BusDevice: Send { +pub trait BusDevice: Send + Suspendable { /// Returns a label suitable for debug output. fn debug_label(&self) -> String; /// Returns a unique id per device type suitable for metrics gathering. diff --git a/devices/src/cmos.rs b/devices/src/cmos.rs index 7a82c29ffe..45d624ab3a 100644 --- a/devices/src/cmos.rs +++ b/devices/src/cmos.rs @@ -13,6 +13,7 @@ use crate::pci::CrosvmDeviceId; use crate::BusAccessInfo; use crate::BusDevice; use crate::DeviceId; +use crate::Suspendable; const INDEX_MASK: u8 = 0x7f; const INDEX_OFFSET: u64 = 0x0; @@ -122,6 +123,8 @@ impl BusDevice for Cmos { } } +impl Suspendable for Cmos {} + #[cfg(test)] mod tests { use chrono::NaiveDateTime; diff --git a/devices/src/debugcon.rs b/devices/src/debugcon.rs index c13d20e8ae..36aef84400 100644 --- a/devices/src/debugcon.rs +++ b/devices/src/debugcon.rs @@ -20,6 +20,7 @@ use crate::BusAccessInfo; use crate::BusDevice; use crate::DeviceId; use crate::SerialDevice; +use crate::Suspendable; const BOCHS_DEBUGCON_READBACK: u8 = 0xe9; @@ -88,6 +89,8 @@ impl Debugcon { } } +impl Suspendable for Debugcon {} + #[cfg(test)] mod tests { use std::io; diff --git a/devices/src/direct_io.rs b/devices/src/direct_io.rs index ca42439e06..7cae0becd0 100644 --- a/devices/src/direct_io.rs +++ b/devices/src/direct_io.rs @@ -23,6 +23,7 @@ use crate::BusDevice; use crate::BusDeviceSync; use crate::BusRange; use crate::DeviceId; +use crate::Suspendable; pub struct DirectIo { dev: Mutex, @@ -86,6 +87,8 @@ impl BusDeviceSync for DirectIo { } } +impl Suspendable for DirectIo {} + pub struct DirectMmio { dev: Mutex>, read_only: bool, @@ -216,3 +219,5 @@ impl BusDeviceSync for DirectMmio { self.iowr(ai, data); } } + +impl Suspendable for DirectMmio {} diff --git a/devices/src/i8042.rs b/devices/src/i8042.rs index 96716e076b..937dd4a736 100644 --- a/devices/src/i8042.rs +++ b/devices/src/i8042.rs @@ -10,6 +10,7 @@ use crate::pci::CrosvmDeviceId; use crate::BusAccessInfo; use crate::BusDevice; use crate::DeviceId; +use crate::Suspendable; /// A i8042 PS/2 controller that emulates just enough to shutdown the machine. pub struct I8042Device { @@ -55,3 +56,5 @@ impl BusDevice for I8042Device { } } } + +impl Suspendable for I8042Device {} diff --git a/devices/src/irqchip/ioapic.rs b/devices/src/irqchip/ioapic.rs index 0af3641762..69d8816321 100644 --- a/devices/src/irqchip/ioapic.rs +++ b/devices/src/irqchip/ioapic.rs @@ -31,6 +31,7 @@ use crate::pci::CrosvmDeviceId; use crate::BusDevice; use crate::DeviceId; use crate::IrqEventSource; +use crate::Suspendable; // ICH10 I/O APIC version: 0x20 const IOAPIC_VERSION_ID: u32 = 0x00000020; @@ -498,6 +499,8 @@ impl Ioapic { } } +impl Suspendable for Ioapic {} + #[sorted] #[derive(Error, Debug)] enum IoapicError { diff --git a/devices/src/irqchip/pic.rs b/devices/src/irqchip/pic.rs index 636017ffe6..0e6f41ffba 100644 --- a/devices/src/irqchip/pic.rs +++ b/devices/src/irqchip/pic.rs @@ -23,6 +23,7 @@ use crate::bus::BusAccessInfo; use crate::pci::CrosvmDeviceId; use crate::BusDevice; use crate::DeviceId; +use crate::Suspendable; pub struct Pic { // Indicates a pending INTR signal to LINT0 of vCPU, checked by vCPU thread. @@ -538,6 +539,8 @@ impl Pic { } } +impl Suspendable for Pic {} + #[cfg(test)] mod tests { // ICW4: Special fully nested mode with no auto EOI. diff --git a/devices/src/irqchip/userspace.rs b/devices/src/irqchip/userspace.rs index d81484abc1..8a76917747 100644 --- a/devices/src/irqchip/userspace.rs +++ b/devices/src/irqchip/userspace.rs @@ -76,6 +76,7 @@ use crate::IrqEventSource; use crate::IrqLevelEvent; use crate::Pit; use crate::PitError; +use crate::Suspendable; /// PIT channel 0 timer is connected to IRQ 0 const PIT_CHANNEL0_IRQ: u32 = 0; @@ -860,6 +861,8 @@ impl BusDevice for UserspaceIrqChip { } } +impl Suspendable for UserspaceIrqChip {} + impl BusDeviceSync for UserspaceIrqChip { fn read(&self, info: BusAccessInfo, data: &mut [u8]) { self.apics[info.id].lock().read(info.offset, data) diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs index 538f0d814d..86cf25ecef 100644 --- a/devices/src/pci/ac97.rs +++ b/devices/src/pci/ac97.rs @@ -46,6 +46,7 @@ use crate::pci::PciDeviceError; use crate::pci::PciInterruptPin; use crate::pci::PCI_VENDOR_ID_INTEL; use crate::IrqLevelEvent; +use crate::Suspendable; // Use 82801AA because it's what qemu does. const PCI_DEVICE_ID_INTEL_82801AA_5: u16 = 0x2415; @@ -405,6 +406,8 @@ impl PciDevice for Ac97Dev { } } +impl Suspendable for Ac97Dev {} + #[cfg(test)] mod tests { use resources::AddressRange; diff --git a/devices/src/pci/coiommu.rs b/devices/src/pci/coiommu.rs index 9461847b86..c5580b8c5f 100644 --- a/devices/src/pci/coiommu.rs +++ b/devices/src/pci/coiommu.rs @@ -80,6 +80,7 @@ use crate::pci::pci_device::Result as PciResult; use crate::pci::PciAddress; use crate::pci::PciDeviceError; use crate::vfio::VfioContainer; +use crate::Suspendable; use crate::UnpinRequest; use crate::UnpinResponse; @@ -1675,3 +1676,5 @@ impl Drop for CoIommuDev { } } } + +impl Suspendable for CoIommuDev {} diff --git a/devices/src/pci/pci_device.rs b/devices/src/pci/pci_device.rs index e639993164..fff129bdf8 100644 --- a/devices/src/pci/pci_device.rs +++ b/devices/src/pci/pci_device.rs @@ -44,6 +44,7 @@ use crate::BusAccessInfo; use crate::BusDevice; use crate::DeviceId; use crate::IrqLevelEvent; +use crate::Suspendable; #[sorted] #[derive(Error, Debug)] @@ -307,7 +308,7 @@ pub enum PreferredIrq { Fixed { pin: PciInterruptPin, gsi: u32 }, } -pub trait PciDevice: Send { +pub trait PciDevice: Send + Suspendable { /// Returns a label suitable for debug output. fn debug_label(&self) -> String; @@ -697,6 +698,24 @@ impl PciDevice for Box { } } +impl Suspendable for Box { + fn snapshot(&self) -> anyhow::Result { + (**self).snapshot() + } + + fn restore(&mut self, data: &str) -> anyhow::Result<()> { + (**self).restore(data) + } + + fn sleep(&mut self) -> anyhow::Result<()> { + (**self).sleep() + } + + fn wake(&mut self) -> anyhow::Result<()> { + (**self).wake() + } +} + impl BusDeviceObj for T { fn as_pci_device(&self) -> Option<&dyn PciDevice> { Some(self) @@ -759,6 +778,8 @@ mod tests { } } + impl Suspendable for TestDev {} + #[test] fn config_write_result() { let mut test_dev = TestDev { diff --git a/devices/src/pci/pci_root.rs b/devices/src/pci/pci_root.rs index f80ca807c5..82d1d9abbc 100644 --- a/devices/src/pci/pci_root.rs +++ b/devices/src/pci/pci_root.rs @@ -33,6 +33,7 @@ use crate::BusAccessInfo; use crate::BusDevice; use crate::BusType; use crate::DeviceId; +use crate::Suspendable; // A PciDevice that holds the root hub's configuration. struct PciRootConfiguration { @@ -71,6 +72,8 @@ impl PciDevice for PciRootConfiguration { } } +impl Suspendable for PciRootConfiguration {} + // Command send to pci root worker thread to add/remove device from pci root pub enum PciRootCommand { Add(PciAddress, Arc>), @@ -428,6 +431,8 @@ impl BusDevice for PciConfigIo { } } +impl Suspendable for PciConfigIo {} + /// Emulates PCI memory-mapped configuration access mechanism. pub struct PciConfigMmio { /// PCI root bridge. @@ -493,7 +498,9 @@ impl BusDevice for PciConfigMmio { } } -/// Inspired by PCI configuration space, crosvm provides 2048 dword virtual registers (8KiB in +impl Suspendable for PciConfigMmio {} + +/// Inspired by PCI configuration space, CrosVM provides 2048 dword virtual registers (8KiB in /// total) for each PCI device. The guest can use these registers to exchange device-specific /// information with crosvm. The first 4kB is trapped by crosvm and crosvm supplies these /// register's emulation. The second 4KB is mapped into guest directly as shared memory, so @@ -567,3 +574,5 @@ impl BusDevice for PciVirtualConfigMmio { .virtual_config_space_write(address, register, value) } } + +impl Suspendable for PciVirtualConfigMmio {} diff --git a/devices/src/pci/pcie/pci_bridge.rs b/devices/src/pci/pcie/pci_bridge.rs index fd179e06a3..8303bd35d3 100644 --- a/devices/src/pci/pcie/pci_bridge.rs +++ b/devices/src/pci/pcie/pci_bridge.rs @@ -31,6 +31,7 @@ use crate::pci::PciHeaderType; use crate::pci::PCI_VENDOR_ID_INTEL; use crate::IrqLevelEvent; use crate::PciInterruptPin; +use crate::Suspendable; pub const BR_BUS_NUMBER_REG: usize = 0x6; pub const BR_BUS_SUBORDINATE_OFFSET: usize = 0x2; @@ -504,3 +505,5 @@ impl PciDevice for PciBridge { self.msi_config.lock().destroy() } } + +impl Suspendable for PciBridge {} diff --git a/devices/src/pci/pvpanic.rs b/devices/src/pci/pvpanic.rs index 87526c8b01..71ecb83ed5 100644 --- a/devices/src/pci/pvpanic.rs +++ b/devices/src/pci/pvpanic.rs @@ -36,6 +36,7 @@ use crate::pci::pci_device::Result; use crate::pci::PciAddress; use crate::pci::PciDeviceError; use crate::pci::PCI_VENDOR_ID_REDHAT; +use crate::Suspendable; const PCI_DEVICE_ID_REDHAT_PVPANIC: u16 = 0x0011; const PCI_PVPANIC_REVISION_ID: u8 = 1; @@ -205,6 +206,8 @@ impl PciDevice for PvPanicPciDevice { } } +impl Suspendable for PvPanicPciDevice {} + #[cfg(test)] mod test { use base::Tube; diff --git a/devices/src/pci/stub.rs b/devices/src/pci/stub.rs index 5aa5110557..142b7982c6 100644 --- a/devices/src/pci/stub.rs +++ b/devices/src/pci/stub.rs @@ -28,6 +28,7 @@ use crate::pci::pci_device::PciDevice; use crate::pci::pci_device::Result; use crate::pci::PciAddress; use crate::pci::PciDeviceError; +use crate::Suspendable; #[derive(Serialize, Deserialize)] pub struct StubPciParameters { @@ -136,6 +137,8 @@ impl PciDevice for StubPciDevice { fn write_bar(&mut self, _addr: u64, _data: &[u8]) {} } +impl Suspendable for StubPciDevice {} + #[cfg(test)] mod test { use resources::AddressRange; diff --git a/devices/src/pci/vfio_pci.rs b/devices/src/pci/vfio_pci.rs index bd61e65f2d..cb3dc316ed 100644 --- a/devices/src/pci/vfio_pci.rs +++ b/devices/src/pci/vfio_pci.rs @@ -89,6 +89,7 @@ use crate::vfio::VfioError; use crate::vfio::VfioIrqType; use crate::vfio::VfioPciConfig; use crate::IrqLevelEvent; +use crate::Suspendable; const PCI_VENDOR_ID: u32 = 0x0; const PCI_DEVICE_ID: u32 = 0x2; @@ -2192,6 +2193,8 @@ impl Drop for VfioPciDevice { } } +impl Suspendable for VfioPciDevice {} + #[cfg(test)] mod tests { use resources::AddressRange; diff --git a/devices/src/pflash.rs b/devices/src/pflash.rs index cfe5985806..d04fc74312 100644 --- a/devices/src/pflash.rs +++ b/devices/src/pflash.rs @@ -34,6 +34,7 @@ use crate::pci::CrosvmDeviceId; use crate::BusAccessInfo; use crate::BusDevice; use crate::DeviceId; +use crate::Suspendable; const COMMAND_WRITE_BYTE: u8 = 0x10; const COMMAND_BLOCK_ERASE: u8 = 0x20; @@ -230,6 +231,8 @@ impl BusDevice for Pflash { } } +impl Suspendable for Pflash {} + #[cfg(test)] mod tests { use base::FileReadWriteAtVolatile; diff --git a/devices/src/pit.rs b/devices/src/pit.rs index 26a764947c..4b2439a17e 100644 --- a/devices/src/pit.rs +++ b/devices/src/pit.rs @@ -41,6 +41,7 @@ use crate::pci::CrosvmDeviceId; use crate::BusDevice; use crate::DeviceId; use crate::IrqEdgeEvent; +use crate::Suspendable; // Bitmask for areas of standard (non-ReadBack) Control Word Format. Constant // names are kept the same as Intel PIT data sheet. @@ -380,6 +381,8 @@ impl Pit { } } +impl Suspendable for Pit {} + // Each instance of this represents one of the PIT counters. They are used to // implement one-shot and repeating timer alarms. An 8254 has three counters. struct PitCounter { diff --git a/devices/src/pl030.rs b/devices/src/pl030.rs index 6688beb5fe..d473a21c21 100644 --- a/devices/src/pl030.rs +++ b/devices/src/pl030.rs @@ -13,6 +13,7 @@ use crate::BusAccessInfo; use crate::BusDevice; use crate::DeviceId; use crate::IrqEdgeEvent; +use crate::Suspendable; // Register offsets // Data register @@ -154,6 +155,9 @@ impl BusDevice for Pl030 { *data_array = reg_content.to_ne_bytes(); } } + +impl Suspendable for Pl030 {} + #[cfg(test)] mod tests { use super::*; diff --git a/devices/src/platform/vfio_platform.rs b/devices/src/platform/vfio_platform.rs index 0c09c701f8..5cc61302a2 100644 --- a/devices/src/platform/vfio_platform.rs +++ b/devices/src/platform/vfio_platform.rs @@ -37,6 +37,7 @@ use crate::BusDeviceObj; use crate::DeviceId; use crate::IrqEdgeEvent; use crate::IrqLevelEvent; +use crate::Suspendable; struct MmioInfo { index: u32, @@ -72,6 +73,8 @@ impl BusDevice for VfioPlatformDevice { } } +impl Suspendable for VfioPlatformDevice {} + impl BusDeviceObj for VfioPlatformDevice { fn as_platform_device(&self) -> Option<&VfioPlatformDevice> { Some(self) diff --git a/devices/src/proxy.rs b/devices/src/proxy.rs index cb212d48d0..82c8514f3b 100644 --- a/devices/src/proxy.rs +++ b/devices/src/proxy.rs @@ -27,6 +27,7 @@ use crate::BusDevice; use crate::BusRange; use crate::BusType; use crate::DeviceId; +use crate::Suspendable; /// Errors for proxy devices. #[sorted] @@ -359,6 +360,8 @@ impl BusDevice for ProxyDevice { } } +impl Suspendable for ProxyDevice {} + impl Drop for ProxyDevice { fn drop(&mut self) { self.sync_send(&Command::Shutdown); @@ -420,6 +423,8 @@ mod tests { } } + impl Suspendable for EchoDevice {} + fn new_proxied_echo_device() -> ProxyDevice { let device = EchoDevice::new(); let keep_fds: Vec = Vec::new(); diff --git a/devices/src/serial.rs b/devices/src/serial.rs index 267fb8f2df..e16b756e07 100644 --- a/devices/src/serial.rs +++ b/devices/src/serial.rs @@ -21,6 +21,7 @@ use base::Result; use crate::bus::BusAccessInfo; use crate::pci::CrosvmDeviceId; use crate::serial_device::SerialInput; +use crate::suspendable::Suspendable; use crate::BusDevice; use crate::DeviceId; @@ -399,6 +400,8 @@ impl BusDevice for Serial { } } +impl Suspendable for Serial {} + #[cfg(test)] mod tests { use std::io; diff --git a/devices/src/suspendable.rs b/devices/src/suspendable.rs index 7177cc058a..a562d05f25 100644 --- a/devices/src/suspendable.rs +++ b/devices/src/suspendable.rs @@ -20,7 +20,7 @@ pub enum DeviceState { pub trait Suspendable { /// Save the device state in an image that can be restored. fn snapshot(&self) -> AnyhowResult { - Ok(format!( + Err(anyhow!( "Suspendable::snapshot not implemented for {}", std::any::type_name::() )) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 73d988ab16..f99c3b9e75 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -37,6 +37,7 @@ use crate::usb::xhci::xhci_regs::init_xhci_mmio_space_and_regs; use crate::usb::xhci::xhci_regs::XhciRegs; use crate::utils::FailHandle; use crate::IrqLevelEvent; +use crate::Suspendable; const XHCI_BAR0_SIZE: u64 = 0x10000; @@ -326,3 +327,5 @@ impl PciDevice for XhciController { self.init_when_forked(); } } + +impl Suspendable for XhciController {} diff --git a/devices/src/virtio/virtio_mmio_device.rs b/devices/src/virtio/virtio_mmio_device.rs index b46f84575b..f18d9f4b14 100644 --- a/devices/src/virtio/virtio_mmio_device.rs +++ b/devices/src/virtio/virtio_mmio_device.rs @@ -38,6 +38,7 @@ use crate::BusDevice; use crate::BusDeviceObj; use crate::DeviceId; use crate::IrqEdgeEvent; +use crate::Suspendable; const VIRT_MAGIC: u32 = 0x74726976; /* 'virt' */ const VIRT_VERSION: u8 = 2; @@ -506,3 +507,5 @@ impl BusDevice for VirtioMmioDevice { self.on_device_sandboxed(); } } + +impl Suspendable for VirtioMmioDevice {} diff --git a/devices/src/virtio/virtio_pci_device.rs b/devices/src/virtio/virtio_pci_device.rs index cc034c4e2d..5bd87a2f5c 100644 --- a/devices/src/virtio/virtio_pci_device.rs +++ b/devices/src/virtio/virtio_pci_device.rs @@ -62,6 +62,7 @@ use crate::pci::PciInterruptPin; use crate::pci::PciSubclass; use crate::virtio::ipc_memory_mapper::IpcMemoryMapper; use crate::IrqLevelEvent; +use crate::Suspendable; #[repr(u8)] #[derive(Debug, Copy, Clone, enumn::N)] @@ -933,6 +934,8 @@ impl PciDevice for VirtioPciDevice { } } +impl Suspendable for VirtioPciDevice {} + struct VmRequester { tube: Tube, alloc: Alloc, diff --git a/devices/src/vmwdt.rs b/devices/src/vmwdt.rs index 8859a16856..95dcfde0c1 100644 --- a/devices/src/vmwdt.rs +++ b/devices/src/vmwdt.rs @@ -35,6 +35,7 @@ use crate::pci::CrosvmDeviceId; use crate::BusAccessInfo; use crate::BusDevice; use crate::DeviceId; +use crate::Suspendable; // Registers offsets const VMWDT_REG_STATUS: u32 = 0x00; @@ -339,6 +340,9 @@ impl BusDevice for Vmwdt { } } } + +impl Suspendable for Vmwdt {} + #[cfg(test)] mod tests { use std::thread::sleep;