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 89 // The queue size in elements the driver selected 90 size: u16, 91 92 // MSI-X vector for the queue. Don't care for INTx 93 vector: u16, 94 95 // Internal index counter to keep track of where to poll 96 avail_index: PackedQueueIndex, 97 use_index: PackedQueueIndex, 98 signalled_used_index: PackedQueueIndex, 99 100 // Device feature bits accepted by the driver 101 features: u64, 102 103 // Guest physical address of the descriptor table 104 desc_table: GuestAddress, 105 106 // Write-only by the device, Including information for reducing the number of device events 107 device_event_suppression: GuestAddress, 108 109 // Read-only by the device, Includes information for reducing the number of driver events 110 driver_event_suppression: GuestAddress, 111 } 112 113 #[derive(Serialize, Deserialize)] 114 pub struct PackedQueueSnapshot { 115 size: u16, 116 vector: u16, 117 avail_index: PackedQueueIndex, 118 use_index: PackedQueueIndex, 119 signalled_used_index: PackedQueueIndex, 120 features: u64, 121 desc_table: GuestAddress, 122 device_event_suppression: GuestAddress, 123 driver_event_suppression: GuestAddress, 124 } 125 126 impl PackedQueue { 127 /// Constructs an empty virtio queue with the given `max_size`. new(config: &QueueConfig, mem: &GuestMemory, event: Event) -> Result<Self>128 pub fn new(config: &QueueConfig, mem: &GuestMemory, event: Event) -> Result<Self> { 129 let size = config.size(); 130 131 let desc_table = config.desc_table(); 132 let driver_area = config.avail_ring(); 133 let device_area = config.used_ring(); 134 135 // Validate addresses and queue size to ensure that address calculation won't overflow. 136 let ring_sizes = Self::area_sizes(size, desc_table, driver_area, device_area); 137 let rings = ring_sizes.iter().zip(vec![ 138 "descriptor table", 139 "driver_event_suppression", 140 "device_event_suppression", 141 ]); 142 143 for ((addr, size), name) in rings { 144 if addr.checked_add(*size as u64).is_none() { 145 bail!( 146 "virtio queue {} goes out of bounds: start:0x{:08x} size:0x{:08x}", 147 name, 148 addr.offset(), 149 size, 150 ); 151 } 152 } 153 154 Ok(PackedQueue { 155 mem: mem.clone(), 156 event, 157 size, 158 vector: config.vector(), 159 desc_table: config.desc_table(), 160 driver_event_suppression: config.avail_ring(), 161 device_event_suppression: config.used_ring(), 162 features: config.acked_features(), 163 avail_index: PackedQueueIndex::default(), 164 use_index: PackedQueueIndex::default(), 165 signalled_used_index: PackedQueueIndex::default(), 166 }) 167 } 168 169 /// Return the actual size of the queue, as the driver may not set up a 170 /// queue as big as the device allows. size(&self) -> u16171 pub fn size(&self) -> u16 { 172 self.size 173 } 174 175 /// Getter for vector field vector(&self) -> u16176 pub fn vector(&self) -> u16 { 177 self.vector 178 } 179 180 /// Getter for descriptor area desc_table(&self) -> GuestAddress181 pub fn desc_table(&self) -> GuestAddress { 182 self.desc_table 183 } 184 185 /// Getter for driver area avail_ring(&self) -> GuestAddress186 pub fn avail_ring(&self) -> GuestAddress { 187 self.driver_event_suppression 188 } 189 190 /// Getter for device area used_ring(&self) -> GuestAddress191 pub fn used_ring(&self) -> GuestAddress { 192 self.device_event_suppression 193 } 194 195 /// Get a reference to the queue's "kick event" event(&self) -> &Event196 pub fn event(&self) -> &Event { 197 &self.event 198 } 199 area_sizes( queue_size: u16, desc_table: GuestAddress, driver_area: GuestAddress, device_area: GuestAddress, ) -> Vec<(GuestAddress, usize)>200 fn area_sizes( 201 queue_size: u16, 202 desc_table: GuestAddress, 203 driver_area: GuestAddress, 204 device_area: GuestAddress, 205 ) -> Vec<(GuestAddress, usize)> { 206 vec![ 207 (desc_table, 16 * queue_size as usize), 208 (driver_area, 4), 209 (device_area, 4), 210 ] 211 } 212 213 /// Set the device event suppression 214 /// 215 /// This field is used to specify the timing of when the driver notifies the 216 /// device that the descriptor table is ready to be processed. set_avail_event(&mut self, event: PackedDescEvent)217 fn set_avail_event(&mut self, event: PackedDescEvent) { 218 fence(Ordering::SeqCst); 219 self.mem 220 .write_obj_at_addr_volatile(event, self.device_event_suppression) 221 .unwrap(); 222 } 223 224 // Get the driver event suppression. 225 // This field is used to specify the timing of when the device notifies the 226 // driver that the descriptor table is ready to be processed. get_driver_event(&self) -> PackedDescEvent227 fn get_driver_event(&self) -> PackedDescEvent { 228 fence(Ordering::SeqCst); 229 230 let desc: PackedDescEvent = self 231 .mem 232 .read_obj_from_addr_volatile(self.driver_event_suppression) 233 .unwrap(); 234 desc 235 } 236 237 /// Get the first available descriptor chain without removing it from the queue. 238 /// Call `pop_peeked` to remove the returned descriptor chain from the queue. peek(&mut self) -> Option<DescriptorChain>239 pub fn peek(&mut self) -> Option<DescriptorChain> { 240 let desc_addr = self 241 .desc_table 242 .checked_add((self.avail_index.index.0 as u64) * 16) 243 .expect("peeked address will not overflow"); 244 245 let desc = self 246 .mem 247 .read_obj_from_addr::<PackedDesc>(desc_addr) 248 .map_err(|e| { 249 error!("failed to read desc {:#x}", desc_addr.offset()); 250 e 251 }) 252 .ok()?; 253 254 if !desc.is_available(self.avail_index.wrap_counter as u16) { 255 return None; 256 } 257 258 // This fence ensures that subsequent reads from the descriptor do not 259 // get reordered and happen only after verifying the descriptor table is 260 // available. 261 fence(Ordering::SeqCst); 262 263 let chain = PackedDescriptorChain::new( 264 &self.mem, 265 self.desc_table, 266 self.size, 267 self.avail_index.wrap_counter, 268 self.avail_index.index.0, 269 ); 270 271 match DescriptorChain::new(chain, &self.mem, self.avail_index.index.0) { 272 Ok(descriptor_chain) => Some(descriptor_chain), 273 Err(e) => { 274 error!("{:#}", e); 275 None 276 } 277 } 278 } 279 280 /// Remove the first available descriptor chain from the queue. 281 /// This function should only be called immediately following `peek` and must be passed a 282 /// reference to the same `DescriptorChain` returned by the most recent `peek`. pop_peeked(&mut self, descriptor_chain: &DescriptorChain)283 pub(super) fn pop_peeked(&mut self, descriptor_chain: &DescriptorChain) { 284 self.avail_index 285 .add_index(descriptor_chain.count, self.size()); 286 if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) != 0 { 287 self.set_avail_event(self.avail_index.to_desc()); 288 } 289 } 290 291 /// Write to first descriptor in descriptor chain to mark descriptor chain as used add_used(&mut self, desc_chain: DescriptorChain, len: u32)292 pub fn add_used(&mut self, desc_chain: DescriptorChain, len: u32) { 293 let desc_index = desc_chain.index(); 294 if desc_index >= self.size { 295 error!( 296 "attempted to add out of bounds descriptor to used ring: {}", 297 desc_index 298 ); 299 return; 300 } 301 302 let chain_id = desc_chain 303 .id 304 .expect("Packed descriptor chain should have id"); 305 306 let desc_addr = self 307 .desc_table 308 .checked_add(self.use_index.index.0 as u64 * 16) 309 .expect("Descriptor address should not overflow."); 310 311 // Write to len field 312 self.mem 313 .write_obj_at_addr( 314 len, 315 desc_addr 316 .checked_add(8) 317 .expect("Descriptor address should not overflow."), 318 ) 319 .unwrap(); 320 321 // Write to id field 322 self.mem 323 .write_obj_at_addr( 324 chain_id, 325 desc_addr 326 .checked_add(12) 327 .expect("Descriptor address should not overflow."), 328 ) 329 .unwrap(); 330 331 let wrap_counter = self.use_index.wrap_counter; 332 333 let mut flags: u16 = 0; 334 if wrap_counter { 335 flags = flags | VIRTQ_DESC_F_USED | VIRTQ_DESC_F_AVAIL; 336 } 337 if len > 0 { 338 flags |= VIRTQ_DESC_F_WRITE; 339 } 340 341 // Writing to flags should come at the very end to avoid showing the 342 // driver fragmented descriptor data 343 fence(Ordering::SeqCst); 344 345 self.mem 346 .write_obj_at_addr_volatile(flags, desc_addr.unchecked_add(14)) 347 .unwrap(); 348 349 self.use_index.add_index(desc_chain.count, self.size()); 350 } 351 352 /// Returns if the queue should have an interrupt sent based on its state. queue_wants_interrupt(&mut self) -> bool353 fn queue_wants_interrupt(&mut self) -> bool { 354 let driver_event = self.get_driver_event(); 355 match driver_event.notification_type() { 356 PackedNotificationType::Enable => true, 357 PackedNotificationType::Disable => false, 358 PackedNotificationType::Desc(desc) => { 359 if self.features & ((1u64) << VIRTIO_RING_F_EVENT_IDX) == 0 { 360 warn!("This is undefined behavior. We should actually send error in this case"); 361 return true; 362 } 363 364 // Reserved current use_index for next notify 365 let old = self.signalled_used_index; 366 self.signalled_used_index = self.use_index; 367 368 // Get desc_event_off and desc_event_wrap from driver event suppress area 369 let event_index: PackedQueueIndex = PackedQueueIndex::new_from_desc(desc); 370 371 let event_idx = event_index.index; 372 let old_idx = old.index; 373 let new_idx = self.use_index.index; 374 375 // In qemu's implementation, there's an additional calculation, 376 // need to verify its correctness. 377 // if event_index.wrap_counter != self.use_index.wrap_counter { 378 // event_idx -= self.size() as u16; 379 // } 380 381 (new_idx - event_idx - Wrapping(1)) < (new_idx - old_idx) 382 } 383 }; 384 true 385 } 386 387 /// inject interrupt into guest on this queue 388 /// return true: interrupt is injected into guest for this queue 389 /// false: interrupt isn't injected trigger_interrupt(&mut self, interrupt: &Interrupt) -> bool390 pub fn trigger_interrupt(&mut self, interrupt: &Interrupt) -> bool { 391 if self.queue_wants_interrupt() { 392 interrupt.signal_used_queue(self.vector); 393 true 394 } else { 395 false 396 } 397 } 398 399 /// Acknowledges that this set of features should be enabled on this queue. ack_features(&mut self, features: u64)400 pub fn ack_features(&mut self, features: u64) { 401 self.features |= features; 402 } 403 404 /// TODO: b/290307056 - Implement snapshot for packed virtqueue, 405 /// add tests to validate. snapshot(&self) -> Result<serde_json::Value>406 pub fn snapshot(&self) -> Result<serde_json::Value> { 407 bail!("Snapshot for packed virtqueue not implemented."); 408 } 409 410 /// TODO: b/290307056 - Implement restore for packed virtqueue, 411 /// add tests to validate. restore( _queue_value: serde_json::Value, _mem: &GuestMemory, _event: Event, ) -> Result<PackedQueue>412 pub fn restore( 413 _queue_value: serde_json::Value, 414 _mem: &GuestMemory, 415 _event: Event, 416 ) -> Result<PackedQueue> { 417 bail!("Restore for packed virtqueue not implemented."); 418 } 419 } 420