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::PciDeviceError; 33 use crate::Suspendable; 34 35 #[derive(Debug)] 36 pub struct PciClassParameters { 37 pub class: PciClassCode, 38 pub subclass: u8, 39 pub programming_interface: u8, 40 } 41 42 impl Default for PciClassParameters { default() -> Self43 fn default() -> Self { 44 PciClassParameters { 45 class: PciClassCode::Other, 46 subclass: 0, 47 programming_interface: 0, 48 } 49 } 50 } 51 52 // Deserialize the combined class, subclass, and programming interface as a single numeric value. 53 // This matches the numeric format used in `/sys/bus/pci/devices/*/class`. 54 impl<'de> Deserialize<'de> for PciClassParameters { deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error> where D: Deserializer<'de>,55 fn deserialize<D>(deserializer: D) -> std::result::Result<PciClassParameters, D::Error> 56 where 57 D: Deserializer<'de>, 58 { 59 let class_numeric = u32::deserialize(deserializer)?; 60 61 let class_code = (class_numeric >> 16) as u8; 62 let class = PciClassCode::try_from(class_code as u8).map_err(|_| { 63 serde::de::Error::custom(format!("Unknown class code {:#x}", class_code)) 64 })?; 65 66 let subclass = (class_numeric >> 8) as u8; 67 68 let programming_interface = class_numeric as u8; 69 70 Ok(PciClassParameters { 71 class, 72 subclass, 73 programming_interface, 74 }) 75 } 76 } 77 78 impl Serialize for PciClassParameters { serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> where S: Serializer,79 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error> 80 where 81 S: Serializer, 82 { 83 let class_numeric: u32 = ((self.class as u32) << 16) 84 | ((self.subclass as u32) << 8) 85 | self.programming_interface as u32; 86 87 serializer.serialize_u32(class_numeric) 88 } 89 } 90 91 #[derive(Serialize, Deserialize, Debug, serde_keyvalue::FromKeyValues)] 92 #[serde(deny_unknown_fields, rename_all = "kebab-case")] 93 pub struct StubPciParameters { 94 pub address: PciAddress, 95 #[serde(default)] 96 pub vendor: u16, 97 #[serde(default)] 98 pub device: u16, 99 #[serde(default)] 100 pub class: PciClassParameters, 101 #[serde(default, alias = "subsystem_vendor")] 102 pub subsystem_vendor: u16, 103 #[serde(default, alias = "subsystem_device")] 104 pub subsystem_device: u16, 105 #[serde(default)] 106 pub revision: u8, 107 } 108 109 pub struct StubPciDevice { 110 requested_address: PciAddress, 111 assigned_address: Option<PciAddress>, 112 config_regs: PciConfiguration, 113 } 114 115 struct NumericPciSubClass(u8); 116 117 impl PciSubclass for NumericPciSubClass { get_register_value(&self) -> u8118 fn get_register_value(&self) -> u8 { 119 self.0 120 } 121 } 122 123 struct NumericPciProgrammingInterface(u8); 124 125 impl PciProgrammingInterface for NumericPciProgrammingInterface { get_register_value(&self) -> u8126 fn get_register_value(&self) -> u8 { 127 self.0 128 } 129 } 130 131 impl StubPciDevice { new(config: &StubPciParameters) -> StubPciDevice132 pub fn new(config: &StubPciParameters) -> StubPciDevice { 133 let config_regs = PciConfiguration::new( 134 config.vendor, 135 config.device, 136 config.class.class, 137 &NumericPciSubClass(config.class.subclass), 138 Some(&NumericPciProgrammingInterface( 139 config.class.programming_interface, 140 )), 141 PciHeaderType::Device, 142 config.subsystem_vendor, 143 config.subsystem_device, 144 config.revision, 145 ); 146 147 Self { 148 requested_address: config.address, 149 assigned_address: None, 150 config_regs, 151 } 152 } 153 } 154 155 impl PciDevice for StubPciDevice { debug_label(&self) -> String156 fn debug_label(&self) -> String { 157 "Stub".to_owned() 158 } 159 preferred_address(&self) -> Option<PciAddress>160 fn preferred_address(&self) -> Option<PciAddress> { 161 Some(self.requested_address) 162 } 163 allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>164 fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> { 165 if self.assigned_address.is_none() { 166 if resources.reserve_pci( 167 Alloc::PciBar { 168 bus: self.requested_address.bus, 169 dev: self.requested_address.dev, 170 func: self.requested_address.func, 171 bar: 0, 172 }, 173 self.debug_label(), 174 ) { 175 self.assigned_address = Some(self.requested_address); 176 } 177 } 178 self.assigned_address 179 .ok_or(PciDeviceError::PciAllocationFailed) 180 } 181 keep_rds(&self) -> Vec<RawDescriptor>182 fn keep_rds(&self) -> Vec<RawDescriptor> { 183 Vec::new() 184 } 185 get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>186 fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> { 187 self.config_regs.get_bar_configuration(bar_num) 188 } 189 read_config_register(&self, reg_idx: usize) -> u32190 fn read_config_register(&self, reg_idx: usize) -> u32 { 191 self.config_regs.read_reg(reg_idx) 192 } 193 write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])194 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 195 self.config_regs.write_reg(reg_idx, offset, data) 196 } 197 read_bar(&mut self, _addr: u64, _data: &mut [u8])198 fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {} 199 write_bar(&mut self, _addr: u64, _data: &[u8])200 fn write_bar(&mut self, _addr: u64, _data: &[u8]) {} 201 } 202 203 impl Suspendable for StubPciDevice { sleep(&mut self) -> anyhow::Result<()>204 fn sleep(&mut self) -> anyhow::Result<()> { 205 // There are no workers to sleep/wake. 206 Ok(()) 207 } 208 wake(&mut self) -> anyhow::Result<()>209 fn wake(&mut self) -> anyhow::Result<()> { 210 // There are no workers to sleep/wake. 211 Ok(()) 212 } 213 } 214 215 #[cfg(test)] 216 mod test { 217 use resources::AddressRange; 218 use resources::SystemAllocator; 219 use resources::SystemAllocatorConfig; 220 use serde_keyvalue::from_key_values; 221 use serde_keyvalue::ErrorKind; 222 use serde_keyvalue::ParseError; 223 224 use super::*; 225 226 const CONFIG: StubPciParameters = StubPciParameters { 227 address: PciAddress { 228 bus: 0x0a, 229 dev: 0x0b, 230 func: 0x1, 231 }, 232 vendor: 2, 233 device: 3, 234 class: PciClassParameters { 235 class: PciClassCode::MultimediaController, 236 subclass: 5, 237 programming_interface: 6, 238 }, 239 subsystem_vendor: 7, 240 subsystem_device: 8, 241 revision: 9, 242 }; 243 from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError>244 fn from_stub_arg(options: &str) -> std::result::Result<StubPciParameters, ParseError> { 245 from_key_values(options) 246 } 247 248 #[test] configuration()249 fn configuration() { 250 let device = StubPciDevice::new(&CONFIG); 251 252 assert_eq!(device.read_config_register(0), 0x0003_0002); 253 assert_eq!(device.read_config_register(2), 0x04_05_06_09); 254 assert_eq!(device.read_config_register(11), 0x0008_0007); 255 } 256 257 #[test] address_allocation()258 fn address_allocation() { 259 let mut allocator = SystemAllocator::new( 260 SystemAllocatorConfig { 261 io: Some(AddressRange { 262 start: 0x1000, 263 end: 0x2fff, 264 }), 265 low_mmio: AddressRange { 266 start: 0x2000_0000, 267 end: 0x2fff_ffff, 268 }, 269 high_mmio: AddressRange { 270 start: 0x1_0000_0000, 271 end: 0x1_0fff_ffff, 272 }, 273 platform_mmio: None, 274 first_irq: 5, 275 }, 276 None, 277 &[], 278 ) 279 .unwrap(); 280 let mut device = StubPciDevice::new(&CONFIG); 281 282 assert!(device.allocate_address(&mut allocator).is_ok()); 283 assert!(allocator.release_pci(0xa, 0xb, 1)); 284 } 285 286 #[test] params_missing_address()287 fn params_missing_address() { 288 // PCI address argument is mandatory. 289 let err = from_stub_arg("").unwrap_err(); 290 assert_eq!( 291 err, 292 ParseError { 293 kind: ErrorKind::SerdeError("missing field `address`".into()), 294 pos: 0, 295 } 296 ); 297 } 298 299 #[test] params_address_implicit()300 fn params_address_implicit() { 301 // Address is the default argument. 302 let params = from_stub_arg("0000:00:01.2").unwrap(); 303 assert_eq!( 304 params.address, 305 PciAddress { 306 bus: 0, 307 dev: 1, 308 func: 2 309 } 310 ); 311 } 312 313 #[test] params_address_explicit()314 fn params_address_explicit() { 315 // Explicitly-specified address. 316 let params = from_stub_arg("address=0000:00:01.2").unwrap(); 317 assert_eq!( 318 params.address, 319 PciAddress { 320 bus: 0, 321 dev: 1, 322 func: 2 323 } 324 ); 325 } 326 327 #[test] params_class()328 fn params_class() { 329 // Class, subclass, and programming interface are encoded as a single number. 330 let params = from_stub_arg("address=0000:00:01.2,class=0x012345").unwrap(); 331 assert_eq!(params.class.class, PciClassCode::MassStorage); 332 assert_eq!(params.class.subclass, 0x23); 333 assert_eq!(params.class.programming_interface, 0x45); 334 } 335 336 #[test] params_subsystem_underscores()337 fn params_subsystem_underscores() { 338 // Accept aliases with underscores rather than hyphens for compatibility. 339 let params = 340 from_stub_arg("address=0000:00:01.2,subsystem_vendor=0x8675,subsystem_device=0x309") 341 .unwrap(); 342 assert_eq!(params.subsystem_vendor, 0x8675); 343 assert_eq!(params.subsystem_device, 0x0309); 344 } 345 346 #[test] params_full()347 fn params_full() { 348 let params = from_stub_arg( 349 "address=0000:00:01.2,vendor=0x1234,device=0x5678,subsystem-vendor=0x8675,subsystem-device=0x309,class=0x012345,revision=52", 350 ).unwrap(); 351 assert_eq!( 352 params.address, 353 PciAddress { 354 bus: 0, 355 dev: 1, 356 func: 2 357 } 358 ); 359 assert_eq!(params.vendor, 0x1234); 360 assert_eq!(params.device, 0x5678); 361 assert_eq!(params.subsystem_vendor, 0x8675); 362 assert_eq!(params.subsystem_device, 0x0309); 363 assert_eq!(params.class.class, PciClassCode::MassStorage); 364 assert_eq!(params.class.subclass, 0x23); 365 assert_eq!(params.class.programming_interface, 0x45); 366 assert_eq!(params.revision, 52); 367 } 368 } 369