1 //! VirtIO transports. 2 3 #[cfg(test)] 4 pub mod fake; 5 pub mod mmio; 6 pub mod pci; 7 8 use crate::{PhysAddr, Result, PAGE_SIZE}; 9 use bitflags::{bitflags, Flags}; 10 use core::{fmt::Debug, ops::BitAnd, ptr::NonNull}; 11 use log::debug; 12 13 /// A VirtIO transport layer. 14 pub trait Transport { 15 /// Gets the device type. device_type(&self) -> DeviceType16 fn device_type(&self) -> DeviceType; 17 18 /// Reads device features. read_device_features(&mut self) -> u6419 fn read_device_features(&mut self) -> u64; 20 21 /// Writes device features. write_driver_features(&mut self, driver_features: u64)22 fn write_driver_features(&mut self, driver_features: u64); 23 24 /// Gets the max size of the given queue. max_queue_size(&mut self, queue: u16) -> u3225 fn max_queue_size(&mut self, queue: u16) -> u32; 26 27 /// Notifies the given queue on the device. notify(&mut self, queue: u16)28 fn notify(&mut self, queue: u16); 29 30 /// Gets the device status. get_status(&self) -> DeviceStatus31 fn get_status(&self) -> DeviceStatus; 32 33 /// Sets the device status. set_status(&mut self, status: DeviceStatus)34 fn set_status(&mut self, status: DeviceStatus); 35 36 /// Sets the guest page size. set_guest_page_size(&mut self, guest_page_size: u32)37 fn set_guest_page_size(&mut self, guest_page_size: u32); 38 39 /// Returns whether the transport requires queues to use the legacy layout. 40 /// 41 /// Ref: 2.6.2 Legacy Interfaces: A Note on Virtqueue Layout requires_legacy_layout(&self) -> bool42 fn requires_legacy_layout(&self) -> bool; 43 44 /// Sets up the given queue. queue_set( &mut self, queue: u16, size: u32, descriptors: PhysAddr, driver_area: PhysAddr, device_area: PhysAddr, )45 fn queue_set( 46 &mut self, 47 queue: u16, 48 size: u32, 49 descriptors: PhysAddr, 50 driver_area: PhysAddr, 51 device_area: PhysAddr, 52 ); 53 54 /// Disables and resets the given queue. queue_unset(&mut self, queue: u16)55 fn queue_unset(&mut self, queue: u16); 56 57 /// Returns whether the queue is in use, i.e. has a nonzero PFN or is marked as ready. queue_used(&mut self, queue: u16) -> bool58 fn queue_used(&mut self, queue: u16) -> bool; 59 60 /// Acknowledges an interrupt. 61 /// 62 /// Returns true on success. ack_interrupt(&mut self) -> bool63 fn ack_interrupt(&mut self) -> bool; 64 65 /// Begins initializing the device. 66 /// 67 /// Ref: virtio 3.1.1 Device Initialization 68 /// 69 /// Returns the negotiated set of features. begin_init<F: Flags<Bits = u64> + BitAnd<Output = F> + Debug>( &mut self, supported_features: F, ) -> F70 fn begin_init<F: Flags<Bits = u64> + BitAnd<Output = F> + Debug>( 71 &mut self, 72 supported_features: F, 73 ) -> F { 74 self.set_status(DeviceStatus::empty()); 75 self.set_status(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER); 76 77 let device_features = F::from_bits_truncate(self.read_device_features()); 78 debug!("Device features: {:?}", device_features); 79 let negotiated_features = device_features & supported_features; 80 self.write_driver_features(negotiated_features.bits()); 81 82 self.set_status( 83 DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK, 84 ); 85 86 self.set_guest_page_size(PAGE_SIZE as u32); 87 88 negotiated_features 89 } 90 91 /// Finishes initializing the device. finish_init(&mut self)92 fn finish_init(&mut self) { 93 self.set_status( 94 DeviceStatus::ACKNOWLEDGE 95 | DeviceStatus::DRIVER 96 | DeviceStatus::FEATURES_OK 97 | DeviceStatus::DRIVER_OK, 98 ); 99 } 100 101 /// Gets the pointer to the config space. config_space<T: 'static>(&self) -> Result<NonNull<T>>102 fn config_space<T: 'static>(&self) -> Result<NonNull<T>>; 103 } 104 105 bitflags! { 106 /// The device status field. Writing 0 into this field resets the device. 107 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] 108 pub struct DeviceStatus: u32 { 109 /// Indicates that the guest OS has found the device and recognized it 110 /// as a valid virtio device. 111 const ACKNOWLEDGE = 1; 112 113 /// Indicates that the guest OS knows how to drive the device. 114 const DRIVER = 2; 115 116 /// Indicates that something went wrong in the guest, and it has given 117 /// up on the device. This could be an internal error, or the driver 118 /// didn’t like the device for some reason, or even a fatal error 119 /// during device operation. 120 const FAILED = 128; 121 122 /// Indicates that the driver has acknowledged all the features it 123 /// understands, and feature negotiation is complete. 124 const FEATURES_OK = 8; 125 126 /// Indicates that the driver is set up and ready to drive the device. 127 const DRIVER_OK = 4; 128 129 /// Indicates that the device has experienced an error from which it 130 /// can’t recover. 131 const DEVICE_NEEDS_RESET = 64; 132 } 133 } 134 135 /// Types of virtio devices. 136 #[repr(u8)] 137 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 138 #[allow(missing_docs)] 139 pub enum DeviceType { 140 Invalid = 0, 141 Network = 1, 142 Block = 2, 143 Console = 3, 144 EntropySource = 4, 145 MemoryBallooning = 5, 146 IoMemory = 6, 147 Rpmsg = 7, 148 ScsiHost = 8, 149 _9P = 9, 150 Mac80211 = 10, 151 RprocSerial = 11, 152 VirtioCAIF = 12, 153 MemoryBalloon = 13, 154 GPU = 16, 155 Timer = 17, 156 Input = 18, 157 Socket = 19, 158 Crypto = 20, 159 SignalDistributionModule = 21, 160 Pstore = 22, 161 IOMMU = 23, 162 Memory = 24, 163 } 164 165 impl From<u32> for DeviceType { from(virtio_device_id: u32) -> Self166 fn from(virtio_device_id: u32) -> Self { 167 match virtio_device_id { 168 1 => DeviceType::Network, 169 2 => DeviceType::Block, 170 3 => DeviceType::Console, 171 4 => DeviceType::EntropySource, 172 5 => DeviceType::MemoryBalloon, 173 6 => DeviceType::IoMemory, 174 7 => DeviceType::Rpmsg, 175 8 => DeviceType::ScsiHost, 176 9 => DeviceType::_9P, 177 10 => DeviceType::Mac80211, 178 11 => DeviceType::RprocSerial, 179 12 => DeviceType::VirtioCAIF, 180 13 => DeviceType::MemoryBalloon, 181 16 => DeviceType::GPU, 182 17 => DeviceType::Timer, 183 18 => DeviceType::Input, 184 19 => DeviceType::Socket, 185 20 => DeviceType::Crypto, 186 21 => DeviceType::SignalDistributionModule, 187 22 => DeviceType::Pstore, 188 23 => DeviceType::IOMMU, 189 24 => DeviceType::Memory, 190 _ => DeviceType::Invalid, 191 } 192 } 193 } 194 195 impl From<u16> for DeviceType { from(virtio_device_id: u16) -> Self196 fn from(virtio_device_id: u16) -> Self { 197 u32::from(virtio_device_id).into() 198 } 199 } 200 201 impl From<u8> for DeviceType { from(virtio_device_id: u8) -> Self202 fn from(virtio_device_id: u8) -> Self { 203 u32::from(virtio_device_id).into() 204 } 205 } 206