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}