virtio_spec/
lib.rs

1//! This crate contains the Rust equivalents of the definitions from the [Virtual I/O Device (VIRTIO) Specification](https://github.com/oasis-tcs/virtio-spec).
2//! This crate aims to be unopinionated regarding actual VIRTIO drivers that are implemented on top of this crate.
3//!
4//! # Usage
5//!
6//! We recommend to rename this crate to `virtio` when adding the dependency.
7//! This allows closely matching the specification when using definitions:
8//!
9//! - `VIRTIO_NET_F_CSUM` from the specification becomes [`virtio::net::F::CSUM`] in this crate.
10//! - `virtio_net_config` from the specification becomes [`virtio::net::Config`] in this crate.
11//!  
12//! [`virtio::net::F::CSUM`]: net::F::CSUM
13//! [`virtio::net::Config`]: net::Config
14//!
15//! Either run
16//!
17//! ```bash
18//! cargo add virtio-spec --rename virtio
19//! ```
20//!
21//! or manually edit your `Cargo.toml`:
22//!
23//! ```toml
24//! [dependencies]
25//! virtio = { package = "virtio-spec", version = "x.y.z" }
26//! ```
27//!
28//! ## Features
29//!
30//! This crate has the following Cargo features:
31//!
32//! - `alloc` enables allocating unsized structs such as [`virtq::Avail`] and [`virtq::Used`] via the [`allocator_api2`] crate.
33//! - `mmio` enables the [`mmio`] module for Virtio Over MMIO.
34//! - `nightly` enables nightly-only functionality.
35//! - `pci` enables the [`pci`] module for Virtio Over PCI via the [`pci_types`] crate.
36//! - `zerocopy` derives the following traits for most structs:
37//!   - [`zerocopy::KnownLayout`]
38//!   - [`zerocopy::Immutable`]
39//!   - [`zerocopy::FromBytes`]
40//!   - [`zerocopy::IntoBytes`]
41//!
42//! # Implementation Status
43//!
44//! This crate adds new modules by demand.
45//! If you need anything that is not available yet, please open an issue.
46//!
47//! ## Virtqueues
48//!
49//! | Virtqueue         | Available | Module     |
50//! | ----------------- | --------- | ---------- |
51//! | Split Virtqueues  | ✅        | [`virtq`]  |
52//! | Packed Virtqueues | ✅        | [`pvirtq`] |
53//!
54//! ## Transport Options
55//!
56//! | Transport Option | Available | Module   |
57//! | ---------------- | --------- | -------- |
58//! | PCI Bus          | ✅        | [`pci`]  |
59//! | MMIO             | ✅        | [`mmio`] |
60//! | Channel I/O      | ❌        |          |
61//!
62//! ## Device Types
63//!
64//! | Device Type                       | Available | Module      |
65//! | --------------------------------- | --------- | ----------- |
66//! | Network Device                    | ✅        | [`net`]     |
67//! | Block Device                      | ❌        |             |
68//! | Console Device                    | ✅        | [`console`] |
69//! | Entropy Device                    | ❌        |             |
70//! | Traditional Memory Balloon Device | ❌        |             |
71//! | SCSI Host Device                  | ❌        |             |
72//! | GPU Device                        | ❌        |             |
73//! | Input Device                      | ❌        |             |
74//! | Crypto Device                     | ❌        |             |
75//! | Socket Device                     | ✅        | [`vsock`]   |
76//! | File System Device                | ✅        | [`fs`]      |
77//! | RPMB Device                       | ❌        |             |
78//! | IOMMU Device                      | ❌        |             |
79//! | Sound Device                      | ❌        |             |
80//! | Memory Device                     | ❌        |             |
81//! | I2C Adapter Device                | ❌        |             |
82//! | SCMI Device                       | ❌        |             |
83//! | GPIO Device                       | ❌        |             |
84//! | PMEM Device                       | ❌        |             |
85
86#![cfg_attr(not(test), no_std)]
87#![cfg_attr(docsrs, feature(doc_auto_cfg))]
88#![cfg_attr(feature = "nightly", feature(allocator_api))]
89
90#[cfg(feature = "alloc")]
91extern crate alloc;
92
93#[macro_use]
94mod bitflags;
95#[macro_use]
96pub mod volatile;
97pub mod console;
98#[cfg(any(feature = "mmio", feature = "pci"))]
99mod driver_notifications;
100mod features;
101pub mod fs;
102#[cfg(feature = "mmio")]
103pub mod mmio;
104pub mod net;
105#[cfg(feature = "pci")]
106pub mod pci;
107pub mod pvirtq;
108pub mod virtq;
109pub mod vsock;
110
111pub use endian_num::{be128, be16, be32, be64, le128, le16, le32, le64, Be, Le};
112use num_enum::{FromPrimitive, IntoPrimitive, TryFromPrimitive};
113
114pub use self::features::{FeatureBits, F};
115
116virtio_bitflags! {
117    /// Device Status Field
118    ///
119    /// During device initialization by a driver,
120    /// the driver follows the sequence of steps specified in
121    /// _General Initialization And Device Operation / Device
122    /// Initialization_.
123    ///
124    /// The `device status` field provides a simple low-level
125    /// indication of the completed steps of this sequence.
126    /// It's most useful to imagine it hooked up to traffic
127    /// lights on the console indicating the status of each device.  The
128    /// following bits are defined (listed below in the order in which
129    /// they would be typically set):
130    pub struct DeviceStatus: u8 {
131        /// Indicates that the guest OS has found the
132        /// device and recognized it as a valid virtio device.
133        const ACKNOWLEDGE = 1;
134
135        /// Indicates that the guest OS knows how to drive the
136        /// device.
137        ///
138        /// <div class="warning">
139        ///
140        /// There could be a significant (or infinite) delay before setting
141        /// this bit.  For example, under Linux, drivers can be loadable modules.
142        ///
143        /// </div>
144        const DRIVER = 2;
145
146        /// Indicates that something went wrong in the guest,
147        /// and it has given up on the device. This could be an internal
148        /// error, or the driver didn't like the device for some reason, or
149        /// even a fatal error during device operation.
150        const FAILED = 128;
151
152        /// Indicates that the driver has acknowledged all the
153        /// features it understands, and feature negotiation is complete.
154        const FEATURES_OK = 8;
155
156        /// Indicates that the driver is set up and ready to
157        /// drive the device.
158        const DRIVER_OK = 4;
159
160        /// Indicates that the device has experienced
161        /// an error from which it can't recover.
162        const DEVICE_NEEDS_RESET = 64;
163    }
164}
165
166/// Virtio Device IDs
167///
168/// <div class="warning">
169///
170/// This enum is not ABI-compatible with it's corresponding field.
171/// Use [`Id::from`] for converting from an integer.
172///
173/// </div>
174///
175/// [`Id::from`]: Id#impl-From<u8>-for-Id
176#[derive(IntoPrimitive, FromPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
177#[non_exhaustive]
178#[repr(u8)]
179pub enum Id {
180    /// reserved (invalid)
181    Reserved = 0,
182
183    /// network card
184    Net = 1,
185
186    /// block device
187    Block = 2,
188
189    /// console
190    Console = 3,
191
192    /// entropy source
193    Rng = 4,
194
195    /// memory ballooning (traditional)
196    Balloon = 5,
197
198    /// ioMemory
199    IoMem = 6,
200
201    /// rpmsg
202    Rpmsg = 7,
203
204    /// SCSI host
205    Scsi = 8,
206
207    /// 9P transport
208    NineP = 9,
209
210    /// mac80211 wlan
211    Mac80211Wlan = 10,
212
213    /// rproc serial
214    RprocSerial = 11,
215
216    /// virtio CAIF
217    Caif = 12,
218
219    /// memory balloon
220    MemoryBalloon = 13,
221
222    /// GPU device
223    Gpu = 16,
224
225    /// Timer/Clock device
226    Clock = 17,
227
228    /// Input device
229    Input = 18,
230
231    /// Socket device
232    Vsock = 19,
233
234    /// Crypto device
235    Crypto = 20,
236
237    /// Signal Distribution Module
238    SignalDist = 21,
239
240    /// pstore device
241    Pstore = 22,
242
243    /// IOMMU device
244    Iommu = 23,
245
246    /// Memory device
247    Mem = 24,
248
249    /// Audio device
250    Sound = 25,
251
252    /// file system device
253    Fs = 26,
254
255    /// PMEM device
256    Pmem = 27,
257
258    /// RPMB device
259    Rpmb = 28,
260
261    /// mac80211 hwsim wireless simulation device
262    Mac80211Hwsim = 29,
263
264    /// Video encoder device
265    VideoEncoder = 30,
266
267    /// Video decoder device
268    VideoDecoder = 31,
269
270    /// SCMI device
271    Scmi = 32,
272
273    /// NitroSecureModule
274    NitroSecMod = 33,
275
276    /// I2C adapter
277    I2cAdapter = 34,
278
279    /// Watchdog
280    Watchdog = 35,
281
282    /// CAN device
283    Can = 36,
284
285    /// Parameter Server
286    ParamServ = 38,
287
288    /// Audio policy device
289    AudioPolicy = 39,
290
291    /// Bluetooth device
292    Bt = 40,
293
294    /// GPIO device
295    Gpio = 41,
296
297    /// RDMA device
298    Rdma = 42,
299
300    /// Unknown device
301    #[num_enum(catch_all)]
302    Unknown(u8),
303}
304
305/// Descriptor Ring Change Event Flags
306#[doc(alias = "RING_EVENT_FLAGS")]
307#[derive(IntoPrimitive, TryFromPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
308#[non_exhaustive]
309#[repr(u8)]
310pub enum RingEventFlags {
311    /// Enable events
312    #[doc(alias = "RING_EVENT_FLAGS_ENABLE")]
313    Enable = 0x0,
314
315    /// Disable events
316    #[doc(alias = "RING_EVENT_FLAGS_DISABLE")]
317    Disable = 0x1,
318
319    /// Enable events for a specific descriptor
320    /// (as specified by Descriptor Ring Change Event Offset/Wrap Counter).
321    /// Only valid if VIRTIO_F_EVENT_IDX has been negotiated.
322    #[doc(alias = "RING_EVENT_FLAGS_DESC")]
323    Desc = 0x2,
324
325    Reserved = 0x3,
326}
327
328impl RingEventFlags {
329    const fn from_bits(bits: u8) -> Self {
330        match bits {
331            0x0 => Self::Enable,
332            0x1 => Self::Disable,
333            0x2 => Self::Desc,
334            0x3 => Self::Reserved,
335            _ => unreachable!(),
336        }
337    }
338
339    const fn into_bits(self) -> u8 {
340        self as u8
341    }
342}
343
344/// Common device configuration space functionality.
345pub trait DeviceConfigSpace: Sized {
346    /// Read from device configuration space.
347    ///
348    /// This function should be used when reading from fields greater than
349    /// 32 bits wide or when reading from multiple fields.
350    ///
351    /// As described in _Driver Requirements: Device Configuration Space_,
352    /// this method checks the configuration atomicity value of the device
353    /// and only returns once the value was the same before and after the
354    /// provided function.
355    ///
356    /// # Examples
357    ///
358    /// ```rust
359    /// # use virtio_spec as virtio;
360    /// use virtio::net::ConfigVolatileFieldAccess;
361    /// use virtio::DeviceConfigSpace;
362    /// use volatile::access::ReadOnly;
363    /// use volatile::VolatilePtr;
364    ///
365    /// fn read_mac(
366    ///     common_cfg: VolatilePtr<'_, virtio::pci::CommonCfg, ReadOnly>,
367    ///     net_cfg: VolatilePtr<'_, virtio::net::Config, ReadOnly>,
368    /// ) -> [u8; 6] {
369    ///     common_cfg.read_config_with(|| net_cfg.mac().read())
370    /// }
371    /// ```
372    fn read_config_with<F, T>(self, f: F) -> T
373    where
374        F: FnMut() -> T;
375}