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::{PAGE_SIZE, PhysAddr, Result};
12use bitflags::{Flags, bitflags};
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!(
97 negotiated_features.bits() & Feature::VERSION_1.bits() > 0,
98 "Driver must accept VIRTIO_F_VERSION_1 in supported features because it is offered by the device."
99 );
100 }
101 }
102 self.write_driver_features(negotiated_features.bits());
103
104 self.set_status(
105 DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK,
106 );
107
108 self.set_guest_page_size(PAGE_SIZE as u32);
109
110 negotiated_features
111 }
112
113 fn finish_init(&mut self) {
115 self.set_status(
116 DeviceStatus::ACKNOWLEDGE
117 | DeviceStatus::DRIVER
118 | DeviceStatus::FEATURES_OK
119 | DeviceStatus::DRIVER_OK,
120 );
121 }
122
123 fn read_config_generation(&self) -> u32;
125
126 fn read_config_space<T: FromBytes + IntoBytes>(&self, offset: usize) -> Result<T>;
128
129 fn write_config_space<T: IntoBytes + Immutable>(
131 &mut self,
132 offset: usize,
133 value: T,
134 ) -> Result<()>;
135
136 fn read_consistent<T>(&self, f: impl Fn() -> Result<T>) -> Result<T> {
139 loop {
140 let before = self.read_config_generation();
141 let result = f();
142 let after = self.read_config_generation();
143 if before == after {
144 break result;
145 }
146 }
147 }
148}
149
150#[derive(Copy, Clone, Default, Eq, FromBytes, Immutable, IntoBytes, PartialEq)]
152pub struct DeviceStatus(u32);
153
154impl Debug for DeviceStatus {
155 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
156 write!(f, "DeviceStatus(")?;
157 bitflags::parser::to_writer(self, &mut *f)?;
158 write!(f, ")")?;
159 Ok(())
160 }
161}
162
163bitflags! {
164 impl DeviceStatus: u32 {
165 const ACKNOWLEDGE = 1;
168
169 const DRIVER = 2;
171
172 const FAILED = 128;
177
178 const FEATURES_OK = 8;
181
182 const DRIVER_OK = 4;
184
185 const DEVICE_NEEDS_RESET = 64;
188 }
189}
190
191#[derive(Copy, Clone, Default, Eq, FromBytes, PartialEq)]
195pub struct InterruptStatus(u32);
196
197bitflags! {
198 impl InterruptStatus: u32 {
199 const QUEUE_INTERRUPT = 1 << 0;
201
202 const DEVICE_CONFIGURATION_INTERRUPT = 1 << 1;
204 }
205}
206
207#[repr(u8)]
209#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
210#[allow(missing_docs)]
211pub enum DeviceType {
212 Network = 1,
213 Block = 2,
214 Console = 3,
215 EntropySource = 4,
216 MemoryBallooning = 5,
217 IoMemory = 6,
218 Rpmsg = 7,
219 ScsiHost = 8,
220 _9P = 9,
221 Mac80211 = 10,
222 RprocSerial = 11,
223 VirtioCAIF = 12,
224 MemoryBalloon = 13,
225 GPU = 16,
226 Timer = 17,
227 Input = 18,
228 Socket = 19,
229 Crypto = 20,
230 SignalDistributionModule = 21,
231 Pstore = 22,
232 IOMMU = 23,
233 Memory = 24,
234 Sound = 25,
235}
236
237#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
239pub enum DeviceTypeError {
240 #[error("Invalid or unknown virtio device type {0}")]
242 InvalidDeviceType(u32),
243}
244
245impl TryFrom<u32> for DeviceType {
246 type Error = DeviceTypeError;
247
248 fn try_from(virtio_device_id: u32) -> core::result::Result<Self, Self::Error> {
249 match virtio_device_id {
250 1 => Ok(DeviceType::Network),
251 2 => Ok(DeviceType::Block),
252 3 => Ok(DeviceType::Console),
253 4 => Ok(DeviceType::EntropySource),
254 5 => Ok(DeviceType::MemoryBalloon),
255 6 => Ok(DeviceType::IoMemory),
256 7 => Ok(DeviceType::Rpmsg),
257 8 => Ok(DeviceType::ScsiHost),
258 9 => Ok(DeviceType::_9P),
259 10 => Ok(DeviceType::Mac80211),
260 11 => Ok(DeviceType::RprocSerial),
261 12 => Ok(DeviceType::VirtioCAIF),
262 13 => Ok(DeviceType::MemoryBalloon),
263 16 => Ok(DeviceType::GPU),
264 17 => Ok(DeviceType::Timer),
265 18 => Ok(DeviceType::Input),
266 19 => Ok(DeviceType::Socket),
267 20 => Ok(DeviceType::Crypto),
268 21 => Ok(DeviceType::SignalDistributionModule),
269 22 => Ok(DeviceType::Pstore),
270 23 => Ok(DeviceType::IOMMU),
271 24 => Ok(DeviceType::Memory),
272 25 => Ok(DeviceType::Sound),
273 _ => Err(DeviceTypeError::InvalidDeviceType(virtio_device_id)),
274 }
275 }
276}
277
278impl TryFrom<u16> for DeviceType {
279 type Error = DeviceTypeError;
280
281 fn try_from(virtio_device_id: u16) -> core::result::Result<Self, Self::Error> {
282 u32::from(virtio_device_id).try_into()
283 }
284}
285
286impl TryFrom<u8> for DeviceType {
287 type Error = DeviceTypeError;
288
289 fn try_from(virtio_device_id: u8) -> core::result::Result<Self, Self::Error> {
290 u32::from(virtio_device_id).try_into()
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn debug_device_status() {
300 let status = DeviceStatus::from_bits_retain(0x23);
301 assert_eq!(
302 format!("{:?}", status),
303 "DeviceStatus(ACKNOWLEDGE | DRIVER | 0x20)"
304 );
305 }
306}