virtio_queue/
lib.rs

1// Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2//
3// Portions Copyright 2017 The Chromium OS Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE-BSD-3-Clause file.
6//
7// Copyright © 2019 Intel Corporation
8//
9// Copyright (C) 2020-2021 Alibaba Cloud. All rights reserved.
10//
11// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
12
13//! Virtio queue API for backend device drivers to access virtio queues.
14
15#![deny(missing_docs)]
16
17use std::fmt::{self, Debug, Display};
18use std::num::Wrapping;
19use std::ops::{Deref, DerefMut};
20use std::sync::atomic::Ordering;
21
22use log::error;
23use vm_memory::{GuestMemory, GuestMemoryError, VolatileMemoryError};
24
25pub use self::chain::{DescriptorChain, DescriptorChainRwIter};
26pub use self::descriptor_utils::{Reader, Writer};
27pub use self::queue::{AvailIter, Queue};
28pub use self::queue_sync::QueueSync;
29pub use self::state::QueueState;
30
31pub mod defs;
32pub mod desc;
33#[cfg(any(test, feature = "test-utils"))]
34pub mod mock;
35
36mod chain;
37mod descriptor_utils;
38mod queue;
39mod queue_sync;
40mod state;
41
42/// Virtio Queue related errors.
43#[derive(Debug)]
44pub enum Error {
45    /// Address overflow.
46    AddressOverflow,
47    /// Failed to access guest memory.
48    GuestMemory(GuestMemoryError),
49    /// Invalid indirect descriptor.
50    InvalidIndirectDescriptor,
51    /// Invalid indirect descriptor table.
52    InvalidIndirectDescriptorTable,
53    /// Invalid descriptor chain.
54    InvalidChain,
55    /// Invalid descriptor index.
56    InvalidDescriptorIndex,
57    /// Invalid max_size.
58    InvalidMaxSize,
59    /// Invalid Queue Size.
60    InvalidSize,
61    /// Invalid alignment of descriptor table address.
62    InvalidDescTableAlign,
63    /// Invalid alignment of available ring address.
64    InvalidAvailRingAlign,
65    /// Invalid alignment of used ring address.
66    InvalidUsedRingAlign,
67    /// Invalid available ring index.
68    InvalidAvailRingIndex,
69    /// The queue is not ready for operation.
70    QueueNotReady,
71    /// Volatile memory error.
72    VolatileMemoryError(VolatileMemoryError),
73    /// The combined length of all the buffers in a `DescriptorChain` would overflow.
74    DescriptorChainOverflow,
75    /// No memory region for this address range.
76    FindMemoryRegion,
77    /// Descriptor guest memory error.
78    GuestMemoryError(GuestMemoryError),
79    /// DescriptorChain split is out of bounds.
80    SplitOutOfBounds(usize),
81}
82
83impl Display for Error {
84    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85        use self::Error::*;
86
87        match self {
88            AddressOverflow => write!(f, "address overflow"),
89            GuestMemory(_) => write!(f, "error accessing guest memory"),
90            InvalidChain => write!(f, "invalid descriptor chain"),
91            InvalidIndirectDescriptor => write!(f, "invalid indirect descriptor"),
92            InvalidIndirectDescriptorTable => write!(f, "invalid indirect descriptor table"),
93            InvalidDescriptorIndex => write!(f, "invalid descriptor index"),
94            InvalidMaxSize => write!(f, "invalid queue maximum size"),
95            InvalidSize => write!(f, "invalid queue size"),
96            InvalidDescTableAlign => write!(
97                f,
98                "virtio queue descriptor table breaks alignment constraints"
99            ),
100            InvalidAvailRingAlign => write!(
101                f,
102                "virtio queue available ring breaks alignment constraints"
103            ),
104            InvalidUsedRingAlign => {
105                write!(f, "virtio queue used ring breaks alignment constraints")
106            }
107            InvalidAvailRingIndex => write!(
108                f,
109                "invalid available ring index (more descriptors to process than queue size)"
110            ),
111            QueueNotReady => write!(f, "trying to process requests on a queue that's not ready"),
112            VolatileMemoryError(e) => write!(f, "volatile memory error: {e}"),
113            DescriptorChainOverflow => write!(
114                f,
115                "the combined length of all the buffers in a `DescriptorChain` would overflow"
116            ),
117            FindMemoryRegion => write!(f, "no memory region for this address range"),
118            GuestMemoryError(e) => write!(f, "descriptor guest memory error: {e}"),
119            SplitOutOfBounds(off) => write!(f, "`DescriptorChain` split is out of bounds: {off}"),
120        }
121    }
122}
123
124impl std::error::Error for Error {}
125
126/// Trait for objects returned by `QueueT::lock()`.
127pub trait QueueGuard<'a> {
128    /// Type for guard returned by `Self::lock()`.
129    type G: DerefMut<Target = Queue>;
130}
131
132/// Trait to access and manipulate a virtio queue.
133///
134/// To optimize for performance, different implementations of the `QueueT` trait may be
135/// provided for single-threaded context and multi-threaded context.
136///
137/// Using Higher-Rank Trait Bounds (HRTBs) to effectively define an associated type that has a
138/// lifetime parameter, without tagging the `QueueT` trait with a lifetime as well.
139pub trait QueueT: for<'a> QueueGuard<'a> {
140    /// Construct an empty virtio queue state object with the given `max_size`.
141    ///
142    /// Returns an error if `max_size` is invalid.
143    fn new(max_size: u16) -> Result<Self, Error>
144    where
145        Self: Sized;
146
147    /// Check whether the queue configuration is valid.
148    fn is_valid<M: GuestMemory>(&self, mem: &M) -> bool;
149
150    /// Reset the queue to the initial state.
151    fn reset(&mut self);
152
153    /// Get an exclusive reference to the underlying `Queue` object.
154    ///
155    /// Logically this method will acquire the underlying lock protecting the `Queue` Object.
156    /// The lock will be released when the returned object gets dropped.
157    fn lock(&mut self) -> <Self as QueueGuard<'_>>::G;
158
159    /// Get the maximum size of the virtio queue.
160    fn max_size(&self) -> u16;
161
162    /// Get the actual size configured by the guest.
163    fn size(&self) -> u16;
164
165    /// Configure the queue size for the virtio queue.
166    fn set_size(&mut self, size: u16);
167
168    /// Check whether the queue is ready to be processed.
169    fn ready(&self) -> bool;
170
171    /// Configure the queue to `ready for processing` state.
172    fn set_ready(&mut self, ready: bool);
173
174    /// Set the descriptor table address for the queue.
175    ///
176    /// The descriptor table address is 64-bit, the corresponding part will be updated if 'low'
177    /// and/or `high` is `Some` and valid.
178    fn set_desc_table_address(&mut self, low: Option<u32>, high: Option<u32>);
179
180    /// Set the available ring address for the queue.
181    ///
182    /// The available ring address is 64-bit, the corresponding part will be updated if 'low'
183    /// and/or `high` is `Some` and valid.
184    fn set_avail_ring_address(&mut self, low: Option<u32>, high: Option<u32>);
185
186    /// Set the used ring address for the queue.
187    ///
188    /// The used ring address is 64-bit, the corresponding part will be updated if 'low'
189    /// and/or `high` is `Some` and valid.
190    fn set_used_ring_address(&mut self, low: Option<u32>, high: Option<u32>);
191
192    /// Enable/disable the VIRTIO_F_RING_EVENT_IDX feature for interrupt coalescing.
193    fn set_event_idx(&mut self, enabled: bool);
194
195    /// Read the `idx` field from the available ring.
196    ///
197    /// # Panics
198    ///
199    /// Panics if order is Release or AcqRel.
200    fn avail_idx<M>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error>
201    where
202        M: GuestMemory + ?Sized;
203
204    /// Read the `idx` field from the used ring.
205    ///
206    /// # Panics
207    ///
208    /// Panics if order is Release or AcqRel.
209    fn used_idx<M: GuestMemory>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error>;
210
211    /// Put a used descriptor head into the used ring.
212    fn add_used<M: GuestMemory>(&mut self, mem: &M, head_index: u16, len: u32)
213        -> Result<(), Error>;
214
215    /// Enable notification events from the guest driver.
216    ///
217    /// Return true if one or more descriptors can be consumed from the available ring after
218    /// notifications were enabled (and thus it's possible there will be no corresponding
219    /// notification).
220    fn enable_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<bool, Error>;
221
222    /// Disable notification events from the guest driver.
223    fn disable_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<(), Error>;
224
225    /// Check whether a notification to the guest is needed.
226    ///
227    /// Please note this method has side effects: once it returns `true`, it considers the
228    /// driver will actually be notified, remember the associated index in the used ring, and
229    /// won't return `true` again until the driver updates `used_event` and/or the notification
230    /// conditions hold once more.
231    fn needs_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<bool, Error>;
232
233    /// Return the index of the next entry in the available ring.
234    fn next_avail(&self) -> u16;
235
236    /// Set the index of the next entry in the available ring.
237    fn set_next_avail(&mut self, next_avail: u16);
238
239    /// Return the index for the next descriptor in the used ring.
240    fn next_used(&self) -> u16;
241
242    /// Set the index for the next descriptor in the used ring.
243    fn set_next_used(&mut self, next_used: u16);
244
245    /// Return the address of the descriptor table.
246    fn desc_table(&self) -> u64;
247
248    /// Return the address of the available ring.
249    fn avail_ring(&self) -> u64;
250
251    /// Return the address of the used ring.
252    fn used_ring(&self) -> u64;
253
254    /// Checks whether `VIRTIO_F_RING_EVENT_IDX` is negotiated.
255    ///
256    /// This getter is only returning the correct value after the device passes the `FEATURES_OK`
257    /// status.
258    fn event_idx_enabled(&self) -> bool;
259
260    /// Pop and return the next available descriptor chain, or `None` when there are no more
261    /// descriptor chains available.
262    ///
263    /// This enables the consumption of available descriptor chains in a "one at a time"
264    /// manner, without having to hold a borrow after the method returns.
265    fn pop_descriptor_chain<M>(&mut self, mem: M) -> Option<DescriptorChain<M>>
266    where
267        M: Clone + Deref,
268        M::Target: GuestMemory;
269}
270
271/// Trait to access and manipulate a Virtio queue that's known to be exclusively accessed
272/// by a single execution thread.
273pub trait QueueOwnedT: QueueT {
274    /// Get a consuming iterator over all available descriptor chain heads offered by the driver.
275    ///
276    /// # Arguments
277    /// * `mem` - the `GuestMemory` object that can be used to access the queue buffers.
278    fn iter<M>(&mut self, mem: M) -> Result<AvailIter<'_, M>, Error>
279    where
280        M: Deref,
281        M::Target: GuestMemory;
282
283    /// Undo the last advancement of the next available index field by decrementing its
284    /// value by one.
285    fn go_to_previous_position(&mut self);
286}