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}