1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE-BSD-3-Clause file. 4 // 5 // Copyright © 2019 Intel Corporation 6 // 7 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 8 9 use crate::VirtioDevice; 10 use byteorder::{ByteOrder, LittleEndian}; 11 use std::sync::atomic::{AtomicU16, Ordering}; 12 use std::sync::{Arc, Mutex}; 13 use versionize::{VersionMap, Versionize, VersionizeResult}; 14 use versionize_derive::Versionize; 15 use virtio_queue::{Queue, QueueT}; 16 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped}; 17 use vm_virtio::AccessPlatform; 18 19 pub const VIRTIO_PCI_COMMON_CONFIG_ID: &str = "virtio_pci_common_config"; 20 21 #[derive(Clone, Versionize)] 22 pub struct VirtioPciCommonConfigState { 23 pub driver_status: u8, 24 pub config_generation: u8, 25 pub device_feature_select: u32, 26 pub driver_feature_select: u32, 27 pub queue_select: u16, 28 pub msix_config: u16, 29 pub msix_queues: Vec<u16>, 30 } 31 32 impl VersionMapped for VirtioPciCommonConfigState {} 33 34 /// Contains the data for reading and writing the common configuration structure of a virtio PCI 35 /// device. 36 /// 37 /// * Registers: 38 /// ** About the whole device. 39 /// le32 device_feature_select; // 0x00 // read-write 40 /// le32 device_feature; // 0x04 // read-only for driver 41 /// le32 driver_feature_select; // 0x08 // read-write 42 /// le32 driver_feature; // 0x0C // read-write 43 /// le16 msix_config; // 0x10 // read-write 44 /// le16 num_queues; // 0x12 // read-only for driver 45 /// u8 device_status; // 0x14 // read-write (driver_status) 46 /// u8 config_generation; // 0x15 // read-only for driver 47 /// ** About a specific virtqueue. 48 /// le16 queue_select; // 0x16 // read-write 49 /// le16 queue_size; // 0x18 // read-write, power of 2, or 0. 50 /// le16 queue_msix_vector; // 0x1A // read-write 51 /// le16 queue_enable; // 0x1C // read-write (Ready) 52 /// le16 queue_notify_off; // 0x1E // read-only for driver 53 /// le64 queue_desc; // 0x20 // read-write 54 /// le64 queue_avail; // 0x28 // read-write 55 /// le64 queue_used; // 0x30 // read-write 56 pub struct VirtioPciCommonConfig { 57 pub access_platform: Option<Arc<dyn AccessPlatform>>, 58 pub driver_status: u8, 59 pub config_generation: u8, 60 pub device_feature_select: u32, 61 pub driver_feature_select: u32, 62 pub queue_select: u16, 63 pub msix_config: Arc<AtomicU16>, 64 pub msix_queues: Arc<Mutex<Vec<u16>>>, 65 } 66 67 impl VirtioPciCommonConfig { 68 pub fn new( 69 state: VirtioPciCommonConfigState, 70 access_platform: Option<Arc<dyn AccessPlatform>>, 71 ) -> Self { 72 VirtioPciCommonConfig { 73 access_platform, 74 driver_status: state.driver_status, 75 config_generation: state.config_generation, 76 device_feature_select: state.device_feature_select, 77 driver_feature_select: state.driver_feature_select, 78 queue_select: state.queue_select, 79 msix_config: Arc::new(AtomicU16::new(state.msix_config)), 80 msix_queues: Arc::new(Mutex::new(state.msix_queues)), 81 } 82 } 83 84 fn state(&self) -> VirtioPciCommonConfigState { 85 VirtioPciCommonConfigState { 86 driver_status: self.driver_status, 87 config_generation: self.config_generation, 88 device_feature_select: self.device_feature_select, 89 driver_feature_select: self.driver_feature_select, 90 queue_select: self.queue_select, 91 msix_config: self.msix_config.load(Ordering::Acquire), 92 msix_queues: self.msix_queues.lock().unwrap().clone(), 93 } 94 } 95 96 pub fn read( 97 &mut self, 98 offset: u64, 99 data: &mut [u8], 100 queues: &mut [Queue], 101 device: Arc<Mutex<dyn VirtioDevice>>, 102 ) { 103 assert!(data.len() <= 8); 104 105 match data.len() { 106 1 => { 107 let v = self.read_common_config_byte(offset); 108 data[0] = v; 109 } 110 2 => { 111 let v = self.read_common_config_word(offset, queues); 112 LittleEndian::write_u16(data, v); 113 } 114 4 => { 115 let v = self.read_common_config_dword(offset, device); 116 LittleEndian::write_u32(data, v); 117 } 118 8 => { 119 let v = self.read_common_config_qword(offset); 120 LittleEndian::write_u64(data, v); 121 } 122 _ => error!("invalid data length for virtio read: len {}", data.len()), 123 } 124 } 125 126 pub fn write( 127 &mut self, 128 offset: u64, 129 data: &[u8], 130 queues: &mut [Queue], 131 device: Arc<Mutex<dyn VirtioDevice>>, 132 ) { 133 assert!(data.len() <= 8); 134 135 match data.len() { 136 1 => self.write_common_config_byte(offset, data[0]), 137 2 => self.write_common_config_word(offset, LittleEndian::read_u16(data), queues), 138 4 => { 139 self.write_common_config_dword(offset, LittleEndian::read_u32(data), queues, device) 140 } 141 8 => self.write_common_config_qword(offset, LittleEndian::read_u64(data), queues), 142 _ => error!("invalid data length for virtio write: len {}", data.len()), 143 } 144 } 145 146 fn read_common_config_byte(&self, offset: u64) -> u8 { 147 debug!("read_common_config_byte: offset 0x{:x}", offset); 148 // The driver is only allowed to do aligned, properly sized access. 149 match offset { 150 0x14 => self.driver_status, 151 0x15 => self.config_generation, 152 _ => { 153 warn!("invalid virtio config byte read: 0x{:x}", offset); 154 0 155 } 156 } 157 } 158 159 fn write_common_config_byte(&mut self, offset: u64, value: u8) { 160 debug!("write_common_config_byte: offset 0x{:x}", offset); 161 match offset { 162 0x14 => self.driver_status = value, 163 _ => { 164 warn!("invalid virtio config byte write: 0x{:x}", offset); 165 } 166 } 167 } 168 169 fn read_common_config_word(&self, offset: u64, queues: &[Queue]) -> u16 { 170 debug!("read_common_config_word: offset 0x{:x}", offset); 171 match offset { 172 0x10 => self.msix_config.load(Ordering::Acquire), 173 0x12 => queues.len() as u16, // num_queues 174 0x16 => self.queue_select, 175 0x18 => self.with_queue(queues, |q| q.size()).unwrap_or(0), 176 0x1a => self.msix_queues.lock().unwrap()[self.queue_select as usize], 177 0x1c => u16::from(self.with_queue(queues, |q| q.ready()).unwrap_or(false)), 178 0x1e => self.queue_select, // notify_off 179 _ => { 180 warn!("invalid virtio register word read: 0x{:x}", offset); 181 0 182 } 183 } 184 } 185 186 fn write_common_config_word(&mut self, offset: u64, value: u16, queues: &mut [Queue]) { 187 debug!("write_common_config_word: offset 0x{:x}", offset); 188 match offset { 189 0x10 => self.msix_config.store(value, Ordering::Release), 190 0x16 => self.queue_select = value, 191 0x18 => self.with_queue_mut(queues, |q| q.set_size(value)), 192 0x1a => self.msix_queues.lock().unwrap()[self.queue_select as usize] = value, 193 0x1c => self.with_queue_mut(queues, |q| { 194 let ready = value == 1; 195 q.set_ready(ready); 196 // Translate address of descriptor table and vrings. 197 if let Some(access_platform) = &self.access_platform { 198 if ready { 199 let desc_table = access_platform.translate_gva(q.desc_table(), 0).unwrap(); 200 let avail_ring = access_platform.translate_gva(q.avail_ring(), 0).unwrap(); 201 let used_ring = access_platform.translate_gva(q.used_ring(), 0).unwrap(); 202 q.set_desc_table_address( 203 Some((desc_table & 0xffff_ffff) as u32), 204 Some((desc_table >> 32) as u32), 205 ); 206 q.set_avail_ring_address( 207 Some((avail_ring & 0xffff_ffff) as u32), 208 Some((avail_ring >> 32) as u32), 209 ); 210 q.set_used_ring_address( 211 Some((used_ring & 0xffff_ffff) as u32), 212 Some((used_ring >> 32) as u32), 213 ); 214 } 215 } 216 }), 217 _ => { 218 warn!("invalid virtio register word write: 0x{:x}", offset); 219 } 220 } 221 } 222 223 fn read_common_config_dword(&self, offset: u64, device: Arc<Mutex<dyn VirtioDevice>>) -> u32 { 224 debug!("read_common_config_dword: offset 0x{:x}", offset); 225 match offset { 226 0x00 => self.device_feature_select, 227 0x04 => { 228 let locked_device = device.lock().unwrap(); 229 // Only 64 bits of features (2 pages) are defined for now, so limit 230 // device_feature_select to avoid shifting by 64 or more bits. 231 if self.device_feature_select < 2 { 232 (locked_device.features() >> (self.device_feature_select * 32)) as u32 233 } else { 234 0 235 } 236 } 237 0x08 => self.driver_feature_select, 238 _ => { 239 warn!("invalid virtio register dword read: 0x{:x}", offset); 240 0 241 } 242 } 243 } 244 245 fn write_common_config_dword( 246 &mut self, 247 offset: u64, 248 value: u32, 249 queues: &mut [Queue], 250 device: Arc<Mutex<dyn VirtioDevice>>, 251 ) { 252 debug!("write_common_config_dword: offset 0x{:x}", offset); 253 254 match offset { 255 0x00 => self.device_feature_select = value, 256 0x08 => self.driver_feature_select = value, 257 0x0c => { 258 if self.driver_feature_select < 2 { 259 let mut locked_device = device.lock().unwrap(); 260 locked_device 261 .ack_features(u64::from(value) << (self.driver_feature_select * 32)); 262 } else { 263 warn!( 264 "invalid ack_features (page {}, value 0x{:x})", 265 self.driver_feature_select, value 266 ); 267 } 268 } 269 0x20 => self.with_queue_mut(queues, |q| q.set_desc_table_address(Some(value), None)), 270 0x24 => self.with_queue_mut(queues, |q| q.set_desc_table_address(None, Some(value))), 271 0x28 => self.with_queue_mut(queues, |q| q.set_avail_ring_address(Some(value), None)), 272 0x2c => self.with_queue_mut(queues, |q| q.set_avail_ring_address(None, Some(value))), 273 0x30 => self.with_queue_mut(queues, |q| q.set_used_ring_address(Some(value), None)), 274 0x34 => self.with_queue_mut(queues, |q| q.set_used_ring_address(None, Some(value))), 275 _ => { 276 warn!("invalid virtio register dword write: 0x{:x}", offset); 277 } 278 } 279 } 280 281 fn read_common_config_qword(&self, _offset: u64) -> u64 { 282 debug!("read_common_config_qword: offset 0x{:x}", _offset); 283 0 // Assume the guest has no reason to read write-only registers. 284 } 285 286 fn write_common_config_qword(&mut self, offset: u64, value: u64, queues: &mut [Queue]) { 287 debug!("write_common_config_qword: offset 0x{:x}", offset); 288 289 let low = Some((value & 0xffff_ffff) as u32); 290 let high = Some((value >> 32) as u32); 291 292 match offset { 293 0x20 => self.with_queue_mut(queues, |q| q.set_desc_table_address(low, high)), 294 0x28 => self.with_queue_mut(queues, |q| q.set_avail_ring_address(low, high)), 295 0x30 => self.with_queue_mut(queues, |q| q.set_used_ring_address(low, high)), 296 _ => { 297 warn!("invalid virtio register qword write: 0x{:x}", offset); 298 } 299 } 300 } 301 302 fn with_queue<U, F>(&self, queues: &[Queue], f: F) -> Option<U> 303 where 304 F: FnOnce(&Queue) -> U, 305 { 306 queues.get(self.queue_select as usize).map(f) 307 } 308 309 fn with_queue_mut<F: FnOnce(&mut Queue)>(&self, queues: &mut [Queue], f: F) { 310 if let Some(queue) = queues.get_mut(self.queue_select as usize) { 311 f(queue); 312 } 313 } 314 } 315 316 impl Pausable for VirtioPciCommonConfig {} 317 318 impl Snapshottable for VirtioPciCommonConfig { 319 fn id(&self) -> String { 320 String::from(VIRTIO_PCI_COMMON_CONFIG_ID) 321 } 322 323 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 324 Snapshot::new_from_versioned_state(&self.id(), &self.state()) 325 } 326 } 327 328 #[cfg(test)] 329 mod tests { 330 use super::*; 331 use crate::GuestMemoryMmap; 332 use crate::{ActivateResult, VirtioInterrupt}; 333 use std::sync::Arc; 334 use virtio_queue::Queue; 335 use vm_memory::GuestMemoryAtomic; 336 use vmm_sys_util::eventfd::EventFd; 337 338 struct DummyDevice(u32); 339 const QUEUE_SIZE: u16 = 256; 340 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE]; 341 const DUMMY_FEATURES: u64 = 0x5555_aaaa; 342 impl VirtioDevice for DummyDevice { 343 fn device_type(&self) -> u32 { 344 self.0 345 } 346 fn queue_max_sizes(&self) -> &[u16] { 347 QUEUE_SIZES 348 } 349 fn activate( 350 &mut self, 351 _mem: GuestMemoryAtomic<GuestMemoryMmap>, 352 _interrupt_evt: Arc<dyn VirtioInterrupt>, 353 _queues: Vec<(usize, Queue, EventFd)>, 354 ) -> ActivateResult { 355 Ok(()) 356 } 357 358 fn features(&self) -> u64 { 359 DUMMY_FEATURES 360 } 361 362 fn ack_features(&mut self, _value: u64) {} 363 364 fn read_config(&self, _offset: u64, _data: &mut [u8]) {} 365 366 fn write_config(&mut self, _offset: u64, _data: &[u8]) {} 367 } 368 369 #[test] 370 fn write_base_regs() { 371 let mut regs = VirtioPciCommonConfig { 372 access_platform: None, 373 driver_status: 0xaa, 374 config_generation: 0x55, 375 device_feature_select: 0x0, 376 driver_feature_select: 0x0, 377 queue_select: 0xff, 378 msix_config: Arc::new(AtomicU16::new(0)), 379 msix_queues: Arc::new(Mutex::new(vec![0; 3])), 380 }; 381 382 let dev = Arc::new(Mutex::new(DummyDevice(0))); 383 let mut queues = Vec::new(); 384 385 // Can set all bits of driver_status. 386 regs.write(0x14, &[0x55], &mut queues, dev.clone()); 387 let mut read_back = vec![0x00]; 388 regs.read(0x14, &mut read_back, &mut queues, dev.clone()); 389 assert_eq!(read_back[0], 0x55); 390 391 // The config generation register is read only. 392 regs.write(0x15, &[0xaa], &mut queues, dev.clone()); 393 let mut read_back = vec![0x00]; 394 regs.read(0x15, &mut read_back, &mut queues, dev.clone()); 395 assert_eq!(read_back[0], 0x55); 396 397 // Device features is read-only and passed through from the device. 398 regs.write(0x04, &[0, 0, 0, 0], &mut queues, dev.clone()); 399 let mut read_back = vec![0, 0, 0, 0]; 400 regs.read(0x04, &mut read_back, &mut queues, dev.clone()); 401 assert_eq!(LittleEndian::read_u32(&read_back), DUMMY_FEATURES as u32); 402 403 // Feature select registers are read/write. 404 regs.write(0x00, &[1, 2, 3, 4], &mut queues, dev.clone()); 405 let mut read_back = vec![0, 0, 0, 0]; 406 regs.read(0x00, &mut read_back, &mut queues, dev.clone()); 407 assert_eq!(LittleEndian::read_u32(&read_back), 0x0403_0201); 408 regs.write(0x08, &[1, 2, 3, 4], &mut queues, dev.clone()); 409 let mut read_back = vec![0, 0, 0, 0]; 410 regs.read(0x08, &mut read_back, &mut queues, dev.clone()); 411 assert_eq!(LittleEndian::read_u32(&read_back), 0x0403_0201); 412 413 // 'queue_select' can be read and written. 414 regs.write(0x16, &[0xaa, 0x55], &mut queues, dev.clone()); 415 let mut read_back = vec![0x00, 0x00]; 416 regs.read(0x16, &mut read_back, &mut queues, dev); 417 assert_eq!(read_back[0], 0xaa); 418 assert_eq!(read_back[1], 0x55); 419 } 420 } 421