virtio_drivers/transport/
mod.rs1#[cfg(test)]
4pub mod fake;
5pub mod mmio;
6pub mod pci;
7mod some;
8#[cfg(target_arch = "x86_64")]
9pub mod x86_64;
10
11use crate::{PhysAddr, Result, PAGE_SIZE};
12use bitflags::{bitflags, Flags};
13use core::{
14 fmt::{self, Debug, Formatter},
15 ops::BitAnd,
16};
17use log::debug;
18pub use some::SomeTransport;
19use thiserror::Error;
20use zerocopy::{FromBytes, Immutable, IntoBytes};
21
22pub trait Transport {
24 fn device_type(&self) -> DeviceType;
26
27 fn read_device_features(&mut self) -> u64;
29
30 fn write_driver_features(&mut self, driver_features: u64);
32
33 fn max_queue_size(&mut self, queue: u16) -> u32;
35
36 fn notify(&mut self, queue: u16);
38
39 fn get_status(&self) -> DeviceStatus;
41
42 fn set_status(&mut self, status: DeviceStatus);
44
45 fn set_guest_page_size(&mut self, guest_page_size: u32);
47
48 fn requires_legacy_layout(&self) -> bool;
52
53 fn queue_set(
55 &mut self,
56 queue: u16,
57 size: u32,
58 descriptors: PhysAddr,
59 driver_area: PhysAddr,
60 device_area: PhysAddr,
61 );
62
63 fn queue_unset(&mut self, queue: u16);
65
66 fn queue_used(&mut self, queue: u16) -> bool;
68
69 fn ack_interrupt(&mut self) -> InterruptStatus;
73
74 fn begin_init<F: Flags<Bits = u64> + BitAnd<Output = F> + Debug>(
80 &mut self,
81 supported_features: F,
82 ) -> F {
83 self.set_status(DeviceStatus::empty());
84 self.set_status(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER);
85
86 let device_feature_bits = self.read_device_features();
87 let device_features = F::from_bits_truncate(device_feature_bits);
88 debug!("Device features: {:?}", device_features);
89 let negotiated_features = device_features & supported_features;
90 if cfg!(debug_assertions) {
91 use crate::device::common::Feature;
92
93 if device_feature_bits & Feature::VERSION_1.bits() > 0 {
94 debug_assert!(negotiated_features.bits() & Feature::VERSION_1.bits() > 0, "Driver must accept VIRTIO_F_VERSION_1 in supported features because it is offered by the device.");
97 }
98 }
99 self.write_driver_features(negotiated_features.bits());
100
101 self.set_status(
102 DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK,
103 );
104
105 self.set_guest_page_size(PAGE_SIZE as u32);
106
107 negotiated_features
108 }
109
110 fn finish_init(&mut self) {
112 self.set_status(
113 DeviceStatus::ACKNOWLEDGE
114 | DeviceStatus::DRIVER
115 | DeviceStatus::FEATURES_OK
116 | DeviceStatus::DRIVER_OK,
117 );
118 }
119
120 fn read_config_generation(&self) -> u32;
122
123 fn read_config_space<T: FromBytes + IntoBytes>(&self, offset: usize) -> Result<T>;
125
126 fn write_config_space<T: IntoBytes + Immutable>(
128 &mut self,
129 offset: usize,
130 value: T,
131 ) -> Result<()>;
132
133 fn read_consistent<T>(&self, f: impl Fn() -> Result<T>) -> Result<T> {
136 loop {
137 let before = self.read_config_generation();
138 let result = f();
139 let after = self.read_config_generation();
140 if before == after {
141 break result;
142 }
143 }
144 }
145}
146
147#[derive(Copy, Clone, Default, Eq, FromBytes, Immutable, IntoBytes, PartialEq)]
149pub struct DeviceStatus(u32);
150
151impl Debug for DeviceStatus {
152 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
153 write!(f, "DeviceStatus(")?;
154 bitflags::parser::to_writer(self, &mut *f)?;
155 write!(f, ")")?;
156 Ok(())
157 }
158}
159
160bitflags! {
161 impl DeviceStatus: u32 {
162 const ACKNOWLEDGE = 1;
165
166 const DRIVER = 2;
168
169 const FAILED = 128;
174
175 const FEATURES_OK = 8;
178
179 const DRIVER_OK = 4;
181
182 const DEVICE_NEEDS_RESET = 64;
185 }
186}
187
188#[derive(Copy, Clone, Default, Eq, FromBytes, PartialEq)]
192pub struct InterruptStatus(u32);
193
194bitflags! {
195 impl InterruptStatus: u32 {
196 const QUEUE_INTERRUPT = 1 << 0;
198
199 const DEVICE_CONFIGURATION_INTERRUPT = 1 << 1;
201 }
202}
203
204#[repr(u8)]
206#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
207#[allow(missing_docs)]
208pub enum DeviceType {
209 Network = 1,
210 Block = 2,
211 Console = 3,
212 EntropySource = 4,
213 MemoryBallooning = 5,
214 IoMemory = 6,
215 Rpmsg = 7,
216 ScsiHost = 8,
217 _9P = 9,
218 Mac80211 = 10,
219 RprocSerial = 11,
220 VirtioCAIF = 12,
221 MemoryBalloon = 13,
222 GPU = 16,
223 Timer = 17,
224 Input = 18,
225 Socket = 19,
226 Crypto = 20,
227 SignalDistributionModule = 21,
228 Pstore = 22,
229 IOMMU = 23,
230 Memory = 24,
231 Sound = 25,
232}
233
234#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
236pub enum DeviceTypeError {
237 #[error("Invalid or unknown virtio device type {0}")]
239 InvalidDeviceType(u32),
240}
241
242impl TryFrom<u32> for DeviceType {
243 type Error = DeviceTypeError;
244
245 fn try_from(virtio_device_id: u32) -> core::result::Result<Self, Self::Error> {
246 match virtio_device_id {
247 1 => Ok(DeviceType::Network),
248 2 => Ok(DeviceType::Block),
249 3 => Ok(DeviceType::Console),
250 4 => Ok(DeviceType::EntropySource),
251 5 => Ok(DeviceType::MemoryBalloon),
252 6 => Ok(DeviceType::IoMemory),
253 7 => Ok(DeviceType::Rpmsg),
254 8 => Ok(DeviceType::ScsiHost),
255 9 => Ok(DeviceType::_9P),
256 10 => Ok(DeviceType::Mac80211),
257 11 => Ok(DeviceType::RprocSerial),
258 12 => Ok(DeviceType::VirtioCAIF),
259 13 => Ok(DeviceType::MemoryBalloon),
260 16 => Ok(DeviceType::GPU),
261 17 => Ok(DeviceType::Timer),
262 18 => Ok(DeviceType::Input),
263 19 => Ok(DeviceType::Socket),
264 20 => Ok(DeviceType::Crypto),
265 21 => Ok(DeviceType::SignalDistributionModule),
266 22 => Ok(DeviceType::Pstore),
267 23 => Ok(DeviceType::IOMMU),
268 24 => Ok(DeviceType::Memory),
269 25 => Ok(DeviceType::Sound),
270 _ => Err(DeviceTypeError::InvalidDeviceType(virtio_device_id)),
271 }
272 }
273}
274
275impl TryFrom<u16> for DeviceType {
276 type Error = DeviceTypeError;
277
278 fn try_from(virtio_device_id: u16) -> core::result::Result<Self, Self::Error> {
279 u32::from(virtio_device_id).try_into()
280 }
281}
282
283impl TryFrom<u8> for DeviceType {
284 type Error = DeviceTypeError;
285
286 fn try_from(virtio_device_id: u8) -> core::result::Result<Self, Self::Error> {
287 u32::from(virtio_device_id).try_into()
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294
295 #[test]
296 fn debug_device_status() {
297 let status = DeviceStatus::from_bits_retain(0x23);
298 assert_eq!(
299 format!("{:?}", status),
300 "DeviceStatus(ACKNOWLEDGE | DRIVER | 0x20)"
301 );
302 }
303}