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::SystemAllocator; 17 use serde::Deserialize; 18 use serde::Deserializer; 19 use serde::Serialize; 20 use serde::Serializer; 21 use snapshot::AnySnapshot; 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(self.requested_address, self.debug_label()) { 168 self.assigned_address = Some(self.requested_address); 169 } 170 } 171 self.assigned_address 172 .ok_or(PciDeviceError::PciAllocationFailed) 173 } 174 keep_rds(&self) -> Vec<RawDescriptor>175 fn keep_rds(&self) -> Vec<RawDescriptor> { 176 Vec::new() 177 } 178 get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>179 fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> { 180 self.config_regs.get_bar_configuration(bar_num) 181 } 182 read_config_register(&self, reg_idx: usize) -> u32183 fn read_config_register(&self, reg_idx: usize) -> u32 { 184 self.config_regs.read_reg(reg_idx) 185 } 186 write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])187 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 188 self.config_regs.write_reg(reg_idx, offset, data); 189 } 190 read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8])191 fn read_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &mut [u8]) {} 192 write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8])193 fn write_bar(&mut self, _bar_index: PciBarIndex, _offset: u64, _data: &[u8]) {} 194 } 195 196 impl Suspendable for StubPciDevice { sleep(&mut self) -> anyhow::Result<()>197 fn sleep(&mut self) -> anyhow::Result<()> { 198 // There are no workers to sleep/wake. 199 Ok(()) 200 } 201 wake(&mut self) -> anyhow::Result<()>202 fn wake(&mut self) -> anyhow::Result<()> { 203 // There are no workers to sleep/wake. 204 Ok(()) 205 } 206 snapshot(&mut self) -> anyhow::Result<AnySnapshot>207 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> { 208 self.config_regs.snapshot() 209 } 210 restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>211 fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> { 212 self.config_regs.restore(data) 213 } 214 } 215 216 #[cfg(test)] 217 mod test { 218 use resources::AddressRange; 219 use resources::SystemAllocator; 220 use resources::SystemAllocatorConfig; 221 use serde_keyvalue::from_key_values; 222 use serde_keyvalue::ErrorKind; 223 use serde_keyvalue::ParseError; 224 225 use super::*; 226 227 const CONFIG: StubPciParameters = StubPciParameters { 228 address: PciAddress { 229 bus: 0x0a, 230 dev: 0x0b, 231 func: 0x1, 232 }, 233 vendor: 2, 234 device: 3, 235 class: PciClassParameters { 236 class: PciClassCode::MultimediaController, 237 subclass: 5, 238 programming_interface: 6, 239 }, 240 subsystem_vendor: 7, 241 subsystem_device: 8, 242 revision: 9, 243 }; 244 from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError>245 fn from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError> { 246 from_key_values(options) 247 } 248 249 #[test] configuration()250 fn configuration() { 251 let device = StubPciDevice::new(&CONFIG); 252 253 assert_eq!(device.read_config_register(0), 0x0003_0002); 254 assert_eq!(device.read_config_register(2), 0x04_05_06_09); 255 assert_eq!(device.read_config_register(11), 0x0008_0007); 256 } 257 258 #[test] address_allocation()259 fn address_allocation() { 260 let mut allocator = SystemAllocator::new( 261 SystemAllocatorConfig { 262 io: Some(AddressRange { 263 start: 0x1000, 264 end: 0x2fff, 265 }), 266 low_mmio: AddressRange { 267 start: 0x2000_0000, 268 end: 0x2fff_ffff, 269 }, 270 high_mmio: AddressRange { 271 start: 0x1_0000_0000, 272 end: 0x1_0fff_ffff, 273 }, 274 platform_mmio: None, 275 first_irq: 5, 276 }, 277 None, 278 &[], 279 ) 280 .unwrap(); 281 let mut device = StubPciDevice::new(&CONFIG); 282 283 assert!(device.allocate_address(&mut allocator).is_ok()); 284 assert!(allocator.release_pci(PciAddress::new(0, 0xa, 0xb, 1).unwrap())); 285 } 286 287 #[test] params_missing_address()288 fn params_missing_address() { 289 // PCI address argument is mandatory. 290 let err = from_stub_arg("").unwrap_err(); 291 assert_eq!( 292 err, 293 ParseError { 294 kind: ErrorKind::SerdeError("missing field `address`".into()), 295 pos: 0, 296 } 297 ); 298 } 299 300 #[test] params_address_implicit()301 fn params_address_implicit() { 302 // Address is the default argument. 303 let params = from_stub_arg("0000:00:01.2").unwrap(); 304 assert_eq!( 305 params.address, 306 PciAddress { 307 bus: 0, 308 dev: 1, 309 func: 2 310 } 311 ); 312 } 313 314 #[test] params_address_explicit()315 fn params_address_explicit() { 316 // Explicitly-specified address. 317 let params = from_stub_arg("address=0000:00:01.2").unwrap(); 318 assert_eq!( 319 params.address, 320 PciAddress { 321 bus: 0, 322 dev: 1, 323 func: 2 324 } 325 ); 326 } 327 328 #[test] params_class()329 fn params_class() { 330 // Class, subclass, and programming interface are encoded as a single number. 331 let params = from_stub_arg("address=0000:00:01.2,class=0x012345").unwrap(); 332 assert_eq!(params.class.class, PciClassCode::MassStorage); 333 assert_eq!(params.class.subclass, 0x23); 334 assert_eq!(params.class.programming_interface, 0x45); 335 } 336 337 #[test] params_subsystem_underscores()338 fn params_subsystem_underscores() { 339 // Accept aliases with underscores rather than hyphens for compatibility. 340 let params = 341 from_stub_arg("address=0000:00:01.2,subsystem_vendor=0x8675,subsystem_device=0x309") 342 .unwrap(); 343 assert_eq!(params.subsystem_vendor, 0x8675); 344 assert_eq!(params.subsystem_device, 0x0309); 345 } 346 347 #[test] params_full()348 fn params_full() { 349 let params = from_stub_arg( 350 "address=0000:00:01.2,vendor=0x1234,device=0x5678,subsystem-vendor=0x8675,subsystem-device=0x309,class=0x012345,revision=52", 351 ).unwrap(); 352 assert_eq!( 353 params.address, 354 PciAddress { 355 bus: 0, 356 dev: 1, 357 func: 2 358 } 359 ); 360 assert_eq!(params.vendor, 0x1234); 361 assert_eq!(params.device, 0x5678); 362 assert_eq!(params.subsystem_vendor, 0x8675); 363 assert_eq!(params.subsystem_device, 0x0309); 364 assert_eq!(params.class.class, PciClassCode::MassStorage); 365 assert_eq!(params.class.subclass, 0x23); 366 assert_eq!(params.class.programming_interface, 0x45); 367 assert_eq!(params.revision, 52); 368 } 369 370 #[test] stub_pci_device_snapshot_restore() -> anyhow::Result<()>371 fn stub_pci_device_snapshot_restore() -> anyhow::Result<()> { 372 let mut device = StubPciDevice::new(&CONFIG); 373 let init_reg_value = device.read_config_register(1); 374 let snapshot_init = device.snapshot().unwrap(); 375 376 // Modify config reg 1 and make sure it went through. 377 let new_reg_value: u32 = 0xCAFE; 378 device.write_config_register(1, 0, &new_reg_value.to_le_bytes()); 379 assert_eq!(device.read_config_register(1), new_reg_value); 380 381 // Capture a snapshot after the modification. 382 let mut snapshot_modified = device.snapshot().unwrap(); 383 assert_ne!(snapshot_init, snapshot_modified); 384 385 // Modify the same register and verify that it's restored correctly. 386 device.write_config_register(1, 0, &[0xBA, 0xBA]); 387 assert_ne!(device.read_config_register(1), new_reg_value); 388 assert_ne!(device.read_config_register(1), init_reg_value); 389 device.restore(snapshot_init.clone())?; 390 assert_eq!(device.read_config_register(1), init_reg_value); 391 392 // Capture a snapshot after restoring the initial snapshot. 393 let mut snapshot_restored = device.snapshot().unwrap(); 394 assert_eq!(snapshot_init, snapshot_restored); 395 396 // Restore to the first modification and verify the values. 397 device.restore(snapshot_modified.clone())?; 398 assert_eq!(device.read_config_register(1), new_reg_value); 399 snapshot_restored = device.snapshot().unwrap(); 400 assert_eq!(snapshot_modified, snapshot_restored); 401 402 /* 403 Restore the initial snapshot and verify that addresses are not encoded. 404 The addresses are only configurable during VM creation so they never 405 change afterwards and are not part of the snapshot. Force a change 406 to requested_address to confirm that. 407 */ 408 device.restore(snapshot_init.clone())?; 409 device.requested_address = PciAddress { 410 bus: 0x0d, 411 dev: 0x0e, 412 func: 0x4, 413 }; 414 snapshot_modified = device.snapshot().unwrap(); 415 assert_eq!(snapshot_init, snapshot_modified); 416 417 Ok(()) 418 } 419 } 420