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}