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