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