virtio_spec/features.rs
1//! Feature Bits
2
3use crate::le128;
4
5/// Feature Bits
6#[doc(alias = "VIRTIO_F")]
7pub trait FeatureBits: bitflags::Flags<Bits = le128>
8where
9 Self: From<F> + AsRef<F> + AsMut<F>,
10 F: From<Self> + AsRef<Self> + AsMut<Self>,
11{
12 /// Returns the feature that this feature requires.
13 ///
14 /// If `self` is a single feature and multiple features are returned, `self` requires only one of them.
15 ///
16 /// # Examples
17 ///
18 /// ```
19 /// # use virtio_spec as virtio;
20 /// use virtio::FeatureBits;
21 ///
22 /// assert_eq!(
23 /// virtio::net::F::GUEST_TSO4.requirements(),
24 /// virtio::net::F::GUEST_CSUM
25 /// );
26 /// assert_eq!(
27 /// virtio::net::F::GUEST_ECN.requirements(),
28 /// virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_TSO6
29 /// );
30 /// ```
31 fn requirements(&self) -> Self {
32 Self::empty()
33 }
34
35 /// Returns `true` if all internal feature requirements are satisfied.
36 ///
37 /// # Examples
38 ///
39 /// ```
40 /// # use virtio_spec as virtio;
41 /// use virtio::FeatureBits;
42 ///
43 /// assert!((virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_CSUM).requirements_satisfied());
44 /// assert!(
45 /// (virtio::net::F::GUEST_ECN | virtio::net::F::GUEST_TSO4 | virtio::net::F::GUEST_CSUM)
46 /// .requirements_satisfied()
47 /// );
48 /// ```
49 fn requirements_satisfied(&self) -> bool {
50 self.iter()
51 .map(|feature| feature.requirements())
52 .filter(|requirements| !requirements.is_empty())
53 .all(|requirements| self.intersects(requirements))
54 }
55}
56
57endian_bitflags! {
58 /// Device-independent Feature Bits
59 #[doc(alias = "VIRTIO_F")]
60 pub struct F: le128 {
61 /// Negotiating this feature indicates
62 /// that the driver can use descriptors with the VIRTQ_DESC_F_INDIRECT
63 /// flag set, as described in _Basic Facilities of a Virtio
64 /// Device / Virtqueues / The Virtqueue Descriptor Table / Indirect
65 /// Descriptors_ _Basic Facilities of a Virtio Device /
66 /// Virtqueues / The Virtqueue Descriptor Table / Indirect
67 /// Descriptors_ and _Packed Virtqueues / Indirect Flag: Scatter-Gather Support_ _Packed Virtqueues / Indirect Flag: Scatter-Gather Support_.
68 #[doc(alias = "VIRTIO_F_INDIRECT_DESC")]
69 const INDIRECT_DESC = 1 << 28;
70
71 /// This feature enables the _used_event_
72 /// and the _avail_event_ fields as described in
73 /// _Basic Facilities of a Virtio Device / Virtqueues / Used Buffer Notification Suppression_, _Basic Facilities of a Virtio Device / Virtqueues / The Virtqueue Used Ring_ and _Packed Virtqueues / Driver and Device Event Suppression_.
74 #[doc(alias = "VIRTIO_F_EVENT_IDX")]
75 const EVENT_IDX = 1 << 29;
76
77 /// This indicates compliance with this
78 /// specification, giving a simple way to detect legacy devices or drivers.
79 #[doc(alias = "VIRTIO_F_VERSION_1")]
80 const VERSION_1 = 1 << 32;
81
82 /// This feature indicates that
83 /// the device can be used on a platform where device access to data
84 /// in memory is limited and/or translated. E.g. this is the case if the device can be located
85 /// behind an IOMMU that translates bus addresses from the device into physical
86 /// addresses in memory, if the device can be limited to only access
87 /// certain memory addresses or if special commands such as
88 /// a cache flush can be needed to synchronise data in memory with
89 /// the device. Whether accesses are actually limited or translated
90 /// is described by platform-specific means.
91 /// If this feature bit is set to 0, then the device
92 /// has same access to memory addresses supplied to it as the
93 /// driver has.
94 /// In particular, the device will always use physical addresses
95 /// matching addresses used by the driver (typically meaning
96 /// physical addresses used by the CPU)
97 /// and not translated further, and can access any address supplied to it by
98 /// the driver. When clear, this overrides any platform-specific description of
99 /// whether device access is limited or translated in any way, e.g.
100 /// whether an IOMMU may be present.
101 #[doc(alias = "VIRTIO_F_ACCESS_PLATFORM")]
102 const ACCESS_PLATFORM = 1 << 33;
103
104 /// This feature indicates
105 /// support for the packed virtqueue layout as described in
106 /// _Basic Facilities of a Virtio Device / Packed Virtqueues_ _Basic Facilities of a Virtio Device / Packed Virtqueues_.
107 #[doc(alias = "VIRTIO_F_RING_PACKED")]
108 const RING_PACKED = 1 << 34;
109
110 /// This feature indicates
111 /// that all buffers are used by the device in the same
112 /// order in which they have been made available.
113 #[doc(alias = "VIRTIO_F_IN_ORDER")]
114 const IN_ORDER = 1 << 35;
115
116 /// This feature indicates
117 /// that memory accesses by the driver and the device are ordered
118 /// in a way described by the platform.
119 ///
120 /// If this feature bit is negotiated, the ordering in effect for any
121 /// memory accesses by the driver that need to be ordered in a specific way
122 /// with respect to accesses by the device is the one suitable for devices
123 /// described by the platform. This implies that the driver needs to use
124 /// memory barriers suitable for devices described by the platform; e.g.
125 /// for the PCI transport in the case of hardware PCI devices.
126 ///
127 /// If this feature bit is not negotiated, then the device
128 /// and driver are assumed to be implemented in software, that is
129 /// they can be assumed to run on identical CPUs
130 /// in an SMP configuration.
131 /// Thus a weaker form of memory barriers is sufficient
132 /// to yield better performance.
133 #[doc(alias = "VIRTIO_F_ORDER_PLATFORM")]
134 const ORDER_PLATFORM = 1 << 36;
135
136 /// This feature indicates that
137 /// the device supports Single Root I/O Virtualization.
138 /// Currently only PCI devices support this feature.
139 #[doc(alias = "VIRTIO_F_SR_IOV")]
140 const SR_IOV = 1 << 37;
141
142 /// This feature indicates
143 /// that the driver passes extra data (besides identifying the virtqueue)
144 /// in its device notifications.
145 /// See _Virtqueues / Driver notifications_ _Virtqueues / Driver notifications_.
146 #[doc(alias = "VIRTIO_F_NOTIFICATION_DATA")]
147 const NOTIFICATION_DATA = 1 << 38;
148
149 /// This feature indicates that the driver
150 /// uses the data provided by the device as a virtqueue identifier in available
151 /// buffer notifications.
152 /// As mentioned in section _Virtqueues / Driver notifications_, when the
153 /// driver is required to send an available buffer notification to the device, it
154 /// sends the virtqueue number to be notified. The method of delivering
155 /// notifications is transport specific.
156 /// With the PCI transport, the device can optionally provide a per-virtqueue value
157 /// for the driver to use in driver notifications, instead of the virtqueue number.
158 /// Some devices may benefit from this flexibility by providing, for example,
159 /// an internal virtqueue identifier, or an internal offset related to the
160 /// virtqueue number.
161 ///
162 /// This feature indicates the availability of such value. The definition of the
163 /// data to be provided in driver notification and the delivery method is
164 /// transport specific.
165 /// For more details about driver notifications over PCI see _Virtio Transport Options / Virtio Over PCI Bus / PCI-specific Initialization And Device Operation / Available Buffer Notifications_.
166 #[doc(alias = "VIRTIO_F_NOTIF_CONFIG_DATA")]
167 const NOTIF_CONFIG_DATA = 1 << 39;
168
169 /// This feature indicates
170 /// that the driver can reset a queue individually.
171 /// See _Basic Facilities of a Virtio Device / Virtqueues / Virtqueue Reset_.
172 #[doc(alias = "VIRTIO_F_RING_RESET")]
173 const RING_RESET = 1 << 40;
174 }
175}
176
177impl AsRef<F> for F {
178 fn as_ref(&self) -> &F {
179 self
180 }
181}
182
183impl AsMut<F> for F {
184 fn as_mut(&mut self) -> &mut F {
185 self
186 }
187}
188
189impl FeatureBits for F {}
190
191macro_rules! feature_bits {
192 (
193 $(#[$outer:meta])*
194 $vis:vis struct $BitFlags:ident: $T:ty {
195 $(
196 $(#[$inner:ident $($args:tt)*])*
197 const $Flag:tt = $value:expr;
198 )*
199 }
200
201 $($t:tt)*
202 ) => {
203 endian_bitflags! {
204 $(#[$outer])*
205 $vis struct $BitFlags: $T {
206 $(
207 $(#[$inner $($args)*])*
208 const $Flag = $value;
209 )*
210
211 /// Device-independent Bit. See [`virtio::F::INDIRECT_DESC`](crate::F::INDIRECT_DESC).
212 const INDIRECT_DESC = $crate::F::INDIRECT_DESC.bits().to_ne();
213
214 /// Device-independent Bit. See [`virtio::F::EVENT_IDX`](crate::F::EVENT_IDX).
215 const EVENT_IDX = $crate::F::EVENT_IDX.bits().to_ne();
216
217 /// Device-independent Bit. See [`virtio::F::VERSION_1`](crate::F::VERSION_1).
218 const VERSION_1 = $crate::F::VERSION_1.bits().to_ne();
219
220 /// Device-independent Bit. See [`virtio::F::ACCESS_PLATFORM`](crate::F::ACCESS_PLATFORM).
221 const ACCESS_PLATFORM = $crate::F::ACCESS_PLATFORM.bits().to_ne();
222
223 /// Device-independent Bit. See [`virtio::F::RING_PACKED`](crate::F::RING_PACKED).
224 const RING_PACKED = $crate::F::RING_PACKED.bits().to_ne();
225
226 /// Device-independent Bit. See [`virtio::F::IN_ORDER`](crate::F::IN_ORDER).
227 const IN_ORDER = $crate::F::IN_ORDER.bits().to_ne();
228
229 /// Device-independent Bit. See [`virtio::F::ORDER_PLATFORM`](crate::F::ORDER_PLATFORM).
230 const ORDER_PLATFORM = $crate::F::ORDER_PLATFORM.bits().to_ne();
231
232 /// Device-independent Bit. See [`virtio::F::SR_IOV`](crate::F::SR_IOV).
233 const SR_IOV = $crate::F::SR_IOV.bits().to_ne();
234
235 /// Device-independent Bit. See [`virtio::F::NOTIFICATION_DATA`](crate::F::NOTIFICATION_DATA).
236 const NOTIFICATION_DATA = $crate::F::NOTIFICATION_DATA.bits().to_ne();
237
238 /// Device-independent Bit. See [`virtio::F::NOTIF_CONFIG_DATA`](crate::F::NOTIF_CONFIG_DATA).
239 const NOTIF_CONFIG_DATA = $crate::F::NOTIF_CONFIG_DATA.bits().to_ne();
240
241 /// Device-independent Bit. See [`virtio::F::RING_RESET`](crate::F::RING_RESET).
242 const RING_RESET = $crate::F::RING_RESET.bits().to_ne();
243 }
244 }
245
246 impl From<$crate::F> for $BitFlags {
247 fn from(value: $crate::F) -> Self {
248 Self::from_bits_retain(value.bits())
249 }
250 }
251
252 impl AsRef<$BitFlags> for $crate::F {
253 fn as_ref(&self) -> &$BitFlags {
254 unsafe { &*(self as *const Self as *const $BitFlags) }
255 }
256 }
257
258 impl AsMut<$BitFlags> for $crate::F {
259 fn as_mut(&mut self) -> &mut $BitFlags {
260 unsafe { &mut *(self as *mut Self as *mut $BitFlags) }
261 }
262 }
263
264 impl From<$BitFlags> for $crate::F {
265 /// Returns the device-independent feature bits while retaining device-specific feature bits.
266 fn from(value: $BitFlags) -> Self {
267 $crate::F::from_bits_retain(value.bits())
268 }
269 }
270
271 impl AsRef<$crate::F> for $BitFlags {
272 /// Returns a shared reference to the device-independent features while retaining device-specific feature bits.
273 fn as_ref(&self) -> &$crate::F {
274 unsafe { &*(self as *const Self as *const $crate::F) }
275 }
276 }
277
278 impl AsMut<$crate::F> for $BitFlags {
279 /// Returns a mutable reference to the device-independent features while retaining device-specific feature bits.
280 fn as_mut(&mut self) -> &mut $crate::F {
281 unsafe { &mut *(self as *mut Self as *mut $crate::F) }
282 }
283 }
284
285 feature_bits! {
286 $($t)*
287 }
288 };
289 () => {};
290}
291
292pub mod console {
293 use crate::le128;
294
295 feature_bits! {
296 /// Console Device Feature Bits
297 #[doc(alias = "VIRTIO_CONSOLE_F")]
298 pub struct F: le128 {
299 /// Configuration `cols` and `rows` are valid.
300 #[doc(alias = "VIRTIO_CONSOLE_F_SIZE")]
301 const SIZE = 1 << 0;
302
303 /// Device has support for multiple ports;
304 ///
305 /// `max_nr_ports` is valid and control virtqueues will be used.
306 #[doc(alias = "VIRTIO_CONSOLE_F_MULTIPORT")]
307 const MULTIPORT = 1 << 1;
308
309 /// Device has support for emergency write.
310 ///
311 /// Configuration field emerg_wr is valid.
312 #[doc(alias = "VIRTIO_CONSOLE_F_EMERG_WRITE")]
313 const EMERG_WRITE = 1 << 2;
314 }
315 }
316
317 impl crate::FeatureBits for F {}
318}
319
320pub mod net {
321 use crate::le128;
322
323 feature_bits! {
324 /// Network Device Feature Bits
325 #[doc(alias = "VIRTIO_NET_F")]
326 pub struct F: le128 {
327 /// Device handles packets with partial checksum. This
328 /// “checksum offload” is a common feature on modern network cards.
329 #[doc(alias = "VIRTIO_NET_F_CSUM")]
330 const CSUM = 1 << 0;
331
332 /// Driver handles packets with partial checksum.
333 #[doc(alias = "VIRTIO_NET_F_GUEST_CSUM")]
334 const GUEST_CSUM = 1 << 1;
335
336 /// Control channel offloads
337 /// reconfiguration support.
338 #[doc(alias = "VIRTIO_NET_F_CTRL_GUEST_OFFLOADS")]
339 const CTRL_GUEST_OFFLOADS = 1 << 2;
340
341 /// Device maximum MTU reporting is supported. If
342 /// offered by the device, device advises driver about the value of
343 /// its maximum MTU. If negotiated, the driver uses _mtu_ as
344 /// the maximum MTU value.
345 #[doc(alias = "VIRTIO_NET_F_MTU")]
346 const MTU = 1 << 3;
347
348 /// Device has given MAC address.
349 #[doc(alias = "VIRTIO_NET_F_MAC")]
350 const MAC = 1 << 5;
351
352 /// Driver can receive TSOv4.
353 #[doc(alias = "VIRTIO_NET_F_GUEST_TSO4")]
354 const GUEST_TSO4 = 1 << 7;
355
356 /// Driver can receive TSOv6.
357 #[doc(alias = "VIRTIO_NET_F_GUEST_TSO6")]
358 const GUEST_TSO6 = 1 << 8;
359
360 /// Driver can receive TSO with ECN.
361 #[doc(alias = "VIRTIO_NET_F_GUEST_ECN")]
362 const GUEST_ECN = 1 << 9;
363
364 /// Driver can receive UFO.
365 #[doc(alias = "VIRTIO_NET_F_GUEST_UFO")]
366 const GUEST_UFO = 1 << 10;
367
368 /// Device can receive TSOv4.
369 #[doc(alias = "VIRTIO_NET_F_HOST_TSO4")]
370 const HOST_TSO4 = 1 << 11;
371
372 /// Device can receive TSOv6.
373 #[doc(alias = "VIRTIO_NET_F_HOST_TSO6")]
374 const HOST_TSO6 = 1 << 12;
375
376 /// Device can receive TSO with ECN.
377 #[doc(alias = "VIRTIO_NET_F_HOST_ECN")]
378 const HOST_ECN = 1 << 13;
379
380 /// Device can receive UFO.
381 #[doc(alias = "VIRTIO_NET_F_HOST_UFO")]
382 const HOST_UFO = 1 << 14;
383
384 /// Driver can merge receive buffers.
385 #[doc(alias = "VIRTIO_NET_F_MRG_RXBUF")]
386 const MRG_RXBUF = 1 << 15;
387
388 /// Configuration status field is
389 /// available.
390 #[doc(alias = "VIRTIO_NET_F_STATUS")]
391 const STATUS = 1 << 16;
392
393 /// Control channel is available.
394 #[doc(alias = "VIRTIO_NET_F_CTRL_VQ")]
395 const CTRL_VQ = 1 << 17;
396
397 /// Control channel RX mode support.
398 #[doc(alias = "VIRTIO_NET_F_CTRL_RX")]
399 const CTRL_RX = 1 << 18;
400
401 /// Control channel VLAN filtering.
402 #[doc(alias = "VIRTIO_NET_F_CTRL_VLAN")]
403 const CTRL_VLAN = 1 << 19;
404
405 /// Driver can send gratuitous
406 /// packets.
407 #[doc(alias = "VIRTIO_NET_F_GUEST_ANNOUNCE")]
408 const GUEST_ANNOUNCE = 1 << 21;
409
410 /// Device supports multiqueue with automatic
411 /// receive steering.
412 #[doc(alias = "VIRTIO_NET_F_MQ")]
413 const MQ = 1 << 22;
414
415 /// Set MAC address through control
416 /// channel.
417 #[doc(alias = "VIRTIO_NET_F_CTRL_MAC_ADDR")]
418 const CTRL_MAC_ADDR = 1 << 23;
419
420 /// Device can receive USO packets. Unlike UFO
421 /// (fragmenting the packet) the USO splits large UDP packet
422 /// to several segments when each of these smaller packets has UDP header.
423 #[doc(alias = "VIRTIO_NET_F_HOST_USO")]
424 const HOST_USO = 1 << 56;
425
426 /// Device can report per-packet hash
427 /// value and a type of calculated hash.
428 #[doc(alias = "VIRTIO_NET_F_HASH_REPORT")]
429 const HASH_REPORT = 1 << 57;
430
431 /// Driver can provide the exact _hdr_len_
432 /// value. Device benefits from knowing the exact header length.
433 #[doc(alias = "VIRTIO_NET_F_GUEST_HDRLEN")]
434 const GUEST_HDRLEN = 1 << 59;
435
436 /// Device supports RSS (receive-side scaling)
437 /// with Toeplitz hash calculation and configurable hash
438 /// parameters for receive steering.
439 #[doc(alias = "VIRTIO_NET_F_RSS")]
440 const RSS = 1 << 60;
441
442 /// Device can process duplicated ACKs
443 /// and report number of coalesced segments and duplicated ACKs.
444 #[doc(alias = "VIRTIO_NET_F_RSC_EXT")]
445 const RSC_EXT = 1 << 61;
446
447 /// Device may act as a standby for a primary
448 /// device with the same MAC address.
449 #[doc(alias = "VIRTIO_NET_F_STANDBY")]
450 const STANDBY = 1 << 62;
451
452 /// Device reports speed and duplex.
453 #[doc(alias = "VIRTIO_NET_F_SPEED_DUPLEX")]
454 const SPEED_DUPLEX = 1 << 63;
455 }
456 }
457
458 impl crate::FeatureBits for F {
459 fn requirements(&self) -> Self {
460 let mut requirements = Self::empty();
461
462 for feature in self.iter() {
463 let requirement = match feature {
464 Self::GUEST_TSO4 => Self::GUEST_CSUM,
465 Self::GUEST_TSO6 => Self::GUEST_CSUM,
466 Self::GUEST_ECN => Self::GUEST_TSO4 | Self::GUEST_TSO6,
467 Self::GUEST_UFO => Self::GUEST_CSUM,
468 Self::HOST_TSO4 => Self::CSUM,
469 Self::HOST_TSO6 => Self::CSUM,
470 Self::HOST_ECN => Self::HOST_TSO4 | Self::HOST_TSO6,
471 Self::HOST_UFO => Self::CSUM,
472 Self::HOST_USO => Self::CSUM,
473 Self::CTRL_RX => Self::CTRL_VQ,
474 Self::CTRL_VLAN => Self::CTRL_VQ,
475 Self::GUEST_ANNOUNCE => Self::CTRL_VQ,
476 Self::MQ => Self::CTRL_VQ,
477 Self::CTRL_MAC_ADDR => Self::CTRL_VQ,
478 Self::RSC_EXT => Self::HOST_TSO4 | Self::HOST_TSO6,
479 Self::RSS => Self::CTRL_VQ,
480 _ => Self::empty(),
481 };
482 requirements.insert(requirement);
483 }
484
485 requirements
486 }
487 }
488}
489
490pub mod fs {
491 use crate::le128;
492
493 feature_bits! {
494 /// File System Device Feature Bits
495 #[doc(alias = "VIRTIO_FS_F")]
496 pub struct F: le128 {
497 /// Device has support for FUSE notify
498 /// messages. The notification queue is virtqueue 1.
499 #[doc(alias = "VIRTIO_FS_F_NOTIFICATION")]
500 const NOTIFICATION = 1 << 0;
501 }
502 }
503
504 impl crate::FeatureBits for F {}
505}
506
507pub mod vsock {
508 use crate::le128;
509
510 feature_bits! {
511 /// Socket Device Feature Bits
512 #[doc(alias = "VIRTIO_VSOCK_F")]
513 pub struct F: le128 {
514 /// stream socket type is supported.
515 #[doc(alias = "VIRTIO_VSOCK_F_STREAM")]
516 const STREAM = 1 << 0;
517
518 /// seqpacket socket type is supported.
519 #[doc(alias = "VIRTIO_VSOCK_F_SEQPACKET")]
520 const SEQPACKET = 1 << 1;
521 }
522 }
523
524 impl crate::FeatureBits for F {}
525}
526
527#[cfg(test)]
528mod tests {
529 use super::*;
530
531 #[rustfmt::skip]
532 #[test]
533 fn requirements_satisfied() {
534 assert!(F::INDIRECT_DESC.requirements_satisfied());
535
536 assert!(net::F::CSUM.requirements_satisfied());
537
538 assert!(!net::F::MQ.requirements_satisfied());
539 assert!((net::F::MQ | net::F::CTRL_VQ).requirements_satisfied());
540
541 assert!(!net::F::HOST_TSO4.requirements_satisfied());
542 assert!((net::F::HOST_TSO4 | net::F::CSUM).requirements_satisfied());
543 assert!((net::F::HOST_TSO4 | net::F::HOST_TSO6 | net::F::CSUM).requirements_satisfied());
544
545 assert!(!net::F::HOST_ECN.requirements_satisfied());
546 assert!(!(net::F::HOST_ECN | net::F::CSUM).requirements_satisfied());
547 assert!(!(net::F::HOST_ECN | net::F::HOST_TSO4).requirements_satisfied());
548 assert!((net::F::HOST_ECN | net::F::HOST_TSO4 | net::F::CSUM).requirements_satisfied());
549 assert!((net::F::HOST_ECN | net::F::HOST_TSO4 | net::F::HOST_TSO6 | net::F::CSUM).requirements_satisfied());
550 }
551}