• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::sync::Arc;
6 
7 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
8 use acpi_tables::sdt::SDT;
9 use anyhow::Result;
10 use base::Error as BaseError;
11 use base::Event;
12 use base::Protection;
13 use base::RawDescriptor;
14 use remain::sorted;
15 use sync::Mutex;
16 use thiserror::Error;
17 use vm_control::VmMemorySource;
18 use vm_memory::GuestAddress;
19 use vm_memory::GuestMemory;
20 
21 use super::*;
22 use crate::pci::MsixStatus;
23 use crate::pci::PciAddress;
24 use crate::pci::PciBarConfiguration;
25 use crate::pci::PciBarIndex;
26 use crate::pci::PciCapability;
27 use crate::virtio::ipc_memory_mapper::IpcMemoryMapper;
28 use crate::Suspendable;
29 
30 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
31 pub enum VirtioTransportType {
32     Pci,
33     Mmio,
34 }
35 
36 #[derive(Clone)]
37 pub struct SharedMemoryRegion {
38     /// The id of the shared memory region. A device may have multiple regions, but each
39     /// must have a unique id. The meaning of a particular region is device-specific.
40     pub id: u8,
41     pub length: u64,
42 }
43 
44 /// Trait for mapping memory into the device's shared memory region.
45 pub trait SharedMemoryMapper: Send {
46     /// Maps the given |source| into the shared memory region at |offset|.
add_mapping(&mut self, source: VmMemorySource, offset: u64, prot: Protection) -> Result<()>47     fn add_mapping(&mut self, source: VmMemorySource, offset: u64, prot: Protection) -> Result<()>;
48 
49     /// Removes the mapping beginning at |offset|.
remove_mapping(&mut self, offset: u64) -> Result<()>50     fn remove_mapping(&mut self, offset: u64) -> Result<()>;
51 
as_raw_descriptor(&self) -> Option<RawDescriptor>52     fn as_raw_descriptor(&self) -> Option<RawDescriptor> {
53         None
54     }
55 }
56 
57 /// Trait for virtio devices to be driven by a virtio transport.
58 ///
59 /// The lifecycle of a virtio device is to be moved to a virtio transport, which will then query the
60 /// device. Once the guest driver has configured the device, `VirtioDevice::activate` will be called
61 /// and all the events, memory, and queues for device operation will be moved into the device.
62 /// Optionally, a virtio device can implement device reset in which it returns said resources and
63 /// resets its internal.
64 pub trait VirtioDevice: Send + Suspendable {
65     /// Returns a label suitable for debug output.
debug_label(&self) -> String66     fn debug_label(&self) -> String {
67         format!("virtio-{}", self.device_type())
68     }
69 
70     /// A vector of device-specific file descriptors that must be kept open
71     /// after jailing. Must be called before the process is jailed.
keep_rds(&self) -> Vec<RawDescriptor>72     fn keep_rds(&self) -> Vec<RawDescriptor>;
73 
74     /// The virtio device type.
device_type(&self) -> DeviceType75     fn device_type(&self) -> DeviceType;
76 
77     /// The maximum size of each queue that this device supports.
queue_max_sizes(&self) -> &[u16]78     fn queue_max_sizes(&self) -> &[u16];
79 
80     /// The number of interrupts used by this device.
num_interrupts(&self) -> usize81     fn num_interrupts(&self) -> usize {
82         self.queue_max_sizes().len()
83     }
84 
85     /// Whether this device supports a virtio-iommu.
supports_iommu(&self) -> bool86     fn supports_iommu(&self) -> bool {
87         false
88     }
89 
90     /// The set of feature bits that this device supports in addition to the base features.
features(&self) -> u6491     fn features(&self) -> u64 {
92         0
93     }
94 
95     /// Acknowledges that this set of features should be enabled.
ack_features(&mut self, value: u64)96     fn ack_features(&mut self, value: u64) {
97         let _ = value;
98     }
99 
100     /// Reads this device configuration space at `offset`.
read_config(&self, offset: u64, data: &mut [u8])101     fn read_config(&self, offset: u64, data: &mut [u8]) {
102         let _ = offset;
103         let _ = data;
104     }
105 
106     /// Writes to this device configuration space at `offset`.
write_config(&mut self, offset: u64, data: &[u8])107     fn write_config(&mut self, offset: u64, data: &[u8]) {
108         let _ = offset;
109         let _ = data;
110     }
111 
112     /// If the device is translated by an IOMMU, called before
113     /// |activate| with the IOMMU's mapper.
set_iommu(&mut self, iommu: &Arc<Mutex<IpcMemoryMapper>>)114     fn set_iommu(&mut self, iommu: &Arc<Mutex<IpcMemoryMapper>>) {
115         let _ = iommu;
116     }
117 
118     /// Activates this device for real usage.
activate( &mut self, mem: GuestMemory, interrupt: Interrupt, queues: Vec<(Queue, Event)>, ) -> Result<()>119     fn activate(
120         &mut self,
121         mem: GuestMemory,
122         interrupt: Interrupt,
123         queues: Vec<(Queue, Event)>,
124     ) -> Result<()>;
125 
126     /// Optionally deactivates this device. If the reset method is
127     /// not able to reset the virtio device, or the virtio device model doesn't
128     /// implement the reset method, a false value is returned to indicate
129     /// the reset is not successful. Otherwise a true value should be returned.
reset(&mut self) -> bool130     fn reset(&mut self) -> bool {
131         false
132     }
133 
134     /// Returns any additional BAR configuration required by the device.
get_device_bars(&mut self, _address: PciAddress) -> Vec<PciBarConfiguration>135     fn get_device_bars(&mut self, _address: PciAddress) -> Vec<PciBarConfiguration> {
136         Vec::new()
137     }
138 
139     /// Returns any additional capabiltiies required by the device.
get_device_caps(&self) -> Vec<Box<dyn PciCapability>>140     fn get_device_caps(&self) -> Vec<Box<dyn PciCapability>> {
141         Vec::new()
142     }
143 
144     /// Invoked when the device is sandboxed.
on_device_sandboxed(&mut self)145     fn on_device_sandboxed(&mut self) {}
146 
control_notify(&self, _behavior: MsixStatus)147     fn control_notify(&self, _behavior: MsixStatus) {}
148 
149     #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
generate_acpi( &mut self, _pci_address: &Option<PciAddress>, sdts: Vec<SDT>, ) -> Option<Vec<SDT>>150     fn generate_acpi(
151         &mut self,
152         _pci_address: &Option<PciAddress>,
153         sdts: Vec<SDT>,
154     ) -> Option<Vec<SDT>> {
155         Some(sdts)
156     }
157 
158     /// Reads from a BAR region mapped in to the device.
159     /// * `addr` - The guest address inside the BAR.
160     /// * `data` - Filled with the data from `addr`.
read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8])161     fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {}
162 
163     /// Writes to a BAR region mapped in to the device.
164     /// * `addr` - The guest address inside the BAR.
165     /// * `data` - The data to write.
write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8])166     fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {}
167 
168     /// Returns the PCI address where the device will be allocated.
169     /// Returns `None` if any address is good for the device.
pci_address(&self) -> Option<PciAddress>170     fn pci_address(&self) -> Option<PciAddress> {
171         None
172     }
173 
174     /// Returns the Virtio transport type: PCI (default for crosvm) or MMIO.
transport_type(&self) -> VirtioTransportType175     fn transport_type(&self) -> VirtioTransportType {
176         VirtioTransportType::Pci
177     }
178 
179     /// Returns the device's shared memory region if present.
get_shared_memory_region(&self) -> Option<SharedMemoryRegion>180     fn get_shared_memory_region(&self) -> Option<SharedMemoryRegion> {
181         None
182     }
183 
184     /// If true, VFIO passthrough devices can access descriptors mapped into
185     /// this region by mapping the corresponding addresses from this device's
186     /// PCI bar into their IO address space with virtio-iommu.
187     ///
188     /// NOTE: Not all vm_control::VmMemorySource types are supported.
expose_shmem_descriptors_with_viommu(&self) -> bool189     fn expose_shmem_descriptors_with_viommu(&self) -> bool {
190         false
191     }
192 
193     /// Provides the trait object used to map files into the device's shared
194     /// memory region.
195     ///
196     /// If `get_shared_memory_region` returns `Some`, then this will be called
197     /// before `activate`.
set_shared_memory_mapper(&mut self, _mapper: Box<dyn SharedMemoryMapper>)198     fn set_shared_memory_mapper(&mut self, _mapper: Box<dyn SharedMemoryMapper>) {}
199 
200     /// Provides the base address of the shared memory region, if one is present. Will
201     /// be called before `activate`.
202     ///
203     /// NOTE: Mappings in shared memory regions should be accessed via offset, rather
204     /// than via raw guest physical address. This function is only provided so
205     /// devices can remain backwards compatible with older drivers.
set_shared_memory_region_base(&mut self, _addr: GuestAddress)206     fn set_shared_memory_region_base(&mut self, _addr: GuestAddress) {}
207 
208     /// Stop the device and return queues and GuestMemory to the underlying bus that the virtio
209     /// device resides on (Pci/Mmio) to preserve their state.
stop(&mut self) -> Result<Option<VirtioDeviceSaved>, Error>210     fn stop(&mut self) -> Result<Option<VirtioDeviceSaved>, Error> {
211         Err(Error::NotImplemented(self.debug_label()))
212     }
213 }
214 
215 #[sorted]
216 #[derive(Error, Debug)]
217 pub enum Error {
218     #[error("thread error: {0}")]
219     InThreadFailure(anyhow::Error),
220     #[error("failed to kill {0} worker thread")]
221     KillEventFailure(BaseError),
222     #[error("Stop is not implemented for: {0}")]
223     NotImplemented(String),
224     #[error("thread ending failed: {0}")]
225     ThreadJoinFailure(String),
226 }
227 
228 pub struct VirtioDeviceSaved {
229     pub queues: Vec<Queue>,
230 }
231