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