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