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