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