1 // Copyright 2023 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 //! virtqueue interface 6 7 #![deny(missing_docs)] 8 9 use std::ops::Deref; 10 use std::ops::DerefMut; 11 12 pub mod packed_descriptor_chain; 13 mod packed_queue; 14 pub mod split_descriptor_chain; 15 mod split_queue; 16 17 use std::num::Wrapping; 18 19 use anyhow::bail; 20 use anyhow::Context; 21 use anyhow::Result; 22 use base::warn; 23 use base::Event; 24 use cros_async::AsyncError; 25 use cros_async::EventAsync; 26 use futures::channel::oneshot; 27 use futures::select_biased; 28 use futures::FutureExt; 29 use packed_queue::PackedQueue; 30 use serde::Deserialize; 31 use serde::Serialize; 32 use split_queue::SplitQueue; 33 use virtio_sys::virtio_config::VIRTIO_F_RING_PACKED; 34 use vm_memory::GuestAddress; 35 use vm_memory::GuestMemory; 36 37 use crate::virtio::DescriptorChain; 38 use crate::virtio::Interrupt; 39 use crate::virtio::VIRTIO_MSI_NO_VECTOR; 40 41 /// A virtio queue's parameters. 42 /// 43 /// `QueueConfig` can be converted into a running `Queue` by calling [`QueueConfig::activate()`]. 44 pub struct QueueConfig { 45 /// Whether this queue has already been activated. 46 activated: bool, 47 48 /// The maximal size in elements offered by the device 49 max_size: u16, 50 51 /// The queue size in elements the driver selected. This is always guaranteed to be a power of 52 /// two less than or equal to `max_size`, as required for split virtqueues. These invariants 53 /// are enforced by `set_size()`. 54 size: u16, 55 56 /// Indicates if the queue is finished with configuration 57 ready: bool, 58 59 /// MSI-X vector for the queue. Don't care for INTx 60 vector: u16, 61 62 /// Ring features (e.g. `VIRTIO_RING_F_EVENT_IDX`, `VIRTIO_F_RING_PACKED`) offered by the 63 /// device 64 features: u64, 65 66 // Device feature bits accepted by the driver 67 acked_features: u64, 68 69 /// Guest physical address of the descriptor table 70 desc_table: GuestAddress, 71 72 /// Guest physical address of the available ring (driver area) 73 /// 74 /// TODO(b/290657008): update field and accessor names to match the current virtio spec 75 avail_ring: GuestAddress, 76 77 /// Guest physical address of the used ring (device area) 78 used_ring: GuestAddress, 79 80 /// Initial available ring index when the queue is activated. 81 next_avail: Wrapping<u16>, 82 83 /// Initial used ring index when the queue is activated. 84 next_used: Wrapping<u16>, 85 } 86 87 #[derive(Serialize, Deserialize)] 88 struct QueueConfigSnapshot { 89 activated: bool, 90 max_size: u16, 91 size: u16, 92 ready: bool, 93 vector: u16, 94 features: u64, 95 acked_features: u64, 96 desc_table: GuestAddress, 97 avail_ring: GuestAddress, 98 used_ring: GuestAddress, 99 next_avail: Wrapping<u16>, 100 next_used: Wrapping<u16>, 101 } 102 103 impl QueueConfig { 104 /// Constructs a virtio queue configuration with the given `max_size`. new(max_size: u16, features: u64) -> Self105 pub fn new(max_size: u16, features: u64) -> Self { 106 assert!(max_size > 0); 107 assert!(max_size <= Queue::MAX_SIZE); 108 QueueConfig { 109 activated: false, 110 max_size, 111 size: max_size, 112 ready: false, 113 vector: VIRTIO_MSI_NO_VECTOR, 114 desc_table: GuestAddress(0), 115 avail_ring: GuestAddress(0), 116 used_ring: GuestAddress(0), 117 features, 118 acked_features: 0, 119 next_used: Wrapping(0), 120 next_avail: Wrapping(0), 121 } 122 } 123 124 /// Returns the maximum size of this queue. max_size(&self) -> u16125 pub fn max_size(&self) -> u16 { 126 self.max_size 127 } 128 129 /// Returns the currently configured size of the queue. size(&self) -> u16130 pub fn size(&self) -> u16 { 131 self.size 132 } 133 134 /// Sets the queue size. set_size(&mut self, val: u16)135 pub fn set_size(&mut self, val: u16) { 136 if self.ready { 137 warn!("ignoring write to size on ready queue"); 138 return; 139 } 140 141 if val > self.max_size { 142 warn!( 143 "requested queue size {} is larger than max_size {}", 144 val, self.max_size 145 ); 146 return; 147 } 148 149 self.size = val; 150 } 151 152 /// Returns the currently configured interrupt vector. vector(&self) -> u16153 pub fn vector(&self) -> u16 { 154 self.vector 155 } 156 157 /// Sets the interrupt vector for this queue. set_vector(&mut self, val: u16)158 pub fn set_vector(&mut self, val: u16) { 159 if self.ready { 160 warn!("ignoring write to vector on ready queue"); 161 return; 162 } 163 164 self.vector = val; 165 } 166 167 /// Getter for descriptor area desc_table(&self) -> GuestAddress168 pub fn desc_table(&self) -> GuestAddress { 169 self.desc_table 170 } 171 172 /// Setter for descriptor area set_desc_table(&mut self, val: GuestAddress)173 pub fn set_desc_table(&mut self, val: GuestAddress) { 174 if self.ready { 175 warn!("ignoring write to desc_table on ready queue"); 176 return; 177 } 178 179 self.desc_table = val; 180 } 181 182 /// Getter for driver area avail_ring(&self) -> GuestAddress183 pub fn avail_ring(&self) -> GuestAddress { 184 self.avail_ring 185 } 186 187 /// Setter for driver area set_avail_ring(&mut self, val: GuestAddress)188 pub fn set_avail_ring(&mut self, val: GuestAddress) { 189 if self.ready { 190 warn!("ignoring write to avail_ring on ready queue"); 191 return; 192 } 193 194 self.avail_ring = val; 195 } 196 197 /// Getter for device area used_ring(&self) -> GuestAddress198 pub fn used_ring(&self) -> GuestAddress { 199 self.used_ring 200 } 201 202 /// Setter for device area set_used_ring(&mut self, val: GuestAddress)203 pub fn set_used_ring(&mut self, val: GuestAddress) { 204 if self.ready { 205 warn!("ignoring write to used_ring on ready queue"); 206 return; 207 } 208 209 self.used_ring = val; 210 } 211 212 /// Getter for next_avail index next_avail(&self) -> Wrapping<u16>213 pub fn next_avail(&self) -> Wrapping<u16> { 214 self.next_avail 215 } 216 217 /// Setter for next_avail index set_next_avail(&mut self, val: Wrapping<u16>)218 pub fn set_next_avail(&mut self, val: Wrapping<u16>) { 219 if self.ready { 220 warn!("ignoring write to next_avail on ready queue"); 221 return; 222 } 223 224 self.next_avail = val; 225 } 226 227 /// Getter for next_used index next_used(&self) -> Wrapping<u16>228 pub fn next_used(&self) -> Wrapping<u16> { 229 self.next_used 230 } 231 232 /// Setter for next_used index set_next_used(&mut self, val: Wrapping<u16>)233 pub fn set_next_used(&mut self, val: Wrapping<u16>) { 234 if self.ready { 235 warn!("ignoring write to next_used on ready queue"); 236 return; 237 } 238 239 self.next_used = val; 240 } 241 242 /// Returns the features that have been acknowledged by the driver. acked_features(&self) -> u64243 pub fn acked_features(&self) -> u64 { 244 self.acked_features 245 } 246 247 /// Acknowledges that this set of features should be enabled on this queue. ack_features(&mut self, features: u64)248 pub fn ack_features(&mut self, features: u64) { 249 self.acked_features |= features & self.features; 250 } 251 252 /// Return whether the driver has enabled this queue. ready(&self) -> bool253 pub fn ready(&self) -> bool { 254 self.ready 255 } 256 257 /// Signal that the driver has completed queue configuration. set_ready(&mut self, enable: bool)258 pub fn set_ready(&mut self, enable: bool) { 259 self.ready = enable; 260 } 261 262 /// Convert the queue configuration into an active queue. activate(&mut self, mem: &GuestMemory, event: Event) -> Result<Queue>263 pub fn activate(&mut self, mem: &GuestMemory, event: Event) -> Result<Queue> { 264 if !self.ready { 265 bail!("attempted to activate a non-ready queue"); 266 } 267 268 if self.activated { 269 bail!("queue is already activated"); 270 } 271 // If VIRTIO_F_RING_PACKED feature bit is set, create a packed queue, otherwise create a 272 // split queue 273 let queue: Queue = if ((self.acked_features >> VIRTIO_F_RING_PACKED) & 1) != 0 { 274 let pq = 275 PackedQueue::new(self, mem, event).context("Failed to create a packed queue.")?; 276 Queue::PackedVirtQueue(pq) 277 } else { 278 let sq = 279 SplitQueue::new(self, mem, event).context("Failed to create a split queue.")?; 280 Queue::SplitVirtQueue(sq) 281 }; 282 283 self.activated = true; 284 Ok(queue) 285 } 286 287 /// Reset queue to a clean state reset(&mut self)288 pub fn reset(&mut self) { 289 self.activated = false; 290 self.ready = false; 291 self.size = self.max_size; 292 self.vector = VIRTIO_MSI_NO_VECTOR; 293 self.desc_table = GuestAddress(0); 294 self.avail_ring = GuestAddress(0); 295 self.used_ring = GuestAddress(0); 296 self.next_avail = Wrapping(0); 297 self.next_used = Wrapping(0); 298 self.acked_features = 0; 299 } 300 301 /// Take snapshot of queue configuration snapshot(&self) -> Result<serde_json::Value>302 pub fn snapshot(&self) -> Result<serde_json::Value> { 303 serde_json::to_value(QueueConfigSnapshot { 304 activated: self.activated, 305 max_size: self.max_size, 306 size: self.size, 307 ready: self.ready, 308 vector: self.vector, 309 features: self.features, 310 acked_features: self.acked_features, 311 desc_table: self.desc_table, 312 avail_ring: self.avail_ring, 313 used_ring: self.used_ring, 314 next_avail: self.next_avail, 315 next_used: self.next_used, 316 }) 317 .context("error serializing") 318 } 319 320 /// Restore queue configuration from snapshot restore(&mut self, data: serde_json::Value) -> Result<()>321 pub fn restore(&mut self, data: serde_json::Value) -> Result<()> { 322 let snap: QueueConfigSnapshot = 323 serde_json::from_value(data).context("error deserializing")?; 324 self.activated = snap.activated; 325 self.max_size = snap.max_size; 326 self.size = snap.size; 327 self.ready = snap.ready; 328 self.vector = snap.vector; 329 self.features = snap.features; 330 self.acked_features = snap.acked_features; 331 self.desc_table = snap.desc_table; 332 self.avail_ring = snap.avail_ring; 333 self.used_ring = snap.used_ring; 334 self.next_avail = snap.next_avail; 335 self.next_used = snap.next_used; 336 Ok(()) 337 } 338 } 339 340 /// Usage: define_queue_method!(method_name, return_type[, mut][, arg1: arg1_type, arg2: arg2_type, 341 /// ...]) 342 /// 343 /// - `method_name`: The name of the method to be defined (as an identifier). 344 /// - `return_type`: The return type of the method. 345 /// - `mut` (optional): Include this keyword if the method requires a mutable reference to `self` 346 /// (`&mut self`). 347 /// - `arg1: arg1_type, arg2: arg2_type, ...` (optional): Include method parameters as a 348 /// comma-separated list of `name: type` pairs, if the method takes any arguments. 349 macro_rules! define_queue_method { 350 ( 351 $(#[$doc:meta])* 352 $method:ident, $return_type:ty, $( $var:ident : $vartype:ty ),* 353 ) => { 354 $(#[$doc])* 355 pub fn $method(&self, $($var: $vartype),*) -> $return_type { 356 match self { 357 Queue::SplitVirtQueue(sq) => sq.$method($($var),*), 358 Queue::PackedVirtQueue(pq) => pq.$method($($var),*), 359 } 360 } 361 }; 362 ( 363 $(#[$doc:meta])* 364 $method:ident, $return_type:ty, mut, $( $var:ident : $vartype:ty ),* 365 ) => { 366 $(#[$doc])* 367 pub fn $method(&mut self, $($var: $vartype),*) -> $return_type { 368 match self { 369 Queue::SplitVirtQueue(sq) => sq.$method($($var),*), 370 Queue::PackedVirtQueue(pq) => pq.$method($($var),*), 371 } 372 } 373 }; 374 } 375 376 /// Virtqueue interface representing different types of virtqueues 377 /// The struct of each queue type is wrapped in the enum variants 378 #[derive(Debug)] 379 pub enum Queue { 380 /// Split virtqueue type in virtio v1.2 spec: <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-350007> 381 SplitVirtQueue(SplitQueue), 382 /// Packed virtqueue type in virtio v1.2 spec: <https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html#x1-720008> 383 PackedVirtQueue(PackedQueue), 384 } 385 386 impl Queue { 387 /// Largest valid number of entries in a virtqueue. 388 pub const MAX_SIZE: u16 = 32768; 389 390 /// Asynchronously read the next descriptor chain from the queue. 391 /// Returns a `DescriptorChain` when it is `await`ed. next_async( &mut self, eventfd: &mut EventAsync, ) -> std::result::Result<DescriptorChain, AsyncError>392 pub async fn next_async( 393 &mut self, 394 eventfd: &mut EventAsync, 395 ) -> std::result::Result<DescriptorChain, AsyncError> { 396 loop { 397 // Check if there are more descriptors available. 398 if let Some(chain) = self.pop() { 399 return Ok(chain); 400 } 401 eventfd.next_val().await?; 402 } 403 } 404 405 /// Get the first available descriptor chain without removing it from the queue. 406 /// Call `pop()` on the returned [`PeekedDescriptorChain`] to remove it from the queue. peek(&mut self) -> Option<PeekedDescriptorChain>407 pub fn peek(&mut self) -> Option<PeekedDescriptorChain> { 408 let desc_chain = match self { 409 Queue::SplitVirtQueue(q) => q.peek(), 410 Queue::PackedVirtQueue(q) => q.peek(), 411 }?; 412 413 Some(PeekedDescriptorChain::new(self, desc_chain)) 414 } 415 416 /// If a new DescriptorChain is available, returns one and removes it from the queue. pop(&mut self) -> Option<DescriptorChain>417 pub fn pop(&mut self) -> Option<DescriptorChain> { 418 self.peek().map(PeekedDescriptorChain::pop) 419 } 420 421 /// Returns `None` if stop_rx receives a value; otherwise returns the result 422 /// of waiting for the next descriptor. next_async_interruptable( &mut self, queue_event: &mut EventAsync, mut stop_rx: &mut oneshot::Receiver<()>, ) -> std::result::Result<Option<DescriptorChain>, AsyncError>423 pub async fn next_async_interruptable( 424 &mut self, 425 queue_event: &mut EventAsync, 426 mut stop_rx: &mut oneshot::Receiver<()>, 427 ) -> std::result::Result<Option<DescriptorChain>, AsyncError> { 428 select_biased! { 429 avail_desc_res = self.next_async(queue_event).fuse() => { 430 Ok(Some(avail_desc_res?)) 431 } 432 _ = stop_rx => Ok(None), 433 } 434 } 435 436 /// inject interrupt into guest on this queue 437 /// return true: interrupt is injected into guest for this queue 438 /// false: interrupt isn't injected trigger_interrupt(&mut self, interrupt: &Interrupt) -> bool439 pub fn trigger_interrupt(&mut self, interrupt: &Interrupt) -> bool { 440 match self { 441 Queue::SplitVirtQueue(sq) => sq.trigger_interrupt(interrupt), 442 Queue::PackedVirtQueue(pq) => pq.trigger_interrupt(interrupt), 443 } 444 } 445 446 /// Restore queue from snapshot restore( queue_config: &QueueConfig, queue_value: serde_json::Value, mem: &GuestMemory, event: Event, ) -> anyhow::Result<Queue>447 pub fn restore( 448 queue_config: &QueueConfig, 449 queue_value: serde_json::Value, 450 mem: &GuestMemory, 451 event: Event, 452 ) -> anyhow::Result<Queue> { 453 if queue_config.acked_features & 1 << VIRTIO_F_RING_PACKED != 0 { 454 PackedQueue::restore(queue_value, mem, event).map(Queue::PackedVirtQueue) 455 } else { 456 SplitQueue::restore(queue_value, mem, event).map(Queue::SplitVirtQueue) 457 } 458 } 459 460 define_queue_method!( 461 /// Getter for vector field 462 vector, 463 u16, 464 ); 465 466 define_queue_method!( 467 /// Getter for descriptor area 468 desc_table, 469 GuestAddress, 470 ); 471 472 define_queue_method!( 473 /// Getter for driver area 474 avail_ring, 475 GuestAddress, 476 ); 477 478 define_queue_method!( 479 /// Getter for device area 480 used_ring, 481 GuestAddress, 482 ); 483 484 define_queue_method!( 485 /// Return the actual size of the queue, as the driver may not set up a 486 /// queue as big as the device allows. 487 size, 488 u16, 489 ); 490 491 define_queue_method!( 492 /// Get a reference to the queue's event. 493 event, 494 &Event, 495 ); 496 497 define_queue_method!( 498 /// Puts an available descriptor head into the used ring for use by the guest. 499 add_used, 500 (), 501 mut, 502 desc_chain: DescriptorChain, 503 len: u32 504 ); 505 506 define_queue_method!( 507 /// Take snapshot of queue's current status 508 snapshot, 509 Result<serde_json::Value>, 510 ); 511 } 512 513 /// A `DescriptorChain` that has been peeked from a `Queue` but not popped yet. 514 /// 515 /// Call [`pop()`](Self::pop) to pop this descriptor chain from the `Queue` and receive the 516 /// contained `DescriptorChain` object. 517 /// 518 /// This object holds a mutable reference to the `Queue` to ensure it is not possible to pop or peek 519 /// another descriptor while a peek is already active. Either `pop()` or drop this object before 520 /// attempting to manipulate the `Queue` again. 521 pub struct PeekedDescriptorChain<'q> { 522 queue: &'q mut Queue, 523 desc_chain: DescriptorChain, 524 } 525 526 impl<'q> PeekedDescriptorChain<'q> { 527 /// Create a `PeekedDescriptorChain` that holds a mutable reference to its `Queue`. 528 /// Use [`Queue::peek()`] rather than calling this function. new(queue: &'q mut Queue, desc_chain: DescriptorChain) -> Self529 fn new(queue: &'q mut Queue, desc_chain: DescriptorChain) -> Self { 530 PeekedDescriptorChain { queue, desc_chain } 531 } 532 533 /// Pop this descriptor chain from the queue. pop(self) -> DescriptorChain534 pub fn pop(self) -> DescriptorChain { 535 match self.queue { 536 Queue::SplitVirtQueue(q) => q.pop_peeked(&self.desc_chain), 537 Queue::PackedVirtQueue(q) => q.pop_peeked(&self.desc_chain), 538 } 539 self.desc_chain 540 } 541 } 542 543 impl Deref for PeekedDescriptorChain<'_> { 544 type Target = DescriptorChain; 545 deref(&self) -> &Self::Target546 fn deref(&self) -> &Self::Target { 547 &self.desc_chain 548 } 549 } 550 551 impl DerefMut for PeekedDescriptorChain<'_> { deref_mut(&mut self) -> &mut Self::Target552 fn deref_mut(&mut self) -> &mut Self::Target { 553 &mut self.desc_chain 554 } 555 } 556