• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 //! virtqueue interface
6 
7 #![deny(missing_docs)]
8 
9 use std::ops::Deref;
10 use std::ops::DerefMut;
11 
12 pub mod packed_descriptor_chain;
13 mod packed_queue;
14 pub mod split_descriptor_chain;
15 mod split_queue;
16 
17 use std::num::Wrapping;
18 
19 use anyhow::bail;
20 use anyhow::Context;
21 use anyhow::Result;
22 use base::warn;
23 use base::Event;
24 use cros_async::AsyncError;
25 use cros_async::EventAsync;
26 use futures::channel::oneshot;
27 use futures::select_biased;
28 use futures::FutureExt;
29 use packed_queue::PackedQueue;
30 use serde::Deserialize;
31 use serde::Serialize;
32 use split_queue::SplitQueue;
33 use virtio_sys::virtio_config::VIRTIO_F_RING_PACKED;
34 use vm_memory::GuestAddress;
35 use vm_memory::GuestMemory;
36 
37 use crate::virtio::DescriptorChain;
38 use crate::virtio::Interrupt;
39 use crate::virtio::VIRTIO_MSI_NO_VECTOR;
40 
41 /// A virtio queue's parameters.
42 ///
43 /// `QueueConfig` can be converted into a running `Queue` by calling [`QueueConfig::activate()`].
44 pub struct QueueConfig {
45     /// Whether this queue has already been activated.
46     activated: bool,
47 
48     /// The maximal size in elements offered by the device
49     max_size: u16,
50 
51     /// The queue size in elements the driver selected. This is always guaranteed to be a power of
52     /// two less than or equal to `max_size`, as required for split virtqueues. These invariants
53     /// are enforced by `set_size()`.
54     size: u16,
55 
56     /// Indicates if the queue is finished with configuration
57     ready: bool,
58 
59     /// MSI-X vector for the queue. Don't care for INTx
60     vector: u16,
61 
62     /// Ring features (e.g. `VIRTIO_RING_F_EVENT_IDX`, `VIRTIO_F_RING_PACKED`) offered by the
63     /// device
64     features: u64,
65 
66     // Device feature bits accepted by the driver
67     acked_features: u64,
68 
69     /// Guest physical address of the descriptor table
70     desc_table: GuestAddress,
71 
72     /// Guest physical address of the available ring (driver area)
73     ///
74     /// TODO(b/290657008): update field and accessor names to match the current virtio spec
75     avail_ring: GuestAddress,
76 
77     /// Guest physical address of the used ring (device area)
78     used_ring: GuestAddress,
79 
80     /// Initial available ring index when the queue is activated.
81     next_avail: Wrapping<u16>,
82 
83     /// Initial used ring index when the queue is activated.
84     next_used: Wrapping<u16>,
85 }
86 
87 #[derive(Serialize, Deserialize)]
88 struct QueueConfigSnapshot {
89     activated: bool,
90     max_size: u16,
91     size: u16,
92     ready: bool,
93     vector: u16,
94     features: u64,
95     acked_features: u64,
96     desc_table: GuestAddress,
97     avail_ring: GuestAddress,
98     used_ring: GuestAddress,
99     next_avail: Wrapping<u16>,
100     next_used: Wrapping<u16>,
101 }
102 
103 impl QueueConfig {
104     /// Constructs a virtio queue configuration with the given `max_size`.
new(max_size: u16, features: u64) -> Self105     pub fn new(max_size: u16, features: u64) -> Self {
106         assert!(max_size > 0);
107         assert!(max_size <= Queue::MAX_SIZE);
108         QueueConfig {
109             activated: false,
110             max_size,
111             size: max_size,
112             ready: false,
113             vector: VIRTIO_MSI_NO_VECTOR,
114             desc_table: GuestAddress(0),
115             avail_ring: GuestAddress(0),
116             used_ring: GuestAddress(0),
117             features,
118             acked_features: 0,
119             next_used: Wrapping(0),
120             next_avail: Wrapping(0),
121         }
122     }
123 
124     /// Returns the maximum size of this queue.
max_size(&self) -> u16125     pub fn max_size(&self) -> u16 {
126         self.max_size
127     }
128 
129     /// Returns the currently configured size of the queue.
size(&self) -> u16130     pub fn size(&self) -> u16 {
131         self.size
132     }
133 
134     /// Sets the queue size.
set_size(&mut self, val: u16)135     pub fn set_size(&mut self, val: u16) {
136         if self.ready {
137             warn!("ignoring write to size on ready queue");
138             return;
139         }
140 
141         if val > self.max_size {
142             warn!(
143                 "requested queue size {} is larger than max_size {}",
144                 val, self.max_size
145             );
146             return;
147         }
148 
149         self.size = val;
150     }
151 
152     /// Returns the currently configured interrupt vector.
vector(&self) -> u16153     pub fn vector(&self) -> u16 {
154         self.vector
155     }
156 
157     /// Sets the interrupt vector for this queue.
set_vector(&mut self, val: u16)158     pub fn set_vector(&mut self, val: u16) {
159         if self.ready {
160             warn!("ignoring write to vector on ready queue");
161             return;
162         }
163 
164         self.vector = val;
165     }
166 
167     /// Getter for descriptor area
desc_table(&self) -> GuestAddress168     pub fn desc_table(&self) -> GuestAddress {
169         self.desc_table
170     }
171 
172     /// Setter for descriptor area
set_desc_table(&mut self, val: GuestAddress)173     pub fn set_desc_table(&mut self, val: GuestAddress) {
174         if self.ready {
175             warn!("ignoring write to desc_table on ready queue");
176             return;
177         }
178 
179         self.desc_table = val;
180     }
181 
182     /// Getter for driver area
avail_ring(&self) -> GuestAddress183     pub fn avail_ring(&self) -> GuestAddress {
184         self.avail_ring
185     }
186 
187     /// Setter for driver area
set_avail_ring(&mut self, val: GuestAddress)188     pub fn set_avail_ring(&mut self, val: GuestAddress) {
189         if self.ready {
190             warn!("ignoring write to avail_ring on ready queue");
191             return;
192         }
193 
194         self.avail_ring = val;
195     }
196 
197     /// Getter for device area
used_ring(&self) -> GuestAddress198     pub fn used_ring(&self) -> GuestAddress {
199         self.used_ring
200     }
201 
202     /// Setter for device area
set_used_ring(&mut self, val: GuestAddress)203     pub fn set_used_ring(&mut self, val: GuestAddress) {
204         if self.ready {
205             warn!("ignoring write to used_ring on ready queue");
206             return;
207         }
208 
209         self.used_ring = val;
210     }
211 
212     /// Getter for next_avail index
next_avail(&self) -> Wrapping<u16>213     pub fn next_avail(&self) -> Wrapping<u16> {
214         self.next_avail
215     }
216 
217     /// Setter for next_avail index
set_next_avail(&mut self, val: Wrapping<u16>)218     pub fn set_next_avail(&mut self, val: Wrapping<u16>) {
219         if self.ready {
220             warn!("ignoring write to next_avail on ready queue");
221             return;
222         }
223 
224         self.next_avail = val;
225     }
226 
227     /// Getter for next_used index
next_used(&self) -> Wrapping<u16>228     pub fn next_used(&self) -> Wrapping<u16> {
229         self.next_used
230     }
231 
232     /// Setter for next_used index
set_next_used(&mut self, val: Wrapping<u16>)233     pub fn set_next_used(&mut self, val: Wrapping<u16>) {
234         if self.ready {
235             warn!("ignoring write to next_used on ready queue");
236             return;
237         }
238 
239         self.next_used = val;
240     }
241 
242     /// Returns the features that have been acknowledged by the driver.
acked_features(&self) -> u64243     pub fn acked_features(&self) -> u64 {
244         self.acked_features
245     }
246 
247     /// Acknowledges that this set of features should be enabled on this queue.
ack_features(&mut self, features: u64)248     pub fn ack_features(&mut self, features: u64) {
249         self.acked_features |= features & self.features;
250     }
251 
252     /// Return whether the driver has enabled this queue.
ready(&self) -> bool253     pub fn ready(&self) -> bool {
254         self.ready
255     }
256 
257     /// Signal that the driver has completed queue configuration.
set_ready(&mut self, enable: bool)258     pub fn set_ready(&mut self, enable: bool) {
259         self.ready = enable;
260     }
261 
262     /// Convert the queue configuration into an active queue.
activate(&mut self, mem: &GuestMemory, event: Event) -> Result<Queue>263     pub fn activate(&mut self, mem: &GuestMemory, event: Event) -> Result<Queue> {
264         if !self.ready {
265             bail!("attempted to activate a non-ready queue");
266         }
267 
268         if self.activated {
269             bail!("queue is already activated");
270         }
271         // If VIRTIO_F_RING_PACKED feature bit is set, create a packed queue, otherwise create a
272         // split queue
273         let queue: Queue = if ((self.acked_features >> VIRTIO_F_RING_PACKED) & 1) != 0 {
274             let pq =
275                 PackedQueue::new(self, mem, event).context("Failed to create a packed queue.")?;
276             Queue::PackedVirtQueue(pq)
277         } else {
278             let sq =
279                 SplitQueue::new(self, mem, event).context("Failed to create a split queue.")?;
280             Queue::SplitVirtQueue(sq)
281         };
282 
283         self.activated = true;
284         Ok(queue)
285     }
286 
287     /// Reset queue to a clean state
reset(&mut self)288     pub fn reset(&mut self) {
289         self.activated = false;
290         self.ready = false;
291         self.size = self.max_size;
292         self.vector = VIRTIO_MSI_NO_VECTOR;
293         self.desc_table = GuestAddress(0);
294         self.avail_ring = GuestAddress(0);
295         self.used_ring = GuestAddress(0);
296         self.next_avail = Wrapping(0);
297         self.next_used = Wrapping(0);
298         self.acked_features = 0;
299     }
300 
301     /// Take snapshot of queue configuration
snapshot(&self) -> Result<serde_json::Value>302     pub fn snapshot(&self) -> Result<serde_json::Value> {
303         serde_json::to_value(QueueConfigSnapshot {
304             activated: self.activated,
305             max_size: self.max_size,
306             size: self.size,
307             ready: self.ready,
308             vector: self.vector,
309             features: self.features,
310             acked_features: self.acked_features,
311             desc_table: self.desc_table,
312             avail_ring: self.avail_ring,
313             used_ring: self.used_ring,
314             next_avail: self.next_avail,
315             next_used: self.next_used,
316         })
317         .context("error serializing")
318     }
319 
320     /// Restore queue configuration from snapshot
restore(&mut self, data: serde_json::Value) -> Result<()>321     pub fn restore(&mut self, data: serde_json::Value) -> Result<()> {
322         let snap: QueueConfigSnapshot =
323             serde_json::from_value(data).context("error deserializing")?;
324         self.activated = snap.activated;
325         self.max_size = snap.max_size;
326         self.size = snap.size;
327         self.ready = snap.ready;
328         self.vector = snap.vector;
329         self.features = snap.features;
330         self.acked_features = snap.acked_features;
331         self.desc_table = snap.desc_table;
332         self.avail_ring = snap.avail_ring;
333         self.used_ring = snap.used_ring;
334         self.next_avail = snap.next_avail;
335         self.next_used = snap.next_used;
336         Ok(())
337     }
338 }
339 
340 /// Usage: define_queue_method!(method_name, return_type[, mut][, arg1: arg1_type, arg2: arg2_type,
341 /// ...])
342 ///
343 /// - `method_name`: The name of the method to be defined (as an identifier).
344 /// - `return_type`: The return type of the method.
345 /// - `mut` (optional): Include this keyword if the method requires a mutable reference to `self`
346 ///   (`&mut self`).
347 /// - `arg1: arg1_type, arg2: arg2_type, ...` (optional): Include method parameters as a
348 ///   comma-separated list of `name: type` pairs, if the method takes any arguments.
349 macro_rules! define_queue_method {
350     (
351         $(#[$doc:meta])*
352         $method:ident, $return_type:ty, $( $var:ident : $vartype:ty ),*
353     ) => {
354         $(#[$doc])*
355         pub fn $method(&self, $($var: $vartype),*) -> $return_type {
356             match self {
357                 Queue::SplitVirtQueue(sq) => sq.$method($($var),*),
358                 Queue::PackedVirtQueue(pq) => pq.$method($($var),*),
359             }
360         }
361     };
362     (
363         $(#[$doc:meta])*
364         $method:ident, $return_type:ty, mut, $( $var:ident : $vartype:ty ),*
365     ) => {
366         $(#[$doc])*
367         pub fn $method(&mut self, $($var: $vartype),*) -> $return_type {
368             match self {
369                 Queue::SplitVirtQueue(sq) => sq.$method($($var),*),
370                 Queue::PackedVirtQueue(pq) => pq.$method($($var),*),
371             }
372         }
373     };
374 }
375 
376 /// Virtqueue interface representing different types of virtqueues
377 /// The struct of each queue type is wrapped in the enum variants
378 #[derive(Debug)]
379 pub enum Queue {
380     /// Split virtqueue type in virtio v1.2 spec: <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-350007>
381     SplitVirtQueue(SplitQueue),
382     /// Packed virtqueue type in virtio v1.2 spec: <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-720008>
383     PackedVirtQueue(PackedQueue),
384 }
385 
386 impl Queue {
387     /// Largest valid number of entries in a virtqueue.
388     pub const MAX_SIZE: u16 = 32768;
389 
390     /// Asynchronously read the next descriptor chain from the queue.
391     /// Returns a `DescriptorChain` when it is `await`ed.
next_async( &mut self, eventfd: &mut EventAsync, ) -> std::result::Result<DescriptorChain, AsyncError>392     pub async fn next_async(
393         &mut self,
394         eventfd: &mut EventAsync,
395     ) -> std::result::Result<DescriptorChain, AsyncError> {
396         loop {
397             // Check if there are more descriptors available.
398             if let Some(chain) = self.pop() {
399                 return Ok(chain);
400             }
401             eventfd.next_val().await?;
402         }
403     }
404 
405     /// Get the first available descriptor chain without removing it from the queue.
406     /// Call `pop()` on the returned [`PeekedDescriptorChain`] to remove it from the queue.
peek(&mut self) -> Option<PeekedDescriptorChain>407     pub fn peek(&mut self) -> Option<PeekedDescriptorChain> {
408         let desc_chain = match self {
409             Queue::SplitVirtQueue(q) => q.peek(),
410             Queue::PackedVirtQueue(q) => q.peek(),
411         }?;
412 
413         Some(PeekedDescriptorChain::new(self, desc_chain))
414     }
415 
416     /// If a new DescriptorChain is available, returns one and removes it from the queue.
pop(&mut self) -> Option<DescriptorChain>417     pub fn pop(&mut self) -> Option<DescriptorChain> {
418         self.peek().map(PeekedDescriptorChain::pop)
419     }
420 
421     /// Returns `None` if stop_rx receives a value; otherwise returns the result
422     /// of waiting for the next descriptor.
next_async_interruptable( &mut self, queue_event: &mut EventAsync, mut stop_rx: &mut oneshot::Receiver<()>, ) -> std::result::Result<Option<DescriptorChain>, AsyncError>423     pub async fn next_async_interruptable(
424         &mut self,
425         queue_event: &mut EventAsync,
426         mut stop_rx: &mut oneshot::Receiver<()>,
427     ) -> std::result::Result<Option<DescriptorChain>, AsyncError> {
428         select_biased! {
429             avail_desc_res = self.next_async(queue_event).fuse() => {
430                 Ok(Some(avail_desc_res?))
431             }
432             _ = stop_rx => Ok(None),
433         }
434     }
435 
436     /// inject interrupt into guest on this queue
437     /// return true: interrupt is injected into guest for this queue
438     ///        false: interrupt isn't injected
trigger_interrupt(&mut self, interrupt: &Interrupt) -> bool439     pub fn trigger_interrupt(&mut self, interrupt: &Interrupt) -> bool {
440         match self {
441             Queue::SplitVirtQueue(sq) => sq.trigger_interrupt(interrupt),
442             Queue::PackedVirtQueue(pq) => pq.trigger_interrupt(interrupt),
443         }
444     }
445 
446     /// Restore queue from snapshot
restore( queue_config: &QueueConfig, queue_value: serde_json::Value, mem: &GuestMemory, event: Event, ) -> anyhow::Result<Queue>447     pub fn restore(
448         queue_config: &QueueConfig,
449         queue_value: serde_json::Value,
450         mem: &GuestMemory,
451         event: Event,
452     ) -> anyhow::Result<Queue> {
453         if queue_config.acked_features & 1 << VIRTIO_F_RING_PACKED != 0 {
454             PackedQueue::restore(queue_value, mem, event).map(Queue::PackedVirtQueue)
455         } else {
456             SplitQueue::restore(queue_value, mem, event).map(Queue::SplitVirtQueue)
457         }
458     }
459 
460     define_queue_method!(
461         /// Getter for vector field
462         vector,
463         u16,
464     );
465 
466     define_queue_method!(
467         /// Getter for descriptor area
468         desc_table,
469         GuestAddress,
470     );
471 
472     define_queue_method!(
473         /// Getter for driver area
474         avail_ring,
475         GuestAddress,
476     );
477 
478     define_queue_method!(
479         /// Getter for device area
480         used_ring,
481         GuestAddress,
482     );
483 
484     define_queue_method!(
485         /// Return the actual size of the queue, as the driver may not set up a
486         /// queue as big as the device allows.
487         size,
488         u16,
489     );
490 
491     define_queue_method!(
492         /// Get a reference to the queue's event.
493         event,
494         &Event,
495     );
496 
497     define_queue_method!(
498         /// Puts an available descriptor head into the used ring for use by the guest.
499         add_used,
500         (),
501         mut,
502         desc_chain: DescriptorChain,
503         len: u32
504     );
505 
506     define_queue_method!(
507         /// Take snapshot of queue's current status
508         snapshot,
509         Result<serde_json::Value>,
510     );
511 }
512 
513 /// A `DescriptorChain` that has been peeked from a `Queue` but not popped yet.
514 ///
515 /// Call [`pop()`](Self::pop) to pop this descriptor chain from the `Queue` and receive the
516 /// contained `DescriptorChain` object.
517 ///
518 /// This object holds a mutable reference to the `Queue` to ensure it is not possible to pop or peek
519 /// another descriptor while a peek is already active. Either `pop()` or drop this object before
520 /// attempting to manipulate the `Queue` again.
521 pub struct PeekedDescriptorChain<'q> {
522     queue: &'q mut Queue,
523     desc_chain: DescriptorChain,
524 }
525 
526 impl<'q> PeekedDescriptorChain<'q> {
527     /// Create a `PeekedDescriptorChain` that holds a mutable reference to its `Queue`.
528     /// Use [`Queue::peek()`] rather than calling this function.
new(queue: &'q mut Queue, desc_chain: DescriptorChain) -> Self529     fn new(queue: &'q mut Queue, desc_chain: DescriptorChain) -> Self {
530         PeekedDescriptorChain { queue, desc_chain }
531     }
532 
533     /// Pop this descriptor chain from the queue.
pop(self) -> DescriptorChain534     pub fn pop(self) -> DescriptorChain {
535         match self.queue {
536             Queue::SplitVirtQueue(q) => q.pop_peeked(&self.desc_chain),
537             Queue::PackedVirtQueue(q) => q.pop_peeked(&self.desc_chain),
538         }
539         self.desc_chain
540     }
541 }
542 
543 impl Deref for PeekedDescriptorChain<'_> {
544     type Target = DescriptorChain;
545 
deref(&self) -> &Self::Target546     fn deref(&self) -> &Self::Target {
547         &self.desc_chain
548     }
549 }
550 
551 impl DerefMut for PeekedDescriptorChain<'_> {
deref_mut(&mut self) -> &mut Self::Target552     fn deref_mut(&mut self) -> &mut Self::Target {
553         &mut self.desc_chain
554     }
555 }
556