virtio/queues/
mod.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! VirtIO Virtqueues.
6//!
7//! This module and its submodules provide abstractions for and
8//! implementations of VirtIO Virtqueues. For more information, see
9//! the documentation of the [`Virtqueue`] trait.
10
11pub mod split_queue;
12
13/// A set of addresses representing a Virtqueue in memory.
14pub struct VirtqueueAddresses {
15    pub descriptor_area: u64,
16    pub driver_area: u64,
17    pub device_area: u64,
18}
19
20/// A VirtIO Virtqueue.
21///
22/// Virtqueues are VirtIO's mechanism to exchange data between a host and a
23/// guest. Each queue instance provides a bidirectional communication channel to
24/// send data from the guest (VirtIO driver) to the host (VirtIO device) and
25/// back. Typically, a given Virtqueue is only used for communication in a
26/// single direction. A VirtIO device can support multiple Virtqueues.
27///
28/// Fundamentally, every Virtqueue refers to three distinct regions in memory:
29///
30/// - the **descriptor area**: this memory region contains an array of so-called
31///   Virtqueue descriptors. Each descriptor is a data structure containing
32///   metadata concerning a buffer shared by the guest (VirtIO driver) into the
33///   Virtqueue, such as its guest-physical address in memory and
34///   length. Multiple shared buffers in distinct memory locations can be
35///   chained into a single buffer.
36///
37/// - the **available ring**: this available ring is a data structure maintained
38///   by the guest (VirtIO driver). It contains a ring-buffer which is used for
39///   the guest to share descriptors (as maintained in the _descriptor area_)
40///   with the host (VirtIO device).
41///
42/// - the **used ring**: buffers shared with the host (VirtIO device) will
43///   eventually be returned to the guest (VirtIO driver) by the device placing
44///   them into the used ring. The host will further issue an interrupt, which
45///   shall be routed to the Virtqueue by means of the
46///   [`Virtqueue::used_interrupt`] method.
47pub trait Virtqueue {
48    /// Negotiate the number of used descriptors in the Virtqueue.
49    ///
50    /// The method is presented with the maximum number of queue elements the
51    /// intended device can support. The method must return a value smaller or
52    /// equal than `device_max_elements`. The device's addresses as returned by
53    /// [`Virtqueue::physical_addresses`] after Virtqueue initialization must
54    /// have a memory layout adhering to the [Virtual I/O Device (VIRTIO)
55    /// Specification, Version
56    /// 1.1](https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html),
57    /// for at least the returned number of queue elements.
58    ///
59    /// This method may be called any number of times before initialization of
60    /// the [`Virtqueue`]. Only its latest returned value is valid and must be
61    /// passed to [`Virtqueue::initialize`].
62    fn negotiate_queue_size(&self, device_max_elements: usize) -> usize;
63
64    /// Initialize the Virtqueue.
65    ///
66    /// This method must bring the Virtqueue into a state where it can be
67    /// exposed to a VirtIO transport based on the return value of
68    /// [`Virtqueue::physical_addresses`]. A Virtqueue must refuse operations
69    /// which require it to be initialized until this method has been called.
70    ///
71    /// The passed `queue_number` must identify the queue to the device. After
72    /// returning from [`Virtqueue::initialize`], calls into the Virtqueue
73    /// (except for [`Virtqueue::physical_addresses`]) may attempt to
74    /// communicate with the VirtIO device referencing this passed
75    /// `queue_number`. In practice, this means that the VirtIO device should be
76    /// made aware of this [`Virtqueue`] promptly after calling this method, at
77    /// least before invoking [`Virtqueue::used_interrupt`].
78    ///
79    /// The provided `queue_elements` is the latest negotiated queue size, as
80    /// returned by [`Virtqueue::negotiate_queue_size`].
81    fn initialize(&self, queue_number: u32, queue_elements: usize);
82
83    /// The physical addresses of the Virtqueue descriptors, available and used ring.
84    ///
85    /// The returned addresses and their memory contents must adhere to the
86    /// [Virtual I/O Device (VIRTIO) Specification, Version
87    /// 1.1](https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html)
88    ///
89    /// This method must not be called before the Virtqueue has been
90    /// initialized.
91    fn physical_addresses(&self) -> VirtqueueAddresses;
92
93    /// Interrupt indicating that a VirtIO device may have placed a buffer into
94    /// this Virtqueue's used ring.
95    ///
96    /// A [`Virtqueue`] must be tolerant of spurious calls to this method.
97    fn used_interrupt(&self);
98}