xref: /aosp_15_r20/external/crosvm/devices/src/virtio/virtio_device.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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