• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, VolatileMemoryError};
24 
25 pub use self::chain::{DescriptorChain, DescriptorChainRwIter};
26 pub use self::descriptor::{Descriptor, VirtqUsedElem};
27 pub use self::descriptor_utils::{Reader, Writer};
28 pub use self::queue::{AvailIter, Queue};
29 pub use self::queue_sync::QueueSync;
30 pub use self::state::QueueState;
31 
32 pub mod defs;
33 #[cfg(any(test, feature = "test-utils"))]
34 pub mod mock;
35 
36 mod chain;
37 mod descriptor;
38 mod descriptor_utils;
39 mod queue;
40 mod queue_sync;
41 mod state;
42 
43 /// Virtio Queue related errors.
44 #[derive(Debug)]
45 pub 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 
84 impl Display for Error {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result85     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 
125 impl std::error::Error for Error {}
126 
127 /// Trait for objects returned by `QueueT::lock()`.
128 pub 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.
140 pub 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.
new(max_size: u16) -> Result<Self, Error> where Self: Sized144     fn new(max_size: u16) -> Result<Self, Error>
145     where
146         Self: Sized;
147 
148     /// Check whether the queue configuration is valid.
is_valid<M: GuestMemory>(&self, mem: &M) -> bool149     fn is_valid<M: GuestMemory>(&self, mem: &M) -> bool;
150 
151     /// Reset the queue to the initial state.
reset(&mut self)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.
lock(&mut self) -> <Self as QueueGuard>::G158     fn lock(&mut self) -> <Self as QueueGuard>::G;
159 
160     /// Get the maximum size of the virtio queue.
max_size(&self) -> u16161     fn max_size(&self) -> u16;
162 
163     /// Get the actual size configured by the guest.
size(&self) -> u16164     fn size(&self) -> u16;
165 
166     /// Configure the queue size for the virtio queue.
set_size(&mut self, size: u16)167     fn set_size(&mut self, size: u16);
168 
169     /// Check whether the queue is ready to be processed.
ready(&self) -> bool170     fn ready(&self) -> bool;
171 
172     /// Configure the queue to `ready for processing` state.
set_ready(&mut self, ready: bool)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.
set_desc_table_address(&mut self, low: Option<u32>, high: Option<u32>)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.
set_avail_ring_address(&mut self, low: Option<u32>, high: Option<u32>)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.
set_used_ring_address(&mut self, low: Option<u32>, high: Option<u32>)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.
set_event_idx(&mut self, enabled: bool)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.
avail_idx<M>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error> where M: GuestMemory + ?Sized201     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.
used_idx<M: GuestMemory>(&self, mem: &M, order: Ordering) -> Result<Wrapping<u16>, Error>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.
add_used<M: GuestMemory>(&mut self, mem: &M, head_index: u16, len: u32) -> Result<(), Error>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).
enable_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<bool, Error>221     fn enable_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<bool, Error>;
222 
223     /// Disable notification events from the guest driver.
disable_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<(), Error>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.
needs_notification<M: GuestMemory>(&mut self, mem: &M) -> Result<bool, Error>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.
next_avail(&self) -> u16235     fn next_avail(&self) -> u16;
236 
237     /// Set the index of the next entry in the available ring.
set_next_avail(&mut self, next_avail: u16)238     fn set_next_avail(&mut self, next_avail: u16);
239 
240     /// Return the index for the next descriptor in the used ring.
next_used(&self) -> u16241     fn next_used(&self) -> u16;
242 
243     /// Set the index for the next descriptor in the used ring.
set_next_used(&mut self, next_used: u16)244     fn set_next_used(&mut self, next_used: u16);
245 
246     /// Return the address of the descriptor table.
desc_table(&self) -> u64247     fn desc_table(&self) -> u64;
248 
249     /// Return the address of the available ring.
avail_ring(&self) -> u64250     fn avail_ring(&self) -> u64;
251 
252     /// Return the address of the used ring.
used_ring(&self) -> u64253     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.
event_idx_enabled(&self) -> bool259     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.
pop_descriptor_chain<M>(&mut self, mem: M) -> Option<DescriptorChain<M>> where M: Clone + Deref, M::Target: GuestMemory266     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.
274 pub 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.
iter<M>(&mut self, mem: M) -> Result<AvailIter<'_, M>, Error> where M: Deref, M::Target: GuestMemory279     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.
go_to_previous_position(&mut self)286     fn go_to_previous_position(&mut self);
287 }
288