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 | ✅        | [`balloon`] |
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 balloon;
98pub mod console;
99#[cfg(any(feature = "mmio", feature = "pci"))]
100mod driver_notifications;
101mod features;
102pub mod fs;
103#[cfg(feature = "mmio")]
104pub mod mmio;
105pub mod net;
106#[cfg(feature = "pci")]
107pub mod pci;
108pub mod pvirtq;
109pub mod virtq;
110pub mod vsock;
111
112pub use endian_num::{be128, be16, be32, be64, le128, le16, le32, le64, Be, Le};
113use num_enum::{FromPrimitive, IntoPrimitive, TryFromPrimitive};
114
115pub use self::features::{FeatureBits, F};
116
117virtio_bitflags! {
118    /// Device Status Field
119    ///
120    /// During device initialization by a driver,
121    /// the driver follows the sequence of steps specified in
122    /// _General Initialization And Device Operation / Device
123    /// Initialization_.
124    ///
125    /// The `device status` field provides a simple low-level
126    /// indication of the completed steps of this sequence.
127    /// It's most useful to imagine it hooked up to traffic
128    /// lights on the console indicating the status of each device.  The
129    /// following bits are defined (listed below in the order in which
130    /// they would be typically set):
131    pub struct DeviceStatus: u8 {
132        /// Indicates that the guest OS has found the
133        /// device and recognized it as a valid virtio device.
134        const ACKNOWLEDGE = 1;
135
136        /// Indicates that the guest OS knows how to drive the
137        /// device.
138        ///
139        /// <div class="warning">
140        ///
141        /// There could be a significant (or infinite) delay before setting
142        /// this bit.  For example, under Linux, drivers can be loadable modules.
143        ///
144        /// </div>
145        const DRIVER = 2;
146
147        /// Indicates that something went wrong in the guest,
148        /// and it has given up on the device. This could be an internal
149        /// error, or the driver didn't like the device for some reason, or
150        /// even a fatal error during device operation.
151        const FAILED = 128;
152
153        /// Indicates that the driver has acknowledged all the
154        /// features it understands, and feature negotiation is complete.
155        const FEATURES_OK = 8;
156
157        /// Indicates that the driver is set up and ready to
158        /// drive the device.
159        const DRIVER_OK = 4;
160
161        /// Indicates that the device has experienced
162        /// an error from which it can't recover.
163        const DEVICE_NEEDS_RESET = 64;
164    }
165}
166
167/// Virtio Device IDs
168///
169/// <div class="warning">
170///
171/// This enum is not ABI-compatible with it's corresponding field.
172/// Use [`Id::from`] for converting from an integer.
173///
174/// </div>
175///
176/// [`Id::from`]: Id#impl-From<u8>-for-Id
177#[derive(IntoPrimitive, FromPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
178#[non_exhaustive]
179#[repr(u8)]
180pub enum Id {
181    /// reserved (invalid)
182    Reserved = 0,
183
184    /// network card
185    Net = 1,
186
187    /// block device
188    Block = 2,
189
190    /// console
191    Console = 3,
192
193    /// entropy source
194    Rng = 4,
195
196    /// memory ballooning (traditional)
197    Balloon = 5,
198
199    /// ioMemory
200    IoMem = 6,
201
202    /// rpmsg
203    Rpmsg = 7,
204
205    /// SCSI host
206    Scsi = 8,
207
208    /// 9P transport
209    NineP = 9,
210
211    /// mac80211 wlan
212    Mac80211Wlan = 10,
213
214    /// rproc serial
215    RprocSerial = 11,
216
217    /// virtio CAIF
218    Caif = 12,
219
220    /// memory balloon
221    MemoryBalloon = 13,
222
223    /// GPU device
224    Gpu = 16,
225
226    /// Timer/Clock device
227    Clock = 17,
228
229    /// Input device
230    Input = 18,
231
232    /// Socket device
233    Vsock = 19,
234
235    /// Crypto device
236    Crypto = 20,
237
238    /// Signal Distribution Module
239    SignalDist = 21,
240
241    /// pstore device
242    Pstore = 22,
243
244    /// IOMMU device
245    Iommu = 23,
246
247    /// Memory device
248    Mem = 24,
249
250    /// Audio device
251    Sound = 25,
252
253    /// file system device
254    Fs = 26,
255
256    /// PMEM device
257    Pmem = 27,
258
259    /// RPMB device
260    Rpmb = 28,
261
262    /// mac80211 hwsim wireless simulation device
263    Mac80211Hwsim = 29,
264
265    /// Video encoder device
266    VideoEncoder = 30,
267
268    /// Video decoder device
269    VideoDecoder = 31,
270
271    /// SCMI device
272    Scmi = 32,
273
274    /// NitroSecureModule
275    NitroSecMod = 33,
276
277    /// I2C adapter
278    I2cAdapter = 34,
279
280    /// Watchdog
281    Watchdog = 35,
282
283    /// CAN device
284    Can = 36,
285
286    /// Parameter Server
287    ParamServ = 38,
288
289    /// Audio policy device
290    AudioPolicy = 39,
291
292    /// Bluetooth device
293    Bt = 40,
294
295    /// GPIO device
296    Gpio = 41,
297
298    /// RDMA device
299    Rdma = 42,
300
301    /// Unknown device
302    #[num_enum(catch_all)]
303    Unknown(u8),
304}
305
306/// Descriptor Ring Change Event Flags
307#[doc(alias = "RING_EVENT_FLAGS")]
308#[derive(IntoPrimitive, TryFromPrimitive, PartialEq, Eq, Clone, Copy, Debug)]
309#[non_exhaustive]
310#[repr(u8)]
311pub enum RingEventFlags {
312    /// Enable events
313    #[doc(alias = "RING_EVENT_FLAGS_ENABLE")]
314    Enable = 0x0,
315
316    /// Disable events
317    #[doc(alias = "RING_EVENT_FLAGS_DISABLE")]
318    Disable = 0x1,
319
320    /// Enable events for a specific descriptor
321    /// (as specified by Descriptor Ring Change Event Offset/Wrap Counter).
322    /// Only valid if VIRTIO_F_EVENT_IDX has been negotiated.
323    #[doc(alias = "RING_EVENT_FLAGS_DESC")]
324    Desc = 0x2,
325
326    Reserved = 0x3,
327}
328
329impl RingEventFlags {
330    const fn from_bits(bits: u8) -> Self {
331        match bits {
332            0x0 => Self::Enable,
333            0x1 => Self::Disable,
334            0x2 => Self::Desc,
335            0x3 => Self::Reserved,
336            _ => unreachable!(),
337        }
338    }
339
340    const fn into_bits(self) -> u8 {
341        self as u8
342    }
343}
344
345/// Common device configuration space functionality.
346pub trait DeviceConfigSpace: Sized {
347    /// Read from device configuration space.
348    ///
349    /// This function should be used when reading from fields greater than
350    /// 32 bits wide or when reading from multiple fields.
351    ///
352    /// As described in _Driver Requirements: Device Configuration Space_,
353    /// this method checks the configuration atomicity value of the device
354    /// and only returns once the value was the same before and after the
355    /// provided function.
356    ///
357    /// # Examples
358    ///
359    /// ```rust
360    /// # use virtio_spec as virtio;
361    /// use virtio::net::ConfigVolatileFieldAccess;
362    /// use virtio::DeviceConfigSpace;
363    /// use volatile::access::ReadOnly;
364    /// use volatile::VolatilePtr;
365    ///
366    /// fn read_mac(
367    ///     common_cfg: VolatilePtr<'_, virtio::pci::CommonCfg, ReadOnly>,
368    ///     net_cfg: VolatilePtr<'_, virtio::net::Config, ReadOnly>,
369    /// ) -> [u8; 6] {
370    ///     common_cfg.read_config_with(|| net_cfg.mac().read())
371    /// }
372    /// ```
373    fn read_config_with<F, T>(self, f: F) -> T
374    where
375        F: FnMut() -> T;
376}