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 #![deny(missing_docs)] 6 7 use std::num::Wrapping; 8 use std::sync::atomic::fence; 9 use std::sync::atomic::Ordering; 10 11 use anyhow::bail; 12 use anyhow::Result; 13 use base::error; 14 use base::warn; 15 use base::Event; 16 use serde::Deserialize; 17 use serde::Serialize; 18 use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX; 19 use vm_memory::GuestAddress; 20 use vm_memory::GuestMemory; 21 22 use crate::virtio::descriptor_chain::DescriptorChain; 23 use crate::virtio::descriptor_chain::VIRTQ_DESC_F_AVAIL; 24 use crate::virtio::descriptor_chain::VIRTQ_DESC_F_USED; 25 use crate::virtio::descriptor_chain::VIRTQ_DESC_F_WRITE; 26 use crate::virtio::queue::packed_descriptor_chain::PackedDesc; 27 use crate::virtio::queue::packed_descriptor_chain::PackedDescEvent; 28 use crate::virtio::queue::packed_descriptor_chain::PackedDescriptorChain; 29 use crate::virtio::queue::packed_descriptor_chain::PackedNotificationType; 30 use crate::virtio::queue::packed_descriptor_chain::RING_EVENT_FLAGS_DESC; 31 use crate::virtio::Interrupt; 32 use crate::virtio::QueueConfig; 33 34 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] 35 struct PackedQueueIndex { 36 wrap_counter: bool, 37 index: Wrapping<u16>, 38 } 39 impl PackedQueueIndex { new(wrap_counter: bool, index: u16) -> Self40 pub fn new(wrap_counter: bool, index: u16) -> Self { 41 Self { 42 wrap_counter, 43 index: Wrapping(index), 44 } 45 } 46 new_from_desc(desc: u16) -> Self47 pub fn new_from_desc(desc: u16) -> Self { 48 let wrap_counter: bool = (desc >> 15) == 1; 49 let mask: u16 = 0x7fff; 50 let index = desc & mask; 51 Self::new(wrap_counter, index) 52 } 53 to_desc(self) -> PackedDescEvent54 pub fn to_desc(self) -> PackedDescEvent { 55 let flag = RING_EVENT_FLAGS_DESC; 56 let mut desc = self.index.0; 57 if self.wrap_counter { 58 desc |= 1 << 15; 59 } 60 PackedDescEvent { 61 desc: desc.into(), 62 flag: flag.into(), 63 } 64 } 65 add_index(&mut self, index_value: u16, size: u16)66 fn add_index(&mut self, index_value: u16, size: u16) { 67 let new_index = self.index.0 + index_value; 68 if new_index < size { 69 self.index = Wrapping(new_index); 70 } else { 71 self.index = Wrapping(new_index - size); 72 self.wrap_counter = !self.wrap_counter; 73 } 74 } 75 } 76 77 impl Default for PackedQueueIndex { default() -> Self78 fn default() -> Self { 79 Self::new(true, 0) 80 } 81 } 82 83 #[derive(Debug)] 84 pub struct PackedQueue { 85 mem: GuestMemory, 86 87 event: Event, 88 interrupt: Interrupt, 89 90 // The queue size in elements the driver selected 91 size: u16, 92 93 // MSI-X vector for the queue. Don't care for INTx 94 vector: u16, 95 96 // Internal index counter to keep track of where to poll 97 avail_index: PackedQueueIndex, 98 use_index: PackedQueueIndex, 99 signalled_used_index: PackedQueueIndex, 100 101 // Device feature bits accepted by the driver 102 features: u64, 103 104 // Guest physical address of the descriptor table 105 desc_table: GuestAddress, 106 107 // Write-only by the device, Including information for reducing the number of device events 108 device_event_suppression: GuestAddress, 109 110 // Read-only by the device, Includes information for reducing the number of driver events 111 driver_event_suppression: GuestAddress, 112 } 113 114 #[derive(Serialize, Deserialize)] 115 pub struct PackedQueueSnapshot { 116 size: u16, 117 vector: u16, 118 avail_index: PackedQueueIndex, 119 use_index: PackedQueueIndex, 120 signalled_used_index: PackedQueueIndex, 121 features: u64, 122 desc_table: GuestAddress, 123 device_event_suppression: GuestAddress, 124 driver_event_suppression: GuestAddress, 125 } 126 127 impl PackedQueue { 128 /// Constructs an empty virtio queue with the given `max_size`. new( config: &QueueConfig, mem: &GuestMemory, event: Event, interrupt: Interrupt, ) -> Result<Self>129 pub fn new( 130 config: &QueueConfig, 131 mem: &GuestMemory, 132 event: Event, 133 interrupt: Interrupt, 134 ) -> Result<Self> { 135 let size = config.size(); 136 137 let desc_table = config.desc_table(); 138 let driver_area = config.avail_ring(); 139 let device_area = config.used_ring(); 140 141 // Validate addresses and queue size to ensure that address calculation won't overflow. 142 let ring_sizes = Self::area_sizes(size, desc_table, driver_area, device_area); 143 let rings = ring_sizes.iter().zip(vec![ 144 "descriptor table", 145 "driver_event_suppression", 146 "device_event_suppression", 147 ]); 148 149 for ((addr, size), name) in rings { 150 if addr.checked_add(*size as u64).is_none() { 151 bail!( 152 "virtio queue {} goes out of bounds: start:0x{:08x} size:0x{:08x}", 153 name, 154 addr.offset(), 155 size, 156 ); 157 } 158 } 159 160 Ok(PackedQueue { 161 mem: mem.clone(), 162 event, 163 interrupt, 164 size, 165 vector: config.vector(), 166 desc_table: config.desc_table(), 167 driver_event_suppression: config.avail_ring(), 168 device_event_suppression: config.used_ring(), 169 features: config.acked_features(), 170 avail_index: PackedQueueIndex::default(), 171 use_index: PackedQueueIndex::default(), 172 signalled_used_index: PackedQueueIndex::default(), 173 }) 174 } 175 vhost_user_reclaim(&mut self, _vring_base: u16)176 pub fn vhost_user_reclaim(&mut self, _vring_base: u16) { 177 // TODO: b/331466964 - Need more than `vring_base` to reclaim a packed virtqueue. 178 unimplemented!() 179 } 180 next_avail_to_process(&self) -> u16181 pub fn next_avail_to_process(&self) -> u16 { 182 self.avail_index.index.0 183 } 184 185 /// Return the actual size of the queue, as the driver may not set up a 186 /// queue as big as the device allows. size(&self) -> u16187 pub fn size(&self) -> u16 { 188 self.size 189 } 190 191 /// Getter for vector field vector(&self) -> u16192 pub fn vector(&self) -> u16 { 193 self.vector 194 } 195 196 /// Getter for descriptor area desc_table(&self) -> GuestAddress197 pub fn desc_table(&self) -> GuestAddress { 198 self.desc_table 199 } 200 201 /// Getter for driver area avail_ring(&self) -> GuestAddress202 pub fn avail_ring(&self) -> GuestAddress { 203 self.driver_event_suppression 204 } 205 206 /// Getter for device area used_ring(&self) -> GuestAddress207 pub fn used_ring(&self) -> GuestAddress { 208 self.device_event_suppression 209 } 210 211 /// Get a reference to the queue's "kick event" event(&self) -> &Event212 pub fn event(&self) -> &Event { 213 &self.event 214 } 215 216 /// Get a reference to the queue's interrupt interrupt(&self) -> &Interrupt217 pub fn interrupt(&self) -> &Interrupt { 218 &self.interrupt 219 } 220 area_sizes( queue_size: u16, desc_table: GuestAddress, driver_area: GuestAddress, device_area: GuestAddress, ) -> Vec<(GuestAddress, usize)>221 fn area_sizes( 222 queue_size: u16, 223 desc_table: GuestAddress, 224 driver_area: GuestAddress, 225 device_area: GuestAddress, 226 ) -> Vec<(GuestAddress, usize)> { 227 vec![ 228 (desc_table, 16 * queue_size as usize), 229 (driver_area, 4), 230 (device_area, 4), 231 ] 232 } 233 234 /// Set the device event suppression 235 /// 236 /// This field is used to specify the timing of when the driver notifies the 237 /// device that the descriptor table is ready to be processed. set_avail_event(&mut self, event: PackedDescEvent)238 fn set_avail_event(&mut self, event: PackedDescEvent) { 239 fence(Ordering::SeqCst); 240 self.mem 241 .write_obj_at_addr_volatile(event, self.device_event_suppression) 242 .unwrap(); 243 } 244 245 // Get the driver event suppression. 246 // This field is used to specify the timing of when the device notifies the 247 // driver that the descriptor table is ready to be processed. get_driver_event(&self) -> PackedDescEvent248 fn get_driver_event(&self) -> PackedDescEvent { 249 fence(Ordering::SeqCst); 250 251 let desc: PackedDescEvent = self 252 .mem 253 .read_obj_from_addr_volatile(self.driver_event_suppression) 254 .unwrap(); 255 desc 256 } 257 258 /// Get the first available descriptor chain without removing it from the queue. 259 /// Call `pop_peeked` to remove the returned descriptor chain from the queue. peek(&mut self) -> Option<DescriptorChain>260 pub fn peek(&mut self) -> Option<DescriptorChain> { 261 let desc_addr = self 262 .desc_table 263 .checked_add((self.avail_index.index.0 as u64) * 16) 264 .expect("peeked address will not overflow"); 265 266 let desc = self 267 .mem 268 .read_obj_from_addr::<PackedDesc>(desc_addr) 269 .inspect_err(|_e| { 270 error!("failed to read desc {:#x}", desc_addr.offset()); 271 }) 272 .ok()?; 273 274 if !desc.is_available(self.avail_index.wrap_counter as u16) { 275 return None; 276 } 277 278 // This fence ensures that subsequent reads from the descriptor do not 279 // get reordered and happen only after verifying the descriptor table is 280 // available. 281 fence(Ordering::SeqCst); 282 283 let chain = PackedDescriptorChain::new( 284 &self.mem, 285 self.desc_table, 286 self.size, 287 self.avail_index.wrap_counter, 288 self.avail_index.index.0, 289 ); 290 291 match DescriptorChain::new(chain, &self.mem, self.avail_index.index.0) { 292 Ok(descriptor_chain) => Some(descriptor_chain), 293 Err(e) => { 294 error!("{:#}", e); 295 None 296 } 297 } 298 } 299 300 /// Remove the first available descriptor chain from the queue. 301 /// This function should only be called immediately following `peek` and must be passed a 302 /// reference to the same `DescriptorChain` returned by the most recent `peek`. pop_peeked(&mut self, descriptor_chain: &DescriptorChain)303 pub(super) fn pop_peeked(&mut self, descriptor_chain: &DescriptorChain) { 304 self.avail_index 305 .add_index(descriptor_chain.count, self.size()); 306 if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 { 307 self.set_avail_event(self.avail_index.to_desc()); 308 } 309 } 310 311 /// Write to first descriptor in descriptor chain to mark descriptor chain as used add_used(&mut self, desc_chain: DescriptorChain, len: u32)312 pub fn add_used(&mut self, desc_chain: DescriptorChain, len: u32) { 313 let desc_index = desc_chain.index(); 314 if desc_index >= self.size { 315 error!( 316 "attempted to add out of bounds descriptor to used ring: {}", 317 desc_index 318 ); 319 return; 320 } 321 322 let chain_id = desc_chain 323 .id 324 .expect("Packed descriptor chain should have id"); 325 326 let desc_addr = self 327 .desc_table 328 .checked_add(self.use_index.index.0 as u64 * 16) 329 .expect("Descriptor address should not overflow."); 330 331 // Write to len field 332 self.mem 333 .write_obj_at_addr( 334 len, 335 desc_addr 336 .checked_add(8) 337 .expect("Descriptor address should not overflow."), 338 ) 339 .unwrap(); 340 341 // Write to id field 342 self.mem 343 .write_obj_at_addr( 344 chain_id, 345 desc_addr 346 .checked_add(12) 347 .expect("Descriptor address should not overflow."), 348 ) 349 .unwrap(); 350 351 let wrap_counter = self.use_index.wrap_counter; 352 353 let mut flags: u16 = 0; 354 if wrap_counter { 355 flags = flags | VIRTQ_DESC_F_USED | VIRTQ_DESC_F_AVAIL; 356 } 357 if len > 0 { 358 flags |= VIRTQ_DESC_F_WRITE; 359 } 360 361 // Writing to flags should come at the very end to avoid showing the 362 // driver fragmented descriptor data 363 fence(Ordering::SeqCst); 364 365 self.mem 366 .write_obj_at_addr_volatile(flags, desc_addr.unchecked_add(14)) 367 .unwrap(); 368 369 self.use_index.add_index(desc_chain.count, self.size()); 370 } 371 372 /// Returns if the queue should have an interrupt sent based on its state. queue_wants_interrupt(&mut self) -> bool373 fn queue_wants_interrupt(&mut self) -> bool { 374 let driver_event = self.get_driver_event(); 375 match driver_event.notification_type() { 376 PackedNotificationType::Enable => true, 377 PackedNotificationType::Disable => false, 378 PackedNotificationType::Desc(desc) => { 379 if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) == 0 { 380 warn!("This is undefined behavior. We should actually send error in this case"); 381 return true; 382 } 383 384 // Reserved current use_index for next notify 385 let old = self.signalled_used_index; 386 self.signalled_used_index = self.use_index; 387 388 // Get desc_event_off and desc_event_wrap from driver event suppress area 389 let event_index: PackedQueueIndex = PackedQueueIndex::new_from_desc(desc); 390 391 let event_idx = event_index.index; 392 let old_idx = old.index; 393 let new_idx = self.use_index.index; 394 395 // In qemu's implementation, there's an additional calculation, 396 // need to verify its correctness. 397 // if event_index.wrap_counter != self.use_index.wrap_counter { 398 // event_idx -= self.size() as u16; 399 // } 400 401 (new_idx - event_idx - Wrapping(1)) < (new_idx - old_idx) 402 } 403 }; 404 true 405 } 406 407 /// inject interrupt into guest on this queue 408 /// return true: interrupt is injected into guest for this queue 409 /// false: interrupt isn't injected trigger_interrupt(&mut self) -> bool410 pub fn trigger_interrupt(&mut self) -> bool { 411 if self.queue_wants_interrupt() { 412 self.interrupt.signal_used_queue(self.vector); 413 true 414 } else { 415 false 416 } 417 } 418 419 /// Acknowledges that this set of features should be enabled on this queue. ack_features(&mut self, features: u64)420 pub fn ack_features(&mut self, features: u64) { 421 self.features |= features; 422 } 423 424 /// TODO: b/290307056 - Implement snapshot for packed virtqueue, 425 /// add tests to validate. snapshot(&self) -> Result<serde_json::Value>426 pub fn snapshot(&self) -> Result<serde_json::Value> { 427 bail!("Snapshot for packed virtqueue not implemented."); 428 } 429 430 /// TODO: b/290307056 - Implement restore for packed virtqueue, 431 /// add tests to validate. restore( _queue_value: serde_json::Value, _mem: &GuestMemory, _event: Event, _interrupt: Interrupt, ) -> Result<PackedQueue>432 pub fn restore( 433 _queue_value: serde_json::Value, 434 _mem: &GuestMemory, 435 _event: Event, 436 _interrupt: Interrupt, 437 ) -> Result<PackedQueue> { 438 bail!("Restore for packed virtqueue not implemented."); 439 } 440 } 441