virtio_drivers/transport/
mod.rs

1//! VirtIO transports.
2
3#[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
22/// A VirtIO transport layer.
23pub trait Transport {
24    /// Gets the device type.
25    fn device_type(&self) -> DeviceType;
26
27    /// Reads device features.
28    fn read_device_features(&mut self) -> u64;
29
30    /// Writes device features.
31    fn write_driver_features(&mut self, driver_features: u64);
32
33    /// Gets the max size of the given queue.
34    fn max_queue_size(&mut self, queue: u16) -> u32;
35
36    /// Notifies the given queue on the device.
37    fn notify(&mut self, queue: u16);
38
39    /// Gets the device status.
40    fn get_status(&self) -> DeviceStatus;
41
42    /// Sets the device status.
43    fn set_status(&mut self, status: DeviceStatus);
44
45    /// Sets the guest page size.
46    fn set_guest_page_size(&mut self, guest_page_size: u32);
47
48    /// Returns whether the transport requires queues to use the legacy layout.
49    ///
50    /// Ref: 2.6.2 Legacy Interfaces: A Note on Virtqueue Layout
51    fn requires_legacy_layout(&self) -> bool;
52
53    /// Sets up the given queue.
54    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    /// Disables and resets the given queue.
64    fn queue_unset(&mut self, queue: u16);
65
66    /// Returns whether the queue is in use, i.e. has a nonzero PFN or is marked as ready.
67    fn queue_used(&mut self, queue: u16) -> bool;
68
69    /// Acknowledges an interrupt.
70    ///
71    /// Returns true on success.
72    fn ack_interrupt(&mut self) -> InterruptStatus;
73
74    /// Begins initializing the device.
75    ///
76    /// Ref: virtio 3.1.1 Device Initialization
77    ///
78    /// Returns the negotiated set of features.
79    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                // > 6.1 Driver Requirements: Reserved Feature Bits
95                // > A driver MUST accept VIRTIO_F_VERSION_1 if it is offered.
96                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    /// Finishes initializing the device.
111    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    /// Reads the configuration space generation.
121    fn read_config_generation(&self) -> u32;
122
123    /// Reads a value from the device config space.
124    fn read_config_space<T: FromBytes + IntoBytes>(&self, offset: usize) -> Result<T>;
125
126    /// Writes a value to the device config space.
127    fn write_config_space<T: IntoBytes + Immutable>(
128        &mut self,
129        offset: usize,
130        value: T,
131    ) -> Result<()>;
132
133    /// Safely reads multiple fields from config space by ensuring that the config generation is the
134    /// same before and after all reads, and retrying if not.
135    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/// The device status field. Writing 0 into this field resets the device.
148#[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        /// Indicates that the guest OS has found the device and recognized it
163        /// as a valid virtio device.
164        const ACKNOWLEDGE = 1;
165
166        /// Indicates that the guest OS knows how to drive the device.
167        const DRIVER = 2;
168
169        /// Indicates that something went wrong in the guest, and it has given
170        /// up on the device. This could be an internal error, or the driver
171        /// didn’t like the device for some reason, or even a fatal error
172        /// during device operation.
173        const FAILED = 128;
174
175        /// Indicates that the driver has acknowledged all the features it
176        /// understands, and feature negotiation is complete.
177        const FEATURES_OK = 8;
178
179        /// Indicates that the driver is set up and ready to drive the device.
180        const DRIVER_OK = 4;
181
182        /// Indicates that the device has experienced an error from which it
183        /// can’t recover.
184        const DEVICE_NEEDS_RESET = 64;
185    }
186}
187
188/// The set of interrupts which were pending
189///
190/// Ref: 4.1.4.5 ISR status capability
191#[derive(Copy, Clone, Default, Eq, FromBytes, PartialEq)]
192pub struct InterruptStatus(u32);
193
194bitflags! {
195    impl InterruptStatus: u32 {
196        /// Indicates that a virtqueue buffer was used
197        const QUEUE_INTERRUPT = 1 << 0;
198
199        /// Indicates that a virtio device changed its configuration state
200        const DEVICE_CONFIGURATION_INTERRUPT = 1 << 1;
201    }
202}
203
204/// Types of virtio devices.
205#[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/// Errors converting a number to a virtio device type.
235#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
236pub enum DeviceTypeError {
237    /// Invalid or unknown virtio device type.
238    #[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}