1 // Copyright 2021 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 //! Implements a stub PCI device. This can be used to put a device on the PCI bus that will 6 //! show up in PCI device enumeration with the configured parameters. The device will otherwise be 7 //! non-functional, in particular it doesn't have any BARs, IRQs etc. and neither will it handle 8 //! config register interactions. 9 //! 10 //! The motivation for stub PCI devices is the case of multifunction PCI devices getting passed 11 //! through via VFIO to the guest. Per PCI device enumeration, functions other than 0 will only be 12 //! scanned if function 0 is present. A stub PCI device is useful in that situation to present 13 //! something to the guest on function 0. 14 15 use base::RawDescriptor; 16 use resources::Alloc; 17 use resources::SystemAllocator; 18 use serde::Deserialize; 19 use serde::Deserializer; 20 use serde::Serialize; 21 use serde::Serializer; 22 23 use crate::pci::pci_configuration::PciBarConfiguration; 24 use crate::pci::pci_configuration::PciClassCode; 25 use crate::pci::pci_configuration::PciConfiguration; 26 use crate::pci::pci_configuration::PciHeaderType; 27 use crate::pci::pci_configuration::PciProgrammingInterface; 28 use crate::pci::pci_configuration::PciSubclass; 29 use crate::pci::pci_device::PciDevice; 30 use crate::pci::pci_device::Result; 31 use crate::pci::PciAddress; 32 use crate::pci::PciBarIndex; 33 use crate::pci::PciDeviceError; 34 use crate::Suspendable; 35 36 #[derive(Debug)] 37 pub struct PciClassParameters { 38 pub class: PciClassCode, 39 pub subclass: u8, 40 pub programming_interface: u8, 41 } 42 43 impl Default for PciClassParameters { default() -> Self44 fn default() -> Self { 45 PciClassParameters { 46 class: PciClassCode::Other, 47 subclass: 0, 48 programming_interface: 0, 49 } 50 } 51 } 52 53 // Deserialize the combined class, subclass, and programming interface as a single numeric value. 54 // This matches the numeric format used in `/sys/bus/pci/devices/*/class`. 55 impl<'de> Deserialize<'de> for PciClassParameters { deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error> where D: Deserializer<'de>,56 fn deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error> 57 where 58 D: Deserializer<'de>, 59 { 60 let class_numeric = u32::deserialize(deserializer)?; 61 62 let class_code = (class_numeric >> 16) as u8; 63 let class = PciClassCode::try_from(class_code).map_err(|_| { 64 serde::de::Error::custom(format!("Unknown class code {:#x}", class_code)) 65 })?; 66 67 let subclass = (class_numeric >> 8) as u8; 68 69 let programming_interface = class_numeric as u8; 70 71 Ok(PciClassParameters { 72 class, 73 subclass, 74 programming_interface, 75 }) 76 } 77 } 78 79 impl Serialize for PciClassParameters { serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,80 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> 81 where 82 S: Serializer, 83 { 84 let class_numeric: u32 = ((self.class as u32) << 16) 85 | ((self.subclass as u32) << 8) 86 | self.programming_interface as u32; 87 88 serializer.serialize_u32(class_numeric) 89 } 90 } 91 92 #[derive(Serialize, Deserialize, Debug, serde_keyvalue::FromKeyValues)] 93 #[serde(deny_unknown_fields, rename_all = "kebab-case")] 94 pub struct StubPciParameters { 95 pub address: PciAddress, 96 #[serde(default)] 97 pub vendor: u16, 98 #[serde(default)] 99 pub device: u16, 100 #[serde(default)] 101 pub class: PciClassParameters, 102 #[serde(default, alias = "subsystem_vendor")] 103 pub subsystem_vendor: u16, 104 #[serde(default, alias = "subsystem_device")] 105 pub subsystem_device: u16, 106 #[serde(default)] 107 pub revision: u8, 108 } 109 110 pub struct StubPciDevice { 111 requested_address: PciAddress, 112 assigned_address: Option<PciAddress>, 113 config_regs: PciConfiguration, 114 } 115 116 struct NumericPciSubClass(u8); 117 118 impl PciSubclass for NumericPciSubClass { get_register_value(&self) -> u8119 fn get_register_value(&self) -> u8 { 120 self.0 121 } 122 } 123 124 struct NumericPciProgrammingInterface(u8); 125 126 impl PciProgrammingInterface for NumericPciProgrammingInterface { get_register_value(&self) -> u8127 fn get_register_value(&self) -> u8 { 128 self.0 129 } 130 } 131 132 impl StubPciDevice { new(config: &StubPciParameters) -> StubPciDevice133 pub fn new(config: &StubPciParameters) -> StubPciDevice { 134 let config_regs = PciConfiguration::new( 135 config.vendor, 136 config.device, 137 config.class.class, 138 &NumericPciSubClass(config.class.subclass), 139 Some(&NumericPciProgrammingInterface( 140 config.class.programming_interface, 141 )), 142 PciHeaderType::Device, 143 config.subsystem_vendor, 144 config.subsystem_device, 145 config.revision, 146 ); 147 148 Self { 149 requested_address: config.address, 150 assigned_address: None, 151 config_regs, 152 } 153 } 154 } 155 156 impl PciDevice for StubPciDevice { debug_label(&self) -> String157 fn debug_label(&self) -> String { 158 "Stub".to_owned() 159 } 160 preferred_address(&self) -> Option<PciAddress>161 fn preferred_address(&self) -> Option<PciAddress> { 162 Some(self.requested_address) 163 } 164 allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>165 fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> { 166 if self.assigned_address.is_none() { 167 if resources.reserve_pci( 168 Alloc::PciBar { 169 bus: self.requested_address.bus, 170 dev: self.requested_address.dev, 171 func: self.requested_address.func, 172 bar: 0, 173 }, 174 self.debug_label(), 175 ) { 176 self.assigned_address = Some(self.requested_address); 177 } 178 } 179 self.assigned_address 180 .ok_or(PciDeviceError::PciAllocationFailed) 181 } 182 keep_rds(&self) -> Vec<RawDescriptor>183 fn keep_rds(&self) -> Vec<RawDescriptor> { 184 Vec::new() 185 } 186 get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>187 fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> { 188 self.config_regs.get_bar_configuration(bar_num) 189 } 190 read_config_register(&self, reg_idx: usize) -> u32191 fn read_config_register(&self, reg_idx: usize) -> u32 { 192 self.config_regs.read_reg(reg_idx) 193 } 194 write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])195 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 196 self.config_regs.write_reg(reg_idx, offset, data); 197 } 198 read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8])199 fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {} 200 write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8])201 fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {} 202 } 203 204 impl Suspendable for StubPciDevice { sleep(&mut self) -> anyhow::Result<()>205 fn sleep(&mut self) -> anyhow::Result<()> { 206 // There are no workers to sleep/wake. 207 Ok(()) 208 } 209 wake(&mut self) -> anyhow::Result<()>210 fn wake(&mut self) -> anyhow::Result<()> { 211 // There are no workers to sleep/wake. 212 Ok(()) 213 } 214 snapshot(&mut self) -> anyhow::Result<serde_json::Value>215 fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> { 216 self.config_regs.snapshot() 217 } 218 restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>219 fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> { 220 self.config_regs.restore(data) 221 } 222 } 223 224 #[cfg(test)] 225 mod test { 226 use resources::AddressRange; 227 use resources::SystemAllocator; 228 use resources::SystemAllocatorConfig; 229 use serde_keyvalue::from_key_values; 230 use serde_keyvalue::ErrorKind; 231 use serde_keyvalue::ParseError; 232 233 use super::*; 234 235 const CONFIG: StubPciParameters = StubPciParameters { 236 address: PciAddress { 237 bus: 0x0a, 238 dev: 0x0b, 239 func: 0x1, 240 }, 241 vendor: 2, 242 device: 3, 243 class: PciClassParameters { 244 class: PciClassCode::MultimediaController, 245 subclass: 5, 246 programming_interface: 6, 247 }, 248 subsystem_vendor: 7, 249 subsystem_device: 8, 250 revision: 9, 251 }; 252 from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError>253 fn from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError> { 254 from_key_values(options) 255 } 256 257 #[test] configuration()258 fn configuration() { 259 let device = StubPciDevice::new(&CONFIG); 260 261 assert_eq!(device.read_config_register(0), 0x0003_0002); 262 assert_eq!(device.read_config_register(2), 0x04_05_06_09); 263 assert_eq!(device.read_config_register(11), 0x0008_0007); 264 } 265 266 #[test] address_allocation()267 fn address_allocation() { 268 let mut allocator = SystemAllocator::new( 269 SystemAllocatorConfig { 270 io: Some(AddressRange { 271 start: 0x1000, 272 end: 0x2fff, 273 }), 274 low_mmio: AddressRange { 275 start: 0x2000_0000, 276 end: 0x2fff_ffff, 277 }, 278 high_mmio: AddressRange { 279 start: 0x1_0000_0000, 280 end: 0x1_0fff_ffff, 281 }, 282 platform_mmio: None, 283 first_irq: 5, 284 }, 285 None, 286 &[], 287 ) 288 .unwrap(); 289 let mut device = StubPciDevice::new(&CONFIG); 290 291 assert!(device.allocate_address(&mut allocator).is_ok()); 292 assert!(allocator.release_pci(0xa, 0xb, 1)); 293 } 294 295 #[test] params_missing_address()296 fn params_missing_address() { 297 // PCI address argument is mandatory. 298 let err = from_stub_arg("").unwrap_err(); 299 assert_eq!( 300 err, 301 ParseError { 302 kind: ErrorKind::SerdeError("missing field `address`".into()), 303 pos: 0, 304 } 305 ); 306 } 307 308 #[test] params_address_implicit()309 fn params_address_implicit() { 310 // Address is the default argument. 311 let params = from_stub_arg("0000:00:01.2").unwrap(); 312 assert_eq!( 313 params.address, 314 PciAddress { 315 bus: 0, 316 dev: 1, 317 func: 2 318 } 319 ); 320 } 321 322 #[test] params_address_explicit()323 fn params_address_explicit() { 324 // Explicitly-specified address. 325 let params = from_stub_arg("address=0000:00:01.2").unwrap(); 326 assert_eq!( 327 params.address, 328 PciAddress { 329 bus: 0, 330 dev: 1, 331 func: 2 332 } 333 ); 334 } 335 336 #[test] params_class()337 fn params_class() { 338 // Class, subclass, and programming interface are encoded as a single number. 339 let params = from_stub_arg("address=0000:00:01.2,class=0x012345").unwrap(); 340 assert_eq!(params.class.class, PciClassCode::MassStorage); 341 assert_eq!(params.class.subclass, 0x23); 342 assert_eq!(params.class.programming_interface, 0x45); 343 } 344 345 #[test] params_subsystem_underscores()346 fn params_subsystem_underscores() { 347 // Accept aliases with underscores rather than hyphens for compatibility. 348 let params = 349 from_stub_arg("address=0000:00:01.2,subsystem_vendor=0x8675,subsystem_device=0x309") 350 .unwrap(); 351 assert_eq!(params.subsystem_vendor, 0x8675); 352 assert_eq!(params.subsystem_device, 0x0309); 353 } 354 355 #[test] params_full()356 fn params_full() { 357 let params = from_stub_arg( 358 "address=0000:00:01.2,vendor=0x1234,device=0x5678,subsystem-vendor=0x8675,subsystem-device=0x309,class=0x012345,revision=52", 359 ).unwrap(); 360 assert_eq!( 361 params.address, 362 PciAddress { 363 bus: 0, 364 dev: 1, 365 func: 2 366 } 367 ); 368 assert_eq!(params.vendor, 0x1234); 369 assert_eq!(params.device, 0x5678); 370 assert_eq!(params.subsystem_vendor, 0x8675); 371 assert_eq!(params.subsystem_device, 0x0309); 372 assert_eq!(params.class.class, PciClassCode::MassStorage); 373 assert_eq!(params.class.subclass, 0x23); 374 assert_eq!(params.class.programming_interface, 0x45); 375 assert_eq!(params.revision, 52); 376 } 377 378 #[test] stub_pci_device_snapshot_restore() -> anyhow::Result<()>379 fn stub_pci_device_snapshot_restore() -> anyhow::Result<()> { 380 let mut device = StubPciDevice::new(&CONFIG); 381 let init_reg_value = device.read_config_register(1); 382 let snapshot_init = device.snapshot().unwrap(); 383 384 // Modify config reg 1 and make sure it went through. 385 let new_reg_value: u32 = 0xCAFE; 386 device.write_config_register(1, 0, &new_reg_value.to_le_bytes()); 387 assert_eq!(device.read_config_register(1), new_reg_value); 388 389 // Capture a snapshot after the modification. 390 let mut snapshot_modified = device.snapshot().unwrap(); 391 assert_ne!(snapshot_init, snapshot_modified); 392 393 // Modify the same register and verify that it's restored correctly. 394 device.write_config_register(1, 0, &[0xBA, 0xBA]); 395 assert_ne!(device.read_config_register(1), new_reg_value); 396 assert_ne!(device.read_config_register(1), init_reg_value); 397 device.restore(snapshot_init.clone())?; 398 assert_eq!(device.read_config_register(1), init_reg_value); 399 400 // Capture a snapshot after restoring the initial snapshot. 401 let mut snapshot_restored = device.snapshot().unwrap(); 402 assert_eq!(snapshot_init, snapshot_restored); 403 404 // Restore to the first modification and verify the values. 405 device.restore(snapshot_modified.clone())?; 406 assert_eq!(device.read_config_register(1), new_reg_value); 407 snapshot_restored = device.snapshot().unwrap(); 408 assert_eq!(snapshot_modified, snapshot_restored); 409 410 /* 411 Restore the initial snapshot and verify that addresses are not encoded. 412 The addresses are only configurable during VM creation so they never 413 change afterwards and are not part of the snapshot. Force a change 414 to requested_address to confirm that. 415 */ 416 device.restore(snapshot_init.clone())?; 417 device.requested_address = PciAddress { 418 bus: 0x0d, 419 dev: 0x0e, 420 func: 0x4, 421 }; 422 snapshot_modified = device.snapshot().unwrap(); 423 assert_eq!(snapshot_init, snapshot_modified); 424 425 Ok(()) 426 } 427 } 428