1 //! VirtIO transports. 2 3 #[cfg(test)] 4 pub mod fake; 5 pub mod mmio; 6 pub mod pci; 7 mod some; 8 #[cfg(target_arch = "x86_64")] 9 pub mod x86_64; 10 11 use crate::{PhysAddr, Result, PAGE_SIZE}; 12 use bitflags::{bitflags, Flags}; 13 use core::{fmt::Debug, ops::BitAnd}; 14 use log::debug; 15 pub use some::SomeTransport; 16 use zerocopy::{FromBytes, Immutable, IntoBytes}; 17 18 /// A VirtIO device-side transport layer. 19 pub trait DeviceTransport { 20 /// Gets the client VM ID get_client_id(&self) -> u1621 fn get_client_id(&self) -> u16; 22 23 /// Gets the max size of the given queue. max_queue_size(&mut self, queue: u16) -> u3224 fn max_queue_size(&mut self, queue: u16) -> u32; 25 26 /// Returns whether the transport requires queues to use the legacy layout. 27 /// 28 /// Ref: 2.6.2 Legacy Interfaces: A Note on Virtqueue Layout requires_legacy_layout(&self) -> bool29 fn requires_legacy_layout(&self) -> bool; 30 31 /// Gets the physical addresses for descriptors, driver area and device area for a given queue. queue_get(&mut self, queue: u16) -> [PhysAddr; 3]32 fn queue_get(&mut self, queue: u16) -> [PhysAddr; 3]; 33 34 /// Notifies the given queue on the device. notify(&mut self, queue: u16)35 fn notify(&mut self, queue: u16); 36 } 37 38 /// A VirtIO transport layer. 39 pub trait Transport { 40 /// Gets the device type. device_type(&self) -> DeviceType41 fn device_type(&self) -> DeviceType; 42 43 /// Reads device features. read_device_features(&mut self) -> u6444 fn read_device_features(&mut self) -> u64; 45 46 /// Writes device features. write_driver_features(&mut self, driver_features: u64)47 fn write_driver_features(&mut self, driver_features: u64); 48 49 /// Gets the max size of the given queue. max_queue_size(&mut self, queue: u16) -> u3250 fn max_queue_size(&mut self, queue: u16) -> u32; 51 52 /// Notifies the given queue on the device. notify(&mut self, queue: u16)53 fn notify(&mut self, queue: u16); 54 55 /// Gets the device status. get_status(&self) -> DeviceStatus56 fn get_status(&self) -> DeviceStatus; 57 58 /// Sets the device status. set_status(&mut self, status: DeviceStatus)59 fn set_status(&mut self, status: DeviceStatus); 60 61 /// Sets the guest page size. set_guest_page_size(&mut self, guest_page_size: u32)62 fn set_guest_page_size(&mut self, guest_page_size: u32); 63 64 /// Returns whether the transport requires queues to use the legacy layout. 65 /// 66 /// Ref: 2.6.2 Legacy Interfaces: A Note on Virtqueue Layout requires_legacy_layout(&self) -> bool67 fn requires_legacy_layout(&self) -> bool; 68 69 /// Sets up the given queue. queue_set( &mut self, queue: u16, size: u32, descriptors: PhysAddr, driver_area: PhysAddr, device_area: PhysAddr, )70 fn queue_set( 71 &mut self, 72 queue: u16, 73 size: u32, 74 descriptors: PhysAddr, 75 driver_area: PhysAddr, 76 device_area: PhysAddr, 77 ); 78 79 /// Disables and resets the given queue. queue_unset(&mut self, queue: u16)80 fn queue_unset(&mut self, queue: u16); 81 82 /// Returns whether the queue is in use, i.e. has a nonzero PFN or is marked as ready. queue_used(&mut self, queue: u16) -> bool83 fn queue_used(&mut self, queue: u16) -> bool; 84 85 /// Acknowledges an interrupt. 86 /// 87 /// Returns true on success. ack_interrupt(&mut self) -> bool88 fn ack_interrupt(&mut self) -> bool; 89 90 /// Begins initializing the device. 91 /// 92 /// Ref: virtio 3.1.1 Device Initialization 93 /// 94 /// Returns the negotiated set of features. begin_init<F: Flags<Bits = u64> + BitAnd<Output = F> + Debug>( &mut self, supported_features: F, ) -> F95 fn begin_init<F: Flags<Bits = u64> + BitAnd<Output = F> + Debug>( 96 &mut self, 97 supported_features: F, 98 ) -> F { 99 self.set_status(DeviceStatus::empty()); 100 self.set_status(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER); 101 102 let device_features = F::from_bits_truncate(self.read_device_features()); 103 debug!("Device features: {:?}", device_features); 104 let negotiated_features = device_features & supported_features; 105 self.write_driver_features(negotiated_features.bits()); 106 107 self.set_status( 108 DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK, 109 ); 110 111 self.set_guest_page_size(PAGE_SIZE as u32); 112 113 negotiated_features 114 } 115 116 /// Finishes initializing the device. finish_init(&mut self)117 fn finish_init(&mut self) { 118 self.set_status( 119 DeviceStatus::ACKNOWLEDGE 120 | DeviceStatus::DRIVER 121 | DeviceStatus::FEATURES_OK 122 | DeviceStatus::DRIVER_OK, 123 ); 124 } 125 126 /// Reads the configuration space generation. read_config_generation(&self) -> u32127 fn read_config_generation(&self) -> u32; 128 129 /// Reads a value from the device config space. read_config_space<T: FromBytes>(&self, offset: usize) -> Result<T>130 fn read_config_space<T: FromBytes>(&self, offset: usize) -> Result<T>; 131 132 /// Writes a value to the device config space. write_config_space<T: IntoBytes + Immutable>( &mut self, offset: usize, value: T, ) -> Result<()>133 fn write_config_space<T: IntoBytes + Immutable>( 134 &mut self, 135 offset: usize, 136 value: T, 137 ) -> Result<()>; 138 139 /// Safely reads multiple fields from config space by ensuring that the config generation is the 140 /// same before and after all reads, and retrying if not. read_consistent<T>(&self, f: impl Fn() -> Result<T>) -> Result<T>141 fn read_consistent<T>(&self, f: impl Fn() -> Result<T>) -> Result<T> { 142 loop { 143 let before = self.read_config_generation(); 144 let result = f(); 145 let after = self.read_config_generation(); 146 if before == after { 147 break result; 148 } 149 } 150 } 151 } 152 153 bitflags! { 154 /// The device status field. Writing 0 into this field resets the device. 155 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] 156 pub struct DeviceStatus: u32 { 157 /// Indicates that the guest OS has found the device and recognized it 158 /// as a valid virtio device. 159 const ACKNOWLEDGE = 1; 160 161 /// Indicates that the guest OS knows how to drive the device. 162 const DRIVER = 2; 163 164 /// Indicates that something went wrong in the guest, and it has given 165 /// up on the device. This could be an internal error, or the driver 166 /// didn’t like the device for some reason, or even a fatal error 167 /// during device operation. 168 const FAILED = 128; 169 170 /// Indicates that the driver has acknowledged all the features it 171 /// understands, and feature negotiation is complete. 172 const FEATURES_OK = 8; 173 174 /// Indicates that the driver is set up and ready to drive the device. 175 const DRIVER_OK = 4; 176 177 /// Indicates that the device has experienced an error from which it 178 /// can’t recover. 179 const DEVICE_NEEDS_RESET = 64; 180 } 181 } 182 183 /// Types of virtio devices. 184 #[repr(u8)] 185 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 186 #[allow(missing_docs)] 187 pub enum DeviceType { 188 Invalid = 0, 189 Network = 1, 190 Block = 2, 191 Console = 3, 192 EntropySource = 4, 193 MemoryBallooning = 5, 194 IoMemory = 6, 195 Rpmsg = 7, 196 ScsiHost = 8, 197 _9P = 9, 198 Mac80211 = 10, 199 RprocSerial = 11, 200 VirtioCAIF = 12, 201 MemoryBalloon = 13, 202 GPU = 16, 203 Timer = 17, 204 Input = 18, 205 Socket = 19, 206 Crypto = 20, 207 SignalDistributionModule = 21, 208 Pstore = 22, 209 IOMMU = 23, 210 Memory = 24, 211 Sound = 25, 212 } 213 214 impl From<u32> for DeviceType { from(virtio_device_id: u32) -> Self215 fn from(virtio_device_id: u32) -> Self { 216 match virtio_device_id { 217 1 => DeviceType::Network, 218 2 => DeviceType::Block, 219 3 => DeviceType::Console, 220 4 => DeviceType::EntropySource, 221 5 => DeviceType::MemoryBalloon, 222 6 => DeviceType::IoMemory, 223 7 => DeviceType::Rpmsg, 224 8 => DeviceType::ScsiHost, 225 9 => DeviceType::_9P, 226 10 => DeviceType::Mac80211, 227 11 => DeviceType::RprocSerial, 228 12 => DeviceType::VirtioCAIF, 229 13 => DeviceType::MemoryBalloon, 230 16 => DeviceType::GPU, 231 17 => DeviceType::Timer, 232 18 => DeviceType::Input, 233 19 => DeviceType::Socket, 234 20 => DeviceType::Crypto, 235 21 => DeviceType::SignalDistributionModule, 236 22 => DeviceType::Pstore, 237 23 => DeviceType::IOMMU, 238 24 => DeviceType::Memory, 239 25 => DeviceType::Sound, 240 _ => DeviceType::Invalid, 241 } 242 } 243 } 244 245 impl From<u16> for DeviceType { from(virtio_device_id: u16) -> Self246 fn from(virtio_device_id: u16) -> Self { 247 u32::from(virtio_device_id).into() 248 } 249 } 250 251 impl From<u8> for DeviceType { from(virtio_device_id: u8) -> Self252 fn from(virtio_device_id: u8) -> Self { 253 u32::from(virtio_device_id).into() 254 } 255 } 256