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