1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2018 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap; 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] 8*bb4ee6a4SAndroid Build Coastguard Worker use acpi_tables::sdt::SDT; 9*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow; 10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result; 11*bb4ee6a4SAndroid Build Coastguard Worker use base::Protection; 12*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor; 13*bb4ee6a4SAndroid Build Coastguard Worker use hypervisor::MemCacheType; 14*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmMemorySource; 15*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress; 16*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory; 17*bb4ee6a4SAndroid Build Coastguard Worker 18*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 19*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::MsixStatus; 20*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciAddress; 21*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciBarConfiguration; 22*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciBarIndex; 23*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciCapability; 24*bb4ee6a4SAndroid Build Coastguard Worker 25*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, PartialEq, Eq)] 26*bb4ee6a4SAndroid Build Coastguard Worker pub enum VirtioTransportType { 27*bb4ee6a4SAndroid Build Coastguard Worker Pci, 28*bb4ee6a4SAndroid Build Coastguard Worker Mmio, 29*bb4ee6a4SAndroid Build Coastguard Worker } 30*bb4ee6a4SAndroid Build Coastguard Worker 31*bb4ee6a4SAndroid Build Coastguard Worker /// Type of Virtio device memory mapping to use. 32*bb4ee6a4SAndroid Build Coastguard Worker pub enum SharedMemoryPrepareType { 33*bb4ee6a4SAndroid Build Coastguard Worker /// On first attempted mapping, the entire SharedMemoryRegion is configured with declared 34*bb4ee6a4SAndroid Build Coastguard Worker /// MemCacheType. 35*bb4ee6a4SAndroid Build Coastguard Worker SingleMappingOnFirst(MemCacheType), 36*bb4ee6a4SAndroid Build Coastguard Worker /// No mapping preparation is performed. each mapping is handled individually 37*bb4ee6a4SAndroid Build Coastguard Worker DynamicPerMapping, 38*bb4ee6a4SAndroid Build Coastguard Worker } 39*bb4ee6a4SAndroid Build Coastguard Worker 40*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone)] 41*bb4ee6a4SAndroid Build Coastguard Worker pub struct SharedMemoryRegion { 42*bb4ee6a4SAndroid Build Coastguard Worker /// The id of the shared memory region. A device may have multiple regions, but each 43*bb4ee6a4SAndroid Build Coastguard Worker /// must have a unique id. The meaning of a particular region is device-specific. 44*bb4ee6a4SAndroid Build Coastguard Worker pub id: u8, 45*bb4ee6a4SAndroid Build Coastguard Worker pub length: u64, 46*bb4ee6a4SAndroid Build Coastguard Worker } 47*bb4ee6a4SAndroid Build Coastguard Worker 48*bb4ee6a4SAndroid Build Coastguard Worker /// Trait for mapping memory into the device's shared memory region. 49*bb4ee6a4SAndroid Build Coastguard Worker pub trait SharedMemoryMapper: Send { 50*bb4ee6a4SAndroid Build Coastguard Worker /// Maps the given |source| into the shared memory region at |offset|. add_mapping( &mut self, source: VmMemorySource, offset: u64, prot: Protection, cache: MemCacheType, ) -> Result<()>51*bb4ee6a4SAndroid Build Coastguard Worker fn add_mapping( 52*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 53*bb4ee6a4SAndroid Build Coastguard Worker source: VmMemorySource, 54*bb4ee6a4SAndroid Build Coastguard Worker offset: u64, 55*bb4ee6a4SAndroid Build Coastguard Worker prot: Protection, 56*bb4ee6a4SAndroid Build Coastguard Worker cache: MemCacheType, 57*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()>; 58*bb4ee6a4SAndroid Build Coastguard Worker 59*bb4ee6a4SAndroid Build Coastguard Worker /// Removes the mapping beginning at |offset|. remove_mapping(&mut self, offset: u64) -> Result<()>60*bb4ee6a4SAndroid Build Coastguard Worker fn remove_mapping(&mut self, offset: u64) -> Result<()>; 61*bb4ee6a4SAndroid Build Coastguard Worker as_raw_descriptor(&self) -> Option<RawDescriptor>62*bb4ee6a4SAndroid Build Coastguard Worker fn as_raw_descriptor(&self) -> Option<RawDescriptor> { 63*bb4ee6a4SAndroid Build Coastguard Worker None 64*bb4ee6a4SAndroid Build Coastguard Worker } 65*bb4ee6a4SAndroid Build Coastguard Worker } 66*bb4ee6a4SAndroid Build Coastguard Worker 67*bb4ee6a4SAndroid Build Coastguard Worker /// Trait for virtio devices to be driven by a virtio transport. 68*bb4ee6a4SAndroid Build Coastguard Worker /// 69*bb4ee6a4SAndroid Build Coastguard Worker /// The lifecycle of a virtio device is to be moved to a virtio transport, which will then query the 70*bb4ee6a4SAndroid Build Coastguard Worker /// device. Once the guest driver has configured the device, `VirtioDevice::activate` will be called 71*bb4ee6a4SAndroid Build Coastguard Worker /// and all the events, memory, and queues for device operation will be moved into the device. 72*bb4ee6a4SAndroid Build Coastguard Worker /// Optionally, a virtio device can implement device reset in which it returns said resources and 73*bb4ee6a4SAndroid Build Coastguard Worker /// resets its internal. 74*bb4ee6a4SAndroid Build Coastguard Worker /// 75*bb4ee6a4SAndroid Build Coastguard Worker /// Virtio device state machine 76*bb4ee6a4SAndroid Build Coastguard Worker /// ```none 77*bb4ee6a4SAndroid Build Coastguard Worker /// restore (inactive) 78*bb4ee6a4SAndroid Build Coastguard Worker /// ---------------------------------------------------- 79*bb4ee6a4SAndroid Build Coastguard Worker /// | | 80*bb4ee6a4SAndroid Build Coastguard Worker /// | V 81*bb4ee6a4SAndroid Build Coastguard Worker /// | ------------ -------------- 82*bb4ee6a4SAndroid Build Coastguard Worker /// ------------- restore(active) | asleep | | asleep | // States in this row 83*bb4ee6a4SAndroid Build Coastguard Worker /// |asleep(new)|---------------> | (active) | | (inactive) | // can be snapshotted 84*bb4ee6a4SAndroid Build Coastguard Worker /// ------------- ------------ -------------- 85*bb4ee6a4SAndroid Build Coastguard Worker /// ^ | ^ | ^ | 86*bb4ee6a4SAndroid Build Coastguard Worker /// | | | | | | 87*bb4ee6a4SAndroid Build Coastguard Worker /// sleep wake sleep wake sleep wake 88*bb4ee6a4SAndroid Build Coastguard Worker /// | | | | | | 89*bb4ee6a4SAndroid Build Coastguard Worker /// | V | V | V 90*bb4ee6a4SAndroid Build Coastguard Worker /// ------------ activate ---------- reset ------------ 91*bb4ee6a4SAndroid Build Coastguard Worker /// | new | ---------------> | active | ------> | inactive | 92*bb4ee6a4SAndroid Build Coastguard Worker /// ------------ ---------- <------ ------------ 93*bb4ee6a4SAndroid Build Coastguard Worker /// activate 94*bb4ee6a4SAndroid Build Coastguard Worker /// ``` 95*bb4ee6a4SAndroid Build Coastguard Worker pub trait VirtioDevice: Send { 96*bb4ee6a4SAndroid Build Coastguard Worker /// Returns a label suitable for debug output. debug_label(&self) -> String97*bb4ee6a4SAndroid Build Coastguard Worker fn debug_label(&self) -> String { 98*bb4ee6a4SAndroid Build Coastguard Worker format!("virtio-{}", self.device_type()) 99*bb4ee6a4SAndroid Build Coastguard Worker } 100*bb4ee6a4SAndroid Build Coastguard Worker 101*bb4ee6a4SAndroid Build Coastguard Worker /// A vector of device-specific file descriptors that must be kept open 102*bb4ee6a4SAndroid Build Coastguard Worker /// after jailing. Must be called before the process is jailed. keep_rds(&self) -> Vec<RawDescriptor>103*bb4ee6a4SAndroid Build Coastguard Worker fn keep_rds(&self) -> Vec<RawDescriptor>; 104*bb4ee6a4SAndroid Build Coastguard Worker 105*bb4ee6a4SAndroid Build Coastguard Worker /// The virtio device type. device_type(&self) -> DeviceType106*bb4ee6a4SAndroid Build Coastguard Worker fn device_type(&self) -> DeviceType; 107*bb4ee6a4SAndroid Build Coastguard Worker 108*bb4ee6a4SAndroid Build Coastguard Worker /// The maximum size of each queue that this device supports. queue_max_sizes(&self) -> &[u16]109*bb4ee6a4SAndroid Build Coastguard Worker fn queue_max_sizes(&self) -> &[u16]; 110*bb4ee6a4SAndroid Build Coastguard Worker 111*bb4ee6a4SAndroid Build Coastguard Worker /// The number of interrupts used by this device. num_interrupts(&self) -> usize112*bb4ee6a4SAndroid Build Coastguard Worker fn num_interrupts(&self) -> usize { 113*bb4ee6a4SAndroid Build Coastguard Worker self.queue_max_sizes().len() 114*bb4ee6a4SAndroid Build Coastguard Worker } 115*bb4ee6a4SAndroid Build Coastguard Worker 116*bb4ee6a4SAndroid Build Coastguard Worker /// The set of feature bits that this device supports in addition to the base features. features(&self) -> u64117*bb4ee6a4SAndroid Build Coastguard Worker fn features(&self) -> u64 { 118*bb4ee6a4SAndroid Build Coastguard Worker 0 119*bb4ee6a4SAndroid Build Coastguard Worker } 120*bb4ee6a4SAndroid Build Coastguard Worker 121*bb4ee6a4SAndroid Build Coastguard Worker /// Acknowledges that this set of features should be enabled. ack_features(&mut self, value: u64)122*bb4ee6a4SAndroid Build Coastguard Worker fn ack_features(&mut self, value: u64) { 123*bb4ee6a4SAndroid Build Coastguard Worker let _ = value; 124*bb4ee6a4SAndroid Build Coastguard Worker } 125*bb4ee6a4SAndroid Build Coastguard Worker 126*bb4ee6a4SAndroid Build Coastguard Worker /// Reads this device configuration space at `offset`. read_config(&self, offset: u64, data: &mut [u8])127*bb4ee6a4SAndroid Build Coastguard Worker fn read_config(&self, offset: u64, data: &mut [u8]) { 128*bb4ee6a4SAndroid Build Coastguard Worker let _ = offset; 129*bb4ee6a4SAndroid Build Coastguard Worker let _ = data; 130*bb4ee6a4SAndroid Build Coastguard Worker } 131*bb4ee6a4SAndroid Build Coastguard Worker 132*bb4ee6a4SAndroid Build Coastguard Worker /// Writes to this device configuration space at `offset`. write_config(&mut self, offset: u64, data: &[u8])133*bb4ee6a4SAndroid Build Coastguard Worker fn write_config(&mut self, offset: u64, data: &[u8]) { 134*bb4ee6a4SAndroid Build Coastguard Worker let _ = offset; 135*bb4ee6a4SAndroid Build Coastguard Worker let _ = data; 136*bb4ee6a4SAndroid Build Coastguard Worker } 137*bb4ee6a4SAndroid Build Coastguard Worker 138*bb4ee6a4SAndroid Build Coastguard Worker /// Activates this device for real usage. activate( &mut self, mem: GuestMemory, interrupt: Interrupt, queues: BTreeMap<usize, Queue>, ) -> Result<()>139*bb4ee6a4SAndroid Build Coastguard Worker fn activate( 140*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 141*bb4ee6a4SAndroid Build Coastguard Worker mem: GuestMemory, 142*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt, 143*bb4ee6a4SAndroid Build Coastguard Worker queues: BTreeMap<usize, Queue>, 144*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()>; 145*bb4ee6a4SAndroid Build Coastguard Worker 146*bb4ee6a4SAndroid Build Coastguard Worker /// Optionally deactivates this device. If the reset method is 147*bb4ee6a4SAndroid Build Coastguard Worker /// not able to reset the virtio device, or the virtio device model doesn't 148*bb4ee6a4SAndroid Build Coastguard Worker /// implement the reset method, an `Err` value is returned to indicate 149*bb4ee6a4SAndroid Build Coastguard Worker /// the reset is not successful. Otherwise `Ok(())` should be returned. reset(&mut self) -> Result<()>150*bb4ee6a4SAndroid Build Coastguard Worker fn reset(&mut self) -> Result<()> { 151*bb4ee6a4SAndroid Build Coastguard Worker Err(anyhow!("reset not implemented for {}", self.debug_label())) 152*bb4ee6a4SAndroid Build Coastguard Worker } 153*bb4ee6a4SAndroid Build Coastguard Worker 154*bb4ee6a4SAndroid Build Coastguard Worker /// Returns any additional BAR configuration required by the device. get_device_bars(&mut self, _address: PciAddress) -> Vec<PciBarConfiguration>155*bb4ee6a4SAndroid Build Coastguard Worker fn get_device_bars(&mut self, _address: PciAddress) -> Vec<PciBarConfiguration> { 156*bb4ee6a4SAndroid Build Coastguard Worker Vec::new() 157*bb4ee6a4SAndroid Build Coastguard Worker } 158*bb4ee6a4SAndroid Build Coastguard Worker 159*bb4ee6a4SAndroid Build Coastguard Worker /// Returns any additional capabiltiies required by the device. get_device_caps(&self) -> Vec<Box<dyn PciCapability>>160*bb4ee6a4SAndroid Build Coastguard Worker fn get_device_caps(&self) -> Vec<Box<dyn PciCapability>> { 161*bb4ee6a4SAndroid Build Coastguard Worker Vec::new() 162*bb4ee6a4SAndroid Build Coastguard Worker } 163*bb4ee6a4SAndroid Build Coastguard Worker 164*bb4ee6a4SAndroid Build Coastguard Worker /// Invoked when the device is sandboxed. on_device_sandboxed(&mut self)165*bb4ee6a4SAndroid Build Coastguard Worker fn on_device_sandboxed(&mut self) {} 166*bb4ee6a4SAndroid Build Coastguard Worker control_notify(&self, _behavior: MsixStatus)167*bb4ee6a4SAndroid Build Coastguard Worker fn control_notify(&self, _behavior: MsixStatus) {} 168*bb4ee6a4SAndroid Build Coastguard Worker 169*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")] generate_acpi( &mut self, _pci_address: &Option<PciAddress>, sdts: Vec<SDT>, ) -> Option<Vec<SDT>>170*bb4ee6a4SAndroid Build Coastguard Worker fn generate_acpi( 171*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 172*bb4ee6a4SAndroid Build Coastguard Worker _pci_address: &Option<PciAddress>, 173*bb4ee6a4SAndroid Build Coastguard Worker sdts: Vec<SDT>, 174*bb4ee6a4SAndroid Build Coastguard Worker ) -> Option<Vec<SDT>> { 175*bb4ee6a4SAndroid Build Coastguard Worker Some(sdts) 176*bb4ee6a4SAndroid Build Coastguard Worker } 177*bb4ee6a4SAndroid Build Coastguard Worker 178*bb4ee6a4SAndroid Build Coastguard Worker /// Reads from a BAR region mapped in to the device. 179*bb4ee6a4SAndroid Build Coastguard Worker /// * `addr` - The guest address inside the BAR. 180*bb4ee6a4SAndroid Build Coastguard Worker /// * `data` - Filled with the data from `addr`. read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8])181*bb4ee6a4SAndroid Build Coastguard Worker fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {} 182*bb4ee6a4SAndroid Build Coastguard Worker 183*bb4ee6a4SAndroid Build Coastguard Worker /// Writes to a BAR region mapped in to the device. 184*bb4ee6a4SAndroid Build Coastguard Worker /// * `addr` - The guest address inside the BAR. 185*bb4ee6a4SAndroid Build Coastguard Worker /// * `data` - The data to write. write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8])186*bb4ee6a4SAndroid Build Coastguard Worker fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {} 187*bb4ee6a4SAndroid Build Coastguard Worker 188*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the PCI address where the device will be allocated. 189*bb4ee6a4SAndroid Build Coastguard Worker /// Returns `None` if any address is good for the device. pci_address(&self) -> Option<PciAddress>190*bb4ee6a4SAndroid Build Coastguard Worker fn pci_address(&self) -> Option<PciAddress> { 191*bb4ee6a4SAndroid Build Coastguard Worker None 192*bb4ee6a4SAndroid Build Coastguard Worker } 193*bb4ee6a4SAndroid Build Coastguard Worker 194*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the Virtio transport type: PCI (default for crosvm) or MMIO. transport_type(&self) -> VirtioTransportType195*bb4ee6a4SAndroid Build Coastguard Worker fn transport_type(&self) -> VirtioTransportType { 196*bb4ee6a4SAndroid Build Coastguard Worker VirtioTransportType::Pci 197*bb4ee6a4SAndroid Build Coastguard Worker } 198*bb4ee6a4SAndroid Build Coastguard Worker 199*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the device's shared memory region if present. get_shared_memory_region(&self) -> Option<SharedMemoryRegion>200*bb4ee6a4SAndroid Build Coastguard Worker fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> { 201*bb4ee6a4SAndroid Build Coastguard Worker None 202*bb4ee6a4SAndroid Build Coastguard Worker } 203*bb4ee6a4SAndroid Build Coastguard Worker 204*bb4ee6a4SAndroid Build Coastguard Worker /// If true, VFIO passthrough devices can access descriptors mapped into 205*bb4ee6a4SAndroid Build Coastguard Worker /// this region by mapping the corresponding addresses from this device's 206*bb4ee6a4SAndroid Build Coastguard Worker /// PCI bar into their IO address space with virtio-iommu. 207*bb4ee6a4SAndroid Build Coastguard Worker /// 208*bb4ee6a4SAndroid Build Coastguard Worker /// NOTE: Not all vm_control::VmMemorySource types are supported. 209*bb4ee6a4SAndroid Build Coastguard Worker /// NOTE: Not yet compatible with PrepareSharedMemoryRegion (aka fixed mapping). expose_shmem_descriptors_with_viommu(&self) -> bool210*bb4ee6a4SAndroid Build Coastguard Worker fn expose_shmem_descriptors_with_viommu(&self) -> bool { 211*bb4ee6a4SAndroid Build Coastguard Worker false 212*bb4ee6a4SAndroid Build Coastguard Worker } 213*bb4ee6a4SAndroid Build Coastguard Worker 214*bb4ee6a4SAndroid Build Coastguard Worker /// Provides the trait object used to map files into the device's shared 215*bb4ee6a4SAndroid Build Coastguard Worker /// memory region. 216*bb4ee6a4SAndroid Build Coastguard Worker /// 217*bb4ee6a4SAndroid Build Coastguard Worker /// If `get_shared_memory_region` returns `Some`, then this will be called 218*bb4ee6a4SAndroid Build Coastguard Worker /// before `activate`. set_shared_memory_mapper(&mut self, _mapper: Box<dyn SharedMemoryMapper>)219*bb4ee6a4SAndroid Build Coastguard Worker fn set_shared_memory_mapper(&mut self, _mapper: Box<dyn SharedMemoryMapper>) {} 220*bb4ee6a4SAndroid Build Coastguard Worker 221*bb4ee6a4SAndroid Build Coastguard Worker /// Provides the base address of the shared memory region, if one is present. Will 222*bb4ee6a4SAndroid Build Coastguard Worker /// be called before `activate`. 223*bb4ee6a4SAndroid Build Coastguard Worker /// 224*bb4ee6a4SAndroid Build Coastguard Worker /// NOTE: Mappings in shared memory regions should be accessed via offset, rather 225*bb4ee6a4SAndroid Build Coastguard Worker /// than via raw guest physical address. This function is only provided so 226*bb4ee6a4SAndroid Build Coastguard Worker /// devices can remain backwards compatible with older drivers. set_shared_memory_region_base(&mut self, _addr: GuestAddress)227*bb4ee6a4SAndroid Build Coastguard Worker fn set_shared_memory_region_base(&mut self, _addr: GuestAddress) {} 228*bb4ee6a4SAndroid Build Coastguard Worker 229*bb4ee6a4SAndroid Build Coastguard Worker /// Queries the implementation whether a single prepared hypervisor memory mapping with explicit 230*bb4ee6a4SAndroid Build Coastguard Worker /// caching type should be setup lazily on first mapping request, or whether to dynamically 231*bb4ee6a4SAndroid Build Coastguard Worker /// setup a hypervisor mapping with every request's caching type. get_shared_memory_prepare_type(&mut self) -> SharedMemoryPrepareType232*bb4ee6a4SAndroid Build Coastguard Worker fn get_shared_memory_prepare_type(&mut self) -> SharedMemoryPrepareType { 233*bb4ee6a4SAndroid Build Coastguard Worker // default to lazy-prepare of a single memslot with explicit caching type 234*bb4ee6a4SAndroid Build Coastguard Worker SharedMemoryPrepareType::SingleMappingOnFirst(MemCacheType::CacheCoherent) 235*bb4ee6a4SAndroid Build Coastguard Worker } 236*bb4ee6a4SAndroid Build Coastguard Worker 237*bb4ee6a4SAndroid Build Coastguard Worker /// Pause all processing. 238*bb4ee6a4SAndroid Build Coastguard Worker /// 239*bb4ee6a4SAndroid Build Coastguard Worker /// Gives up the queues so that a higher layer can potentially snapshot them. The 240*bb4ee6a4SAndroid Build Coastguard Worker /// implementations should also drop the `Interrupt` and queues `Event`s that were given along 241*bb4ee6a4SAndroid Build Coastguard Worker /// with the queues originally. 242*bb4ee6a4SAndroid Build Coastguard Worker /// 243*bb4ee6a4SAndroid Build Coastguard Worker /// Unlike `Suspendable::sleep`, this is not idempotent. Attempting to sleep while already 244*bb4ee6a4SAndroid Build Coastguard Worker /// asleep is an error. virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>245*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> { 246*bb4ee6a4SAndroid Build Coastguard Worker anyhow::bail!("virtio_sleep not implemented for {}", self.debug_label()); 247*bb4ee6a4SAndroid Build Coastguard Worker } 248*bb4ee6a4SAndroid Build Coastguard Worker 249*bb4ee6a4SAndroid Build Coastguard Worker /// Resume all processing. 250*bb4ee6a4SAndroid Build Coastguard Worker /// 251*bb4ee6a4SAndroid Build Coastguard Worker /// If the device's queues are active, then the queues and associated data will is included. 252*bb4ee6a4SAndroid Build Coastguard Worker /// 253*bb4ee6a4SAndroid Build Coastguard Worker /// Unlike `Suspendable::wake`, this is not idempotent. Attempting to wake while already awake 254*bb4ee6a4SAndroid Build Coastguard Worker /// is an error. virtio_wake( &mut self, _queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>255*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_wake( 256*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 257*bb4ee6a4SAndroid Build Coastguard Worker _queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, 258*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> { 259*bb4ee6a4SAndroid Build Coastguard Worker anyhow::bail!("virtio_wake not implemented for {}", self.debug_label()); 260*bb4ee6a4SAndroid Build Coastguard Worker } 261*bb4ee6a4SAndroid Build Coastguard Worker 262*bb4ee6a4SAndroid Build Coastguard Worker /// Snapshot current state. Device must be asleep. virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value>263*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value> { 264*bb4ee6a4SAndroid Build Coastguard Worker anyhow::bail!("virtio_snapshot not implemented for {}", self.debug_label()); 265*bb4ee6a4SAndroid Build Coastguard Worker } 266*bb4ee6a4SAndroid Build Coastguard Worker 267*bb4ee6a4SAndroid Build Coastguard Worker /// Restore device state from a snapshot. 268*bb4ee6a4SAndroid Build Coastguard Worker /// TODO(b/280607404): Vhost user will need fds passed to the device process. virtio_restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()>269*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()> { 270*bb4ee6a4SAndroid Build Coastguard Worker anyhow::bail!("virtio_restore not implemented for {}", self.debug_label()); 271*bb4ee6a4SAndroid Build Coastguard Worker } 272*bb4ee6a4SAndroid Build Coastguard Worker 273*bb4ee6a4SAndroid Build Coastguard Worker // Returns a tuple consisting of the non-arch specific part of the OpenFirmware path, 274*bb4ee6a4SAndroid Build Coastguard Worker // represented as bytes, and the boot index of a device. The non-arch specific part of path for 275*bb4ee6a4SAndroid Build Coastguard Worker // a virtio-blk device, for example, would consist of everything after the first '/' below: 276*bb4ee6a4SAndroid Build Coastguard Worker // pci@i0cf8/scsi@6[,3]/disk@0,0 277*bb4ee6a4SAndroid Build Coastguard Worker // ^ ^ ^ ^ ^ 278*bb4ee6a4SAndroid Build Coastguard Worker // | | | fixed 279*bb4ee6a4SAndroid Build Coastguard Worker // | | (PCI function related to disk (optional)) 280*bb4ee6a4SAndroid Build Coastguard Worker // (x86 specf (PCI slot holding disk) 281*bb4ee6a4SAndroid Build Coastguard Worker // root at sys 282*bb4ee6a4SAndroid Build Coastguard Worker // bus port) bootorder_fw_cfg(&self, _pci_address: u8) -> Option<(Vec<u8>, usize)>283*bb4ee6a4SAndroid Build Coastguard Worker fn bootorder_fw_cfg(&self, _pci_address: u8) -> Option<(Vec<u8>, usize)> { 284*bb4ee6a4SAndroid Build Coastguard Worker None 285*bb4ee6a4SAndroid Build Coastguard Worker } 286*bb4ee6a4SAndroid Build Coastguard Worker } 287*bb4ee6a4SAndroid Build Coastguard Worker 288*bb4ee6a4SAndroid Build Coastguard Worker // General tests that should pass on all suspendables. 289*bb4ee6a4SAndroid Build Coastguard Worker // Do implement device-specific tests to validate the functionality of the device. 290*bb4ee6a4SAndroid Build Coastguard Worker // Those tests are not a replacement for regular tests. Only an extension specific to the trait's 291*bb4ee6a4SAndroid Build Coastguard Worker // basic functionality. 292*bb4ee6a4SAndroid Build Coastguard Worker /// `name` is the name of the test grouping. Can be anything unique within the same crate. 293*bb4ee6a4SAndroid Build Coastguard Worker /// `dev` is a block that returns a created virtio device. 294*bb4ee6a4SAndroid Build Coastguard Worker /// ``num_queues` is the number of queues to be created. 295*bb4ee6a4SAndroid Build Coastguard Worker /// `modfun` is the function name of the function that would modify the device. The function call 296*bb4ee6a4SAndroid Build Coastguard Worker /// should modify the device so that a snapshot taken after the function call would be different 297*bb4ee6a4SAndroid Build Coastguard Worker /// from a snapshot taken before the function call. 298*bb4ee6a4SAndroid Build Coastguard Worker #[macro_export] 299*bb4ee6a4SAndroid Build Coastguard Worker macro_rules! suspendable_virtio_tests { 300*bb4ee6a4SAndroid Build Coastguard Worker ($name:ident, $dev: expr, $num_queues:literal, $modfun:expr) => { 301*bb4ee6a4SAndroid Build Coastguard Worker mod $name { 302*bb4ee6a4SAndroid Build Coastguard Worker use $crate::virtio::QueueConfig; 303*bb4ee6a4SAndroid Build Coastguard Worker 304*bb4ee6a4SAndroid Build Coastguard Worker use super::*; 305*bb4ee6a4SAndroid Build Coastguard Worker 306*bb4ee6a4SAndroid Build Coastguard Worker fn memory() -> GuestMemory { 307*bb4ee6a4SAndroid Build Coastguard Worker GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)]) 308*bb4ee6a4SAndroid Build Coastguard Worker .expect("Creating guest memory failed.") 309*bb4ee6a4SAndroid Build Coastguard Worker } 310*bb4ee6a4SAndroid Build Coastguard Worker 311*bb4ee6a4SAndroid Build Coastguard Worker fn interrupt() -> Interrupt { 312*bb4ee6a4SAndroid Build Coastguard Worker Interrupt::new_for_test() 313*bb4ee6a4SAndroid Build Coastguard Worker } 314*bb4ee6a4SAndroid Build Coastguard Worker 315*bb4ee6a4SAndroid Build Coastguard Worker fn create_queues( 316*bb4ee6a4SAndroid Build Coastguard Worker num_queues: usize, 317*bb4ee6a4SAndroid Build Coastguard Worker queue_size: u16, 318*bb4ee6a4SAndroid Build Coastguard Worker mem: &GuestMemory, 319*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt, 320*bb4ee6a4SAndroid Build Coastguard Worker ) -> BTreeMap<usize, Queue> { 321*bb4ee6a4SAndroid Build Coastguard Worker let mut queues = BTreeMap::new(); 322*bb4ee6a4SAndroid Build Coastguard Worker for i in 0..num_queues { 323*bb4ee6a4SAndroid Build Coastguard Worker // activate with queues of an arbitrary size. 324*bb4ee6a4SAndroid Build Coastguard Worker let mut queue = QueueConfig::new(queue_size, 0); 325*bb4ee6a4SAndroid Build Coastguard Worker queue.set_ready(true); 326*bb4ee6a4SAndroid Build Coastguard Worker let queue = queue 327*bb4ee6a4SAndroid Build Coastguard Worker .activate(mem, base::Event::new().unwrap(), interrupt.clone()) 328*bb4ee6a4SAndroid Build Coastguard Worker .expect("QueueConfig::activate"); 329*bb4ee6a4SAndroid Build Coastguard Worker queues.insert(i, queue); 330*bb4ee6a4SAndroid Build Coastguard Worker } 331*bb4ee6a4SAndroid Build Coastguard Worker queues 332*bb4ee6a4SAndroid Build Coastguard Worker } 333*bb4ee6a4SAndroid Build Coastguard Worker 334*bb4ee6a4SAndroid Build Coastguard Worker #[test] 335*bb4ee6a4SAndroid Build Coastguard Worker fn test_unactivated_sleep_snapshot_wake() { 336*bb4ee6a4SAndroid Build Coastguard Worker let (_ctx, mut device) = $dev(); 337*bb4ee6a4SAndroid Build Coastguard Worker let sleep_result = device.virtio_sleep().expect("failed to sleep"); 338*bb4ee6a4SAndroid Build Coastguard Worker assert!(sleep_result.is_none()); 339*bb4ee6a4SAndroid Build Coastguard Worker device.virtio_snapshot().expect("failed to snapshot"); 340*bb4ee6a4SAndroid Build Coastguard Worker device.virtio_wake(None).expect("failed to wake"); 341*bb4ee6a4SAndroid Build Coastguard Worker } 342*bb4ee6a4SAndroid Build Coastguard Worker 343*bb4ee6a4SAndroid Build Coastguard Worker #[test] 344*bb4ee6a4SAndroid Build Coastguard Worker fn test_sleep_snapshot_wake() { 345*bb4ee6a4SAndroid Build Coastguard Worker let (_ctx, mut device) = $dev(); 346*bb4ee6a4SAndroid Build Coastguard Worker let mem = memory(); 347*bb4ee6a4SAndroid Build Coastguard Worker let interrupt = interrupt(); 348*bb4ee6a4SAndroid Build Coastguard Worker let queues = create_queues( 349*bb4ee6a4SAndroid Build Coastguard Worker $num_queues, 350*bb4ee6a4SAndroid Build Coastguard Worker device 351*bb4ee6a4SAndroid Build Coastguard Worker .queue_max_sizes() 352*bb4ee6a4SAndroid Build Coastguard Worker .first() 353*bb4ee6a4SAndroid Build Coastguard Worker .cloned() 354*bb4ee6a4SAndroid Build Coastguard Worker .expect("missing queue size"), 355*bb4ee6a4SAndroid Build Coastguard Worker &mem, 356*bb4ee6a4SAndroid Build Coastguard Worker interrupt.clone(), 357*bb4ee6a4SAndroid Build Coastguard Worker ); 358*bb4ee6a4SAndroid Build Coastguard Worker device 359*bb4ee6a4SAndroid Build Coastguard Worker .activate(mem.clone(), interrupt.clone(), queues) 360*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to activate"); 361*bb4ee6a4SAndroid Build Coastguard Worker let sleep_result = device 362*bb4ee6a4SAndroid Build Coastguard Worker .virtio_sleep() 363*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to sleep") 364*bb4ee6a4SAndroid Build Coastguard Worker .expect("missing queues while sleeping"); 365*bb4ee6a4SAndroid Build Coastguard Worker device.virtio_snapshot().expect("failed to snapshot"); 366*bb4ee6a4SAndroid Build Coastguard Worker device 367*bb4ee6a4SAndroid Build Coastguard Worker .virtio_wake(Some((mem.clone(), interrupt.clone(), sleep_result))) 368*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to wake"); 369*bb4ee6a4SAndroid Build Coastguard Worker } 370*bb4ee6a4SAndroid Build Coastguard Worker 371*bb4ee6a4SAndroid Build Coastguard Worker #[test] 372*bb4ee6a4SAndroid Build Coastguard Worker fn test_suspend_mod_restore() { 373*bb4ee6a4SAndroid Build Coastguard Worker let (mut context, mut device) = $dev(); 374*bb4ee6a4SAndroid Build Coastguard Worker let mem = memory(); 375*bb4ee6a4SAndroid Build Coastguard Worker let interrupt = interrupt(); 376*bb4ee6a4SAndroid Build Coastguard Worker let queues = create_queues( 377*bb4ee6a4SAndroid Build Coastguard Worker $num_queues, 378*bb4ee6a4SAndroid Build Coastguard Worker device 379*bb4ee6a4SAndroid Build Coastguard Worker .queue_max_sizes() 380*bb4ee6a4SAndroid Build Coastguard Worker .first() 381*bb4ee6a4SAndroid Build Coastguard Worker .cloned() 382*bb4ee6a4SAndroid Build Coastguard Worker .expect("missing queue size"), 383*bb4ee6a4SAndroid Build Coastguard Worker &mem, 384*bb4ee6a4SAndroid Build Coastguard Worker interrupt.clone(), 385*bb4ee6a4SAndroid Build Coastguard Worker ); 386*bb4ee6a4SAndroid Build Coastguard Worker device 387*bb4ee6a4SAndroid Build Coastguard Worker .activate(mem.clone(), interrupt.clone(), queues) 388*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to activate"); 389*bb4ee6a4SAndroid Build Coastguard Worker let sleep_result = device 390*bb4ee6a4SAndroid Build Coastguard Worker .virtio_sleep() 391*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to sleep") 392*bb4ee6a4SAndroid Build Coastguard Worker .expect("missing queues while sleeping"); 393*bb4ee6a4SAndroid Build Coastguard Worker // Modify device before snapshotting. 394*bb4ee6a4SAndroid Build Coastguard Worker $modfun(&mut context, &mut device); 395*bb4ee6a4SAndroid Build Coastguard Worker let snap = device 396*bb4ee6a4SAndroid Build Coastguard Worker .virtio_snapshot() 397*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to take initial snapshot"); 398*bb4ee6a4SAndroid Build Coastguard Worker device 399*bb4ee6a4SAndroid Build Coastguard Worker .virtio_wake(Some((mem.clone(), interrupt.clone(), sleep_result))) 400*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to wake"); 401*bb4ee6a4SAndroid Build Coastguard Worker 402*bb4ee6a4SAndroid Build Coastguard Worker // Create a new device to restore the previously taken snapshot 403*bb4ee6a4SAndroid Build Coastguard Worker let (_ctx2, mut device) = $dev(); 404*bb4ee6a4SAndroid Build Coastguard Worker // Sleep the device before restore 405*bb4ee6a4SAndroid Build Coastguard Worker assert!(device.virtio_sleep().expect("failed to sleep").is_none()); 406*bb4ee6a4SAndroid Build Coastguard Worker device 407*bb4ee6a4SAndroid Build Coastguard Worker .virtio_restore(snap.clone()) 408*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to restore"); 409*bb4ee6a4SAndroid Build Coastguard Worker let snap2 = device 410*bb4ee6a4SAndroid Build Coastguard Worker .virtio_snapshot() 411*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to take snapshot after mod"); 412*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(snap, snap2); 413*bb4ee6a4SAndroid Build Coastguard Worker } 414*bb4ee6a4SAndroid Build Coastguard Worker } 415*bb4ee6a4SAndroid Build Coastguard Worker }; 416*bb4ee6a4SAndroid Build Coastguard Worker } 417