virtio_drivers/transport/
mod.rs

1//! VirtIO transports.
2
3#[cfg(test)]
4pub mod fake;
5pub mod mmio;
6pub mod pci;
7
8use crate::{PhysAddr, Result, PAGE_SIZE};
9use bitflags::{bitflags, Flags};
10use core::{fmt::Debug, ops::BitAnd, ptr::NonNull};
11use log::debug;
12
13/// A VirtIO transport layer.
14pub trait Transport {
15    /// Gets the device type.
16    fn device_type(&self) -> DeviceType;
17
18    /// Reads device features.
19    fn read_device_features(&mut self) -> u64;
20
21    /// Writes device features.
22    fn write_driver_features(&mut self, driver_features: u64);
23
24    /// Gets the max size of the given queue.
25    fn max_queue_size(&mut self, queue: u16) -> u32;
26
27    /// Notifies the given queue on the device.
28    fn notify(&mut self, queue: u16);
29
30    /// Gets the device status.
31    fn get_status(&self) -> DeviceStatus;
32
33    /// Sets the device status.
34    fn set_status(&mut self, status: DeviceStatus);
35
36    /// Sets the guest page size.
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
42    fn requires_legacy_layout(&self) -> bool;
43
44    /// Sets up the given queue.
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.
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.
58    fn queue_used(&mut self, queue: u16) -> bool;
59
60    /// Acknowledges an interrupt.
61    ///
62    /// Returns true on success.
63    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.
70    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.
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.
102    fn config_space<T: 'static>(&self) -> Result<NonNull<T>>;
103}
104
105bitflags! {
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)]
139pub 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    Sound = 25,
164}
165
166impl From<u32> for DeviceType {
167    fn from(virtio_device_id: u32) -> Self {
168        match virtio_device_id {
169            1 => DeviceType::Network,
170            2 => DeviceType::Block,
171            3 => DeviceType::Console,
172            4 => DeviceType::EntropySource,
173            5 => DeviceType::MemoryBalloon,
174            6 => DeviceType::IoMemory,
175            7 => DeviceType::Rpmsg,
176            8 => DeviceType::ScsiHost,
177            9 => DeviceType::_9P,
178            10 => DeviceType::Mac80211,
179            11 => DeviceType::RprocSerial,
180            12 => DeviceType::VirtioCAIF,
181            13 => DeviceType::MemoryBalloon,
182            16 => DeviceType::GPU,
183            17 => DeviceType::Timer,
184            18 => DeviceType::Input,
185            19 => DeviceType::Socket,
186            20 => DeviceType::Crypto,
187            21 => DeviceType::SignalDistributionModule,
188            22 => DeviceType::Pstore,
189            23 => DeviceType::IOMMU,
190            24 => DeviceType::Memory,
191            25 => DeviceType::Sound,
192            _ => DeviceType::Invalid,
193        }
194    }
195}
196
197impl From<u16> for DeviceType {
198    fn from(virtio_device_id: u16) -> Self {
199        u32::from(virtio_device_id).into()
200    }
201}
202
203impl From<u8> for DeviceType {
204    fn from(virtio_device_id: u8) -> Self {
205        u32::from(virtio_device_id).into()
206    }
207}