Skip to main content

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