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