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 file. 4 5 use std::convert::TryInto; 6 7 use base::warn; 8 use vm_memory::GuestAddress; 9 10 use super::*; 11 12 /// Contains the data for reading and writing the common configuration structure of a virtio PCI 13 /// device. 14 /// 15 /// * Registers: 16 /// ** About the whole device. 17 /// le32 device_feature_select; // read-write 18 /// le32 device_feature; // read-only for driver 19 /// le32 driver_feature_select; // read-write 20 /// le32 driver_feature; // read-write 21 /// le16 msix_config; // read-write 22 /// le16 num_queues; // read-only for driver 23 /// u8 device_status; // read-write (driver_status) 24 /// u8 config_generation; // read-only for driver 25 /// ** About a specific virtqueue. 26 /// le16 queue_select; // read-write 27 /// le16 queue_size; // read-write, power of 2, or 0. 28 /// le16 queue_msix_vector; // read-write 29 /// le16 queue_enable; // read-write (Ready) 30 /// le16 queue_notify_off; // read-only for driver 31 /// le64 queue_desc; // read-write 32 /// le64 queue_avail; // read-write 33 /// le64 queue_used; // read-write 34 pub struct VirtioPciCommonConfig { 35 pub driver_status: u8, 36 pub config_generation: u8, 37 pub device_feature_select: u32, 38 pub driver_feature_select: u32, 39 pub queue_select: u16, 40 pub msix_config: u16, 41 } 42 43 impl VirtioPciCommonConfig { read( &mut self, offset: u64, data: &mut [u8], queues: &mut [Queue], device: &mut dyn VirtioDevice, )44 pub fn read( 45 &mut self, 46 offset: u64, 47 data: &mut [u8], 48 queues: &mut [Queue], 49 device: &mut dyn VirtioDevice, 50 ) { 51 match data.len() { 52 1 => { 53 let v = self.read_common_config_byte(offset); 54 data[0] = v; 55 } 56 2 => { 57 let v = self.read_common_config_word(offset, queues); 58 data.copy_from_slice(&v.to_le_bytes()); 59 } 60 4 => { 61 let v = self.read_common_config_dword(offset, device); 62 data.copy_from_slice(&v.to_le_bytes()); 63 } 64 8 => { 65 let v = self.read_common_config_qword(offset); 66 data.copy_from_slice(&v.to_le_bytes()); 67 } 68 _ => (), 69 } 70 } 71 write( &mut self, offset: u64, data: &[u8], queues: &mut [Queue], device: &mut dyn VirtioDevice, )72 pub fn write( 73 &mut self, 74 offset: u64, 75 data: &[u8], 76 queues: &mut [Queue], 77 device: &mut dyn VirtioDevice, 78 ) { 79 match data.len() { 80 1 => self.write_common_config_byte(offset, data[0]), 81 2 => self.write_common_config_word( 82 offset, 83 // This unwrap (and those below) cannot fail since data.len() is checked. 84 u16::from_le_bytes(data.try_into().unwrap()), 85 queues, 86 ), 87 4 => self.write_common_config_dword( 88 offset, 89 u32::from_le_bytes(data.try_into().unwrap()), 90 queues, 91 device, 92 ), 93 8 => self.write_common_config_qword( 94 offset, 95 u64::from_le_bytes(data.try_into().unwrap()), 96 queues, 97 ), 98 _ => (), 99 } 100 } 101 read_common_config_byte(&self, offset: u64) -> u8102 fn read_common_config_byte(&self, offset: u64) -> u8 { 103 // The driver is only allowed to do aligned, properly sized access. 104 match offset { 105 0x14 => self.driver_status, 106 0x15 => self.config_generation, 107 _ => 0, 108 } 109 } 110 write_common_config_byte(&mut self, offset: u64, value: u8)111 fn write_common_config_byte(&mut self, offset: u64, value: u8) { 112 match offset { 113 0x14 => self.driver_status = value, 114 _ => { 115 warn!("invalid virtio config byt access: 0x{:x}", offset); 116 } 117 } 118 } 119 read_common_config_word(&self, offset: u64, queues: &[Queue]) -> u16120 fn read_common_config_word(&self, offset: u64, queues: &[Queue]) -> u16 { 121 match offset { 122 0x10 => self.msix_config, 123 0x12 => queues.len() as u16, // num_queues 124 0x16 => self.queue_select, 125 0x18 => self.with_queue(queues, |q| q.size).unwrap_or(0), 126 0x1a => self.with_queue(queues, |q| q.vector).unwrap_or(0), 127 0x1c => { 128 if self.with_queue(queues, |q| q.ready).unwrap_or(false) { 129 1 130 } else { 131 0 132 } 133 } 134 0x1e => self.queue_select, // notify_off 135 _ => 0, 136 } 137 } 138 write_common_config_word(&mut self, offset: u64, value: u16, queues: &mut [Queue])139 fn write_common_config_word(&mut self, offset: u64, value: u16, queues: &mut [Queue]) { 140 match offset { 141 0x10 => self.msix_config = value, 142 0x16 => self.queue_select = value, 143 0x18 => self.with_queue_mut(queues, |q| q.size = value), 144 0x1a => self.with_queue_mut(queues, |q| q.vector = value), 145 0x1c => self.with_queue_mut(queues, |q| q.ready = value == 1), 146 _ => { 147 warn!("invalid virtio register word write: 0x{:x}", offset); 148 } 149 } 150 } 151 read_common_config_dword(&self, offset: u64, device: &dyn VirtioDevice) -> u32152 fn read_common_config_dword(&self, offset: u64, device: &dyn VirtioDevice) -> u32 { 153 match offset { 154 0x00 => self.device_feature_select, 155 0x04 => { 156 // Only 64 bits of features (2 pages) are defined for now, so limit 157 // device_feature_select to avoid shifting by 64 or more bits. 158 if self.device_feature_select < 2 { 159 (device.features() >> (self.device_feature_select * 32)) as u32 160 } else { 161 0 162 } 163 } 164 0x08 => self.driver_feature_select, 165 _ => 0, 166 } 167 } 168 write_common_config_dword( &mut self, offset: u64, value: u32, queues: &mut [Queue], device: &mut dyn VirtioDevice, )169 fn write_common_config_dword( 170 &mut self, 171 offset: u64, 172 value: u32, 173 queues: &mut [Queue], 174 device: &mut dyn VirtioDevice, 175 ) { 176 fn hi(v: &mut GuestAddress, x: u32) { 177 *v = (*v & 0xffffffff) | ((x as u64) << 32) 178 } 179 180 fn lo(v: &mut GuestAddress, x: u32) { 181 *v = (*v & !0xffffffff) | (x as u64) 182 } 183 184 match offset { 185 0x00 => self.device_feature_select = value, 186 0x08 => self.driver_feature_select = value, 187 0x0c => { 188 if self.driver_feature_select < 2 { 189 let features: u64 = (value as u64) << (self.driver_feature_select * 32); 190 device.ack_features(features); 191 for queue in queues.iter_mut() { 192 queue.ack_features(features); 193 } 194 } else { 195 warn!( 196 "invalid ack_features (page {}, value 0x{:x})", 197 self.driver_feature_select, value 198 ); 199 } 200 } 201 0x20 => self.with_queue_mut(queues, |q| lo(&mut q.desc_table, value)), 202 0x24 => self.with_queue_mut(queues, |q| hi(&mut q.desc_table, value)), 203 0x28 => self.with_queue_mut(queues, |q| lo(&mut q.avail_ring, value)), 204 0x2c => self.with_queue_mut(queues, |q| hi(&mut q.avail_ring, value)), 205 0x30 => self.with_queue_mut(queues, |q| lo(&mut q.used_ring, value)), 206 0x34 => self.with_queue_mut(queues, |q| hi(&mut q.used_ring, value)), 207 _ => { 208 warn!("invalid virtio register dword write: 0x{:x}", offset); 209 } 210 } 211 } 212 read_common_config_qword(&self, _offset: u64) -> u64213 fn read_common_config_qword(&self, _offset: u64) -> u64 { 214 0 // Assume the guest has no reason to read write-only registers. 215 } 216 write_common_config_qword(&mut self, offset: u64, value: u64, queues: &mut [Queue])217 fn write_common_config_qword(&mut self, offset: u64, value: u64, queues: &mut [Queue]) { 218 match offset { 219 0x20 => self.with_queue_mut(queues, |q| q.desc_table = GuestAddress(value)), 220 0x28 => self.with_queue_mut(queues, |q| q.avail_ring = GuestAddress(value)), 221 0x30 => self.with_queue_mut(queues, |q| q.used_ring = GuestAddress(value)), 222 _ => { 223 warn!("invalid virtio register qword write: 0x{:x}", offset); 224 } 225 } 226 } 227 with_queue<U, F>(&self, queues: &[Queue], f: F) -> Option<U> where F: FnOnce(&Queue) -> U,228 fn with_queue<U, F>(&self, queues: &[Queue], f: F) -> Option<U> 229 where 230 F: FnOnce(&Queue) -> U, 231 { 232 queues.get(self.queue_select as usize).map(f) 233 } 234 with_queue_mut<F: FnOnce(&mut Queue)>(&self, queues: &mut [Queue], f: F)235 fn with_queue_mut<F: FnOnce(&mut Queue)>(&self, queues: &mut [Queue], f: F) { 236 if let Some(queue) = queues.get_mut(self.queue_select as usize) { 237 f(queue); 238 } 239 } 240 } 241 242 #[cfg(test)] 243 mod tests { 244 use super::*; 245 246 use base::{Event, RawDescriptor}; 247 use vm_memory::GuestMemory; 248 249 struct DummyDevice(u32); 250 const QUEUE_SIZE: u16 = 256; 251 const QUEUE_SIZES: &'static [u16] = &[QUEUE_SIZE]; 252 const DUMMY_FEATURES: u64 = 0x5555_aaaa; 253 impl VirtioDevice for DummyDevice { keep_rds(&self) -> Vec<RawDescriptor>254 fn keep_rds(&self) -> Vec<RawDescriptor> { 255 Vec::new() 256 } device_type(&self) -> u32257 fn device_type(&self) -> u32 { 258 return self.0; 259 } queue_max_sizes(&self) -> &[u16]260 fn queue_max_sizes(&self) -> &[u16] { 261 QUEUE_SIZES 262 } activate( &mut self, _mem: GuestMemory, _interrupt: Interrupt, _queues: Vec<Queue>, _queue_evts: Vec<Event>, )263 fn activate( 264 &mut self, 265 _mem: GuestMemory, 266 _interrupt: Interrupt, 267 _queues: Vec<Queue>, 268 _queue_evts: Vec<Event>, 269 ) { 270 } features(&self) -> u64271 fn features(&self) -> u64 { 272 DUMMY_FEATURES 273 } 274 } 275 276 #[test] write_base_regs()277 fn write_base_regs() { 278 let mut regs = VirtioPciCommonConfig { 279 driver_status: 0xaa, 280 config_generation: 0x55, 281 device_feature_select: 0x0, 282 driver_feature_select: 0x0, 283 queue_select: 0xff, 284 msix_config: 0x00, 285 }; 286 287 let dev = &mut DummyDevice(0) as &mut dyn VirtioDevice; 288 let mut queues = Vec::new(); 289 290 // Can set all bits of driver_status. 291 regs.write(0x14, &[0x55], &mut queues, dev); 292 let mut read_back = vec![0x00]; 293 regs.read(0x14, &mut read_back, &mut queues, dev); 294 assert_eq!(read_back[0], 0x55); 295 296 // The config generation register is read only. 297 regs.write(0x15, &[0xaa], &mut queues, dev); 298 let mut read_back = vec![0x00]; 299 regs.read(0x15, &mut read_back, &mut queues, dev); 300 assert_eq!(read_back[0], 0x55); 301 302 // Device features is read-only and passed through from the device. 303 regs.write(0x04, &[0, 0, 0, 0], &mut queues, dev); 304 let mut read_back = [0u8; 4]; 305 regs.read(0x04, &mut read_back, &mut queues, dev); 306 assert_eq!(u32::from_le_bytes(read_back), DUMMY_FEATURES as u32); 307 308 // Feature select registers are read/write. 309 regs.write(0x00, &[1, 2, 3, 4], &mut queues, dev); 310 let mut read_back = [0u8; 4]; 311 regs.read(0x00, &mut read_back, &mut queues, dev); 312 assert_eq!(u32::from_le_bytes(read_back), 0x0403_0201); 313 regs.write(0x08, &[1, 2, 3, 4], &mut queues, dev); 314 let mut read_back = [0u8; 4]; 315 regs.read(0x08, &mut read_back, &mut queues, dev); 316 assert_eq!(u32::from_le_bytes(read_back), 0x0403_0201); 317 318 // 'queue_select' can be read and written. 319 regs.write(0x16, &[0xaa, 0x55], &mut queues, dev); 320 let mut read_back = vec![0x00, 0x00]; 321 regs.read(0x16, &mut read_back, &mut queues, dev); 322 assert_eq!(read_back[0], 0xaa); 323 assert_eq!(read_back[1], 0x55); 324 } 325 } 326