1 // Copyright 2018 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 use std::collections::BTreeMap; 6 use std::convert::TryFrom; 7 use std::convert::TryInto; 8 use std::sync::Arc; 9 10 use anyhow::bail; 11 use anyhow::Context; 12 use base::custom_serde::deserialize_seq_to_arr; 13 use base::custom_serde::serialize_arr; 14 use base::error; 15 use base::warn; 16 use base::MemoryMapping; 17 use base::MemoryMappingBuilder; 18 use base::SharedMemory; 19 use downcast_rs::impl_downcast; 20 use downcast_rs::Downcast; 21 use remain::sorted; 22 use serde::Deserialize; 23 use serde::Serialize; 24 use snapshot::AnySnapshot; 25 use sync::Mutex; 26 use thiserror::Error; 27 28 use crate::pci::PciInterruptPin; 29 30 // The number of 32bit registers in the config space, 256 bytes. 31 const NUM_CONFIGURATION_REGISTERS: usize = 64; 32 33 pub const PCI_ID_REG: usize = 0; 34 pub const COMMAND_REG: usize = 1; 35 pub const COMMAND_REG_IO_SPACE_MASK: u32 = 0x0000_0001; 36 pub const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002; 37 const STATUS_REG: usize = 1; 38 pub const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000; 39 #[allow(dead_code)] 40 #[cfg(any(target_os = "android", target_os = "linux"))] 41 pub const CLASS_REG: usize = 2; 42 pub const HEADER_TYPE_REG: usize = 3; 43 pub const HEADER_TYPE_REG_OFFSET: usize = 2; 44 pub const HEADER_TYPE_MULTIFUNCTION_MASK: u8 = 0x80; 45 pub const BAR0_REG: usize = 4; 46 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc; 47 const BAR_IO_MIN_SIZE: u64 = 4; 48 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0; 49 const BAR_MEM_MIN_SIZE: u64 = 16; 50 const BAR_ROM_MIN_SIZE: u64 = 2048; 51 pub const NUM_BAR_REGS: usize = 7; // 6 normal BARs + expansion ROM BAR. 52 pub const ROM_BAR_IDX: PciBarIndex = 6; 53 pub const ROM_BAR_REG: usize = 12; 54 pub const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34; 55 #[cfg(any(target_os = "android", target_os = "linux"))] 56 pub const PCI_CAP_NEXT_POINTER: usize = 0x1; 57 const FIRST_CAPABILITY_OFFSET: usize = 0x40; 58 pub const CAPABILITY_MAX_OFFSET: usize = 255; 59 60 const INTERRUPT_LINE_PIN_REG: usize = 15; 61 62 /// Represents the types of PCI headers allowed in the configuration registers. 63 #[allow(dead_code)] 64 #[derive(Copy, Clone)] 65 pub enum PciHeaderType { 66 Device, 67 Bridge, 68 } 69 70 /// Classes of PCI nodes. 71 #[allow(dead_code)] 72 #[derive(Copy, Clone, Debug, enumn::N, Serialize, Deserialize, PartialEq, Eq)] 73 pub enum PciClassCode { 74 TooOld, 75 MassStorage, 76 NetworkController, 77 DisplayController, 78 MultimediaController, 79 MemoryController, 80 BridgeDevice, 81 SimpleCommunicationController, 82 BaseSystemPeripheral, 83 InputDevice, 84 DockingStation, 85 Processor, 86 SerialBusController, 87 WirelessController, 88 IntelligentIoController, 89 SatelliteCommunicationController, 90 EncryptionController, 91 DataAcquisitionSignalProcessing, 92 ProcessingAccelerator, 93 NonEssentialInstrumentation, 94 Other = 0xff, 95 } 96 97 impl PciClassCode { get_register_value(&self) -> u898 pub fn get_register_value(&self) -> u8 { 99 *self as u8 100 } 101 } 102 103 #[sorted] 104 #[derive(Error, Debug)] 105 pub enum PciClassCodeParseError { 106 #[error("Unknown class code")] 107 Unknown, 108 } 109 110 impl TryFrom<u8> for PciClassCode { 111 type Error = PciClassCodeParseError; try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError>112 fn try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError> { 113 match PciClassCode::n(v) { 114 Some(class) => Ok(class), 115 None => Err(PciClassCodeParseError::Unknown), 116 } 117 } 118 } 119 120 /// A PCI sublcass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait 121 /// is implemented by each subclass. It allows use of a trait object to generate configurations. 122 pub trait PciSubclass { 123 /// Convert this subclass to the value used in the PCI specification. get_register_value(&self) -> u8124 fn get_register_value(&self) -> u8; 125 } 126 127 /// Subclasses of the MassStorage class. 128 #[allow(dead_code)] 129 #[derive(Copy, Clone)] 130 pub enum PciMassStorageSubclass { 131 Scsi = 0x00, 132 NonVolatileMemory = 0x08, 133 Other = 0x80, 134 } 135 136 impl PciSubclass for PciMassStorageSubclass { get_register_value(&self) -> u8137 fn get_register_value(&self) -> u8 { 138 *self as u8 139 } 140 } 141 142 /// Subclasses of the NetworkController class. 143 #[allow(dead_code)] 144 #[derive(Copy, Clone)] 145 pub enum PciNetworkControllerSubclass { 146 Other = 0x80, 147 } 148 149 impl PciSubclass for PciNetworkControllerSubclass { get_register_value(&self) -> u8150 fn get_register_value(&self) -> u8 { 151 *self as u8 152 } 153 } 154 155 /// Subclasses of the DisplayController class. 156 #[allow(dead_code)] 157 #[derive(Copy, Clone)] 158 pub enum PciDisplaySubclass { 159 VgaCompatibleController = 0x00, 160 XgaCompatibleController = 0x01, 161 ThreeDController = 0x02, 162 Other = 0x80, 163 } 164 165 impl PciSubclass for PciDisplaySubclass { get_register_value(&self) -> u8166 fn get_register_value(&self) -> u8 { 167 *self as u8 168 } 169 } 170 171 /// Subclasses of the MultimediaController class. 172 #[allow(dead_code)] 173 #[derive(Copy, Clone)] 174 pub enum PciMultimediaSubclass { 175 VideoController = 0x00, 176 AudioController = 0x01, 177 TelephonyDevice = 0x02, 178 AudioDevice = 0x03, 179 Other = 0x80, 180 } 181 182 impl PciSubclass for PciMultimediaSubclass { get_register_value(&self) -> u8183 fn get_register_value(&self) -> u8 { 184 *self as u8 185 } 186 } 187 188 /// Subclasses of the BridgeDevice 189 #[allow(dead_code)] 190 #[derive(Copy, Clone)] 191 pub enum PciBridgeSubclass { 192 HostBridge = 0x00, 193 IsaBridge = 0x01, 194 EisaBridge = 0x02, 195 McaBridge = 0x03, 196 PciToPciBridge = 0x04, 197 PcmciaBridge = 0x05, 198 NuBusBridge = 0x06, 199 CardBusBridge = 0x07, 200 RaceWayBridge = 0x08, 201 PciToPciSemiTransparentBridge = 0x09, 202 InfiniBrandToPciHostBridge = 0x0a, 203 OtherBridgeDevice = 0x80, 204 } 205 206 impl PciSubclass for PciBridgeSubclass { get_register_value(&self) -> u8207 fn get_register_value(&self) -> u8 { 208 *self as u8 209 } 210 } 211 212 /// Subclasses of the SimpleCommunicationController class. 213 #[allow(dead_code)] 214 #[derive(Copy, Clone)] 215 pub enum PciSimpleCommunicationControllerSubclass { 216 Other = 0x80, 217 } 218 219 impl PciSubclass for PciSimpleCommunicationControllerSubclass { get_register_value(&self) -> u8220 fn get_register_value(&self) -> u8 { 221 *self as u8 222 } 223 } 224 225 /// Subclasses of the BaseSystemPeripheral class. 226 #[allow(dead_code)] 227 #[derive(Copy, Clone)] 228 pub enum PciBaseSystemPeripheralSubclass { 229 Iommu = 0x06, 230 Other = 0x80, 231 } 232 233 impl PciSubclass for PciBaseSystemPeripheralSubclass { get_register_value(&self) -> u8234 fn get_register_value(&self) -> u8 { 235 *self as u8 236 } 237 } 238 239 /// Subclasses of the InputDevice class. 240 #[allow(dead_code)] 241 #[derive(Copy, Clone)] 242 pub enum PciInputDeviceSubclass { 243 Other = 0x80, 244 } 245 246 impl PciSubclass for PciInputDeviceSubclass { get_register_value(&self) -> u8247 fn get_register_value(&self) -> u8 { 248 *self as u8 249 } 250 } 251 252 /// Subclass of the SerialBus 253 #[allow(dead_code)] 254 #[derive(Copy, Clone)] 255 pub enum PciSerialBusSubClass { 256 Firewire = 0x00, 257 AccessBus = 0x01, 258 Ssa = 0x02, 259 Usb = 0x03, 260 } 261 262 impl PciSubclass for PciSerialBusSubClass { get_register_value(&self) -> u8263 fn get_register_value(&self) -> u8 { 264 *self as u8 265 } 266 } 267 268 /// Subclasses of the WirelessController class. 269 #[allow(dead_code)] 270 #[derive(Copy, Clone)] 271 pub enum PciWirelessControllerSubclass { 272 Other = 0x80, 273 } 274 275 impl PciSubclass for PciWirelessControllerSubclass { get_register_value(&self) -> u8276 fn get_register_value(&self) -> u8 { 277 *self as u8 278 } 279 } 280 281 /// Subclasses for PciClassCode Other. 282 #[allow(dead_code)] 283 #[derive(Copy, Clone)] 284 #[repr(u8)] 285 pub enum PciOtherSubclass { 286 Other = 0xff, 287 } 288 289 impl PciSubclass for PciOtherSubclass { get_register_value(&self) -> u8290 fn get_register_value(&self) -> u8 { 291 *self as u8 292 } 293 } 294 295 /// A PCI class programming interface. Each combination of `PciClassCode` and 296 /// `PciSubclass` can specify a set of register-level programming interfaces. 297 /// This trait is implemented by each programming interface. 298 /// It allows use of a trait object to generate configurations. 299 pub trait PciProgrammingInterface { 300 /// Convert this programming interface to the value used in the PCI specification. get_register_value(&self) -> u8301 fn get_register_value(&self) -> u8; 302 } 303 304 /// Types of PCI capabilities. 305 pub enum PciCapabilityID { 306 ListID = 0, 307 PowerManagement = 0x01, 308 AcceleratedGraphicsPort = 0x02, 309 VitalProductData = 0x03, 310 SlotIdentification = 0x04, 311 MessageSignalledInterrupts = 0x05, 312 CompactPciHotSwap = 0x06, 313 Pcix = 0x07, 314 HyperTransport = 0x08, 315 VendorSpecific = 0x09, 316 Debugport = 0x0A, 317 CompactPciCentralResourceControl = 0x0B, 318 PciStandardHotPlugController = 0x0C, 319 BridgeSubsystemVendorDeviceID = 0x0D, 320 AgpTargetPciPciBridge = 0x0E, 321 SecureDevice = 0x0F, 322 PciExpress = 0x10, 323 Msix = 0x11, 324 SataDataIndexConf = 0x12, 325 PciAdvancedFeatures = 0x13, 326 PciEnhancedAllocation = 0x14, 327 } 328 329 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space. 330 pub trait PciCapability { bytes(&self) -> &[u8]331 fn bytes(&self) -> &[u8]; id(&self) -> PciCapabilityID332 fn id(&self) -> PciCapabilityID; writable_bits(&self) -> Vec<u32>333 fn writable_bits(&self) -> Vec<u32>; 334 } 335 336 pub trait PciCapConfigWriteResult: Downcast {} 337 impl_downcast!(PciCapConfigWriteResult); 338 339 /// A trait for implementing complex PCI capabilities. 340 pub trait PciCapConfig: Send { 341 /// Reads a 32bit register from the capability. Only the bits set in the 342 /// read mask will be used, while the rest of the bits will be taken from 343 /// the `PciConfiguration`'s register data. 344 /// `reg_idx` - index into the capability read_reg(&self, reg_idx: usize) -> u32345 fn read_reg(&self, reg_idx: usize) -> u32; 346 347 /// Returns the read mask used by `read_reg`. read_mask(&self) -> &'static [u32]348 fn read_mask(&self) -> &'static [u32]; 349 350 /// Writes data to the capability. 351 /// `reg_idx` - index into PciConfiguration.registers. 352 /// `offset` - PciConfiguration.registers is in unit of DWord, offset define byte 353 /// offset in the DWord. 354 /// `data` - The data to write. write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>355 fn write_reg( 356 &mut self, 357 reg_idx: usize, 358 offset: u64, 359 data: &[u8], 360 ) -> Option<Box<dyn PciCapConfigWriteResult>>; 361 362 /// Used to pass the mmio region for the capability to the implementation. 363 /// If any external events update the capability's registers, then 364 /// `PciCapMapping.set_reg` must be called to make the changes visible 365 /// to the guest. set_cap_mapping(&mut self, _mapping: PciCapMapping)366 fn set_cap_mapping(&mut self, _mapping: PciCapMapping) {} 367 num_regs(&self) -> usize368 fn num_regs(&self) -> usize { 369 self.read_mask().len() 370 } 371 } 372 373 /// Contains the configuration space of a PCI node. 374 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space). 375 /// The configuration space is accessed with DWORD reads and writes from the guest. 376 pub struct PciConfiguration { 377 registers: [u32; NUM_CONFIGURATION_REGISTERS], 378 writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register. 379 bar_used: [bool; NUM_BAR_REGS], 380 bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS], 381 // Contains the byte offset and size of the last capability. 382 last_capability: Option<(usize, usize)>, 383 capability_configs: BTreeMap<usize, Box<dyn PciCapConfig>>, 384 mmio_mapping: Option<(Arc<Mutex<MemoryMapping>>, usize)>, 385 } 386 387 #[derive(Serialize, Deserialize)] 388 pub struct PciConfigurationSerialized { 389 #[serde( 390 serialize_with = "serialize_arr", 391 deserialize_with = "deserialize_seq_to_arr" 392 )] 393 registers: [u32; NUM_CONFIGURATION_REGISTERS], 394 #[serde( 395 serialize_with = "serialize_arr", 396 deserialize_with = "deserialize_seq_to_arr" 397 )] 398 writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], 399 bar_used: [bool; NUM_BAR_REGS], 400 bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS], 401 last_capability: Option<(usize, usize)>, 402 } 403 404 /// See pci_regs.h in kernel 405 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 406 pub enum PciBarRegionType { 407 Memory32BitRegion = 0, 408 IoRegion = 0x01, 409 Memory64BitRegion = 0x04, 410 } 411 412 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 413 pub enum PciBarPrefetchable { 414 NotPrefetchable = 0, 415 Prefetchable = 0x08, 416 } 417 418 pub type PciBarIndex = usize; 419 420 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 421 pub struct PciBarConfiguration { 422 addr: u64, 423 size: u64, 424 bar_idx: PciBarIndex, 425 region_type: PciBarRegionType, 426 prefetchable: PciBarPrefetchable, 427 } 428 429 pub struct PciBarIter<'a> { 430 config: &'a PciConfiguration, 431 bar_num: PciBarIndex, 432 } 433 434 impl Iterator for PciBarIter<'_> { 435 type Item = PciBarConfiguration; 436 next(&mut self) -> Option<Self::Item>437 fn next(&mut self) -> Option<Self::Item> { 438 while self.bar_num < NUM_BAR_REGS { 439 let bar_config = self.config.get_bar_configuration(self.bar_num); 440 self.bar_num += 1; 441 if let Some(bar_config) = bar_config { 442 return Some(bar_config); 443 } 444 } 445 446 None 447 } 448 } 449 450 #[sorted] 451 #[derive(Error, Debug, PartialEq, Eq)] 452 pub enum Error { 453 #[error("address {0} size {1} too big")] 454 BarAddressInvalid(u64, u64), 455 #[error("address {0} is not aligned to size {1}")] 456 BarAlignmentInvalid(u64, u64), 457 #[error("bar {0} already used")] 458 BarInUse(PciBarIndex), 459 #[error("64bit bar {0} already used (requires two regs)")] 460 BarInUse64(PciBarIndex), 461 #[error("bar {0} invalid, max {max}", max = NUM_BAR_REGS - 1)] 462 BarInvalid(PciBarIndex), 463 #[error("64bitbar {0} invalid, requires two regs, max {max}", max = ROM_BAR_IDX - 1)] 464 BarInvalid64(PciBarIndex), 465 #[error("expansion rom bar must be a memory region")] 466 BarInvalidRomType, 467 #[error("bar address {0} not a power of two")] 468 BarSizeInvalid(u64), 469 #[error("empty capabilities are invalid")] 470 CapabilityEmpty, 471 #[error("Invalid capability length {0}")] 472 CapabilityLengthInvalid(usize), 473 #[error("capability of size {0} doesn't fit")] 474 CapabilitySpaceFull(usize), 475 } 476 477 pub type Result<T> = std::result::Result<T, Error>; 478 479 impl PciConfiguration { new( vendor_id: u16, device_id: u16, class_code: PciClassCode, subclass: &dyn PciSubclass, programming_interface: Option<&dyn PciProgrammingInterface>, header_type: PciHeaderType, subsystem_vendor_id: u16, subsystem_id: u16, revision_id: u8, ) -> Self480 pub fn new( 481 vendor_id: u16, 482 device_id: u16, 483 class_code: PciClassCode, 484 subclass: &dyn PciSubclass, 485 programming_interface: Option<&dyn PciProgrammingInterface>, 486 header_type: PciHeaderType, 487 subsystem_vendor_id: u16, 488 subsystem_id: u16, 489 revision_id: u8, 490 ) -> Self { 491 let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS]; 492 let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS]; 493 registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id); 494 // TODO(dverkamp): Status should be write-1-to-clear 495 writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w) 496 let pi = if let Some(pi) = programming_interface { 497 pi.get_register_value() 498 } else { 499 0 500 }; 501 registers[2] = u32::from(class_code.get_register_value()) << 24 502 | u32::from(subclass.get_register_value()) << 16 503 | u32::from(pi) << 8 504 | u32::from(revision_id); 505 writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w) 506 match header_type { 507 PciHeaderType::Device => { 508 registers[3] = 0x0000_0000; // Header type 0 (device) 509 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w) 510 registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id); 511 } 512 PciHeaderType::Bridge => { 513 registers[3] = 0x0001_0000; // Header type 1 (bridge) 514 writable_bits[6] = 0x00ff_ffff; // Primary/secondary/subordinate bus number, 515 // secondary latency timer 516 registers[7] = 0x0000_00f0; // IO base > IO Limit, no IO address on secondary side at initialize 517 writable_bits[7] = 0xf900_0000; // IO base and limit, secondary status, 518 registers[8] = 0x0000_fff0; // mem base > mem Limit, no MMIO address on secondary side at initialize 519 writable_bits[8] = 0xfff0_fff0; // Memory base and limit 520 registers[9] = 0x0001_fff1; // pmem base > pmem Limit, no prefetch MMIO address on secondary side at initialize 521 writable_bits[9] = 0xfff0_fff0; // Prefetchable base and limit 522 writable_bits[10] = 0xffff_ffff; // Prefetchable base upper 32 bits 523 writable_bits[11] = 0xffff_ffff; // Prefetchable limit upper 32 bits 524 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w) 525 } 526 }; 527 528 PciConfiguration { 529 registers, 530 writable_bits, 531 bar_used: [false; NUM_BAR_REGS], 532 bar_configs: [None; NUM_BAR_REGS], 533 last_capability: None, 534 capability_configs: BTreeMap::new(), 535 mmio_mapping: None, 536 } 537 } 538 539 /// Reads a 32bit register from `reg_idx` in the register map. read_reg(&self, reg_idx: usize) -> u32540 pub fn read_reg(&self, reg_idx: usize) -> u32 { 541 let mut data = *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff)); 542 if let Some((idx, cfg)) = self.capability_configs.range(..=reg_idx).last() { 543 if reg_idx < idx + cfg.num_regs() { 544 let cap_idx = reg_idx - idx; 545 let mask = cfg.read_mask()[cap_idx]; 546 data = (data & !mask) | (cfg.read_reg(cap_idx) & mask); 547 } 548 } 549 data 550 } 551 552 /// Writes data to PciConfiguration.registers. 553 /// `reg_idx` - index into PciConfiguration.registers. 554 /// `offset` - PciConfiguration.registers is in unit of DWord, offset define byte 555 /// offset in the DWord. 556 /// `data` - The data to write. write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>557 pub fn write_reg( 558 &mut self, 559 reg_idx: usize, 560 offset: u64, 561 data: &[u8], 562 ) -> Option<Box<dyn PciCapConfigWriteResult>> { 563 let reg_offset = reg_idx * 4 + offset as usize; 564 match data.len() { 565 1 => self.write_byte(reg_offset, data[0]), 566 2 => self.write_word(reg_offset, u16::from_le_bytes(data.try_into().unwrap())), 567 4 => self.write_dword(reg_offset, u32::from_le_bytes(data.try_into().unwrap())), 568 _ => (), 569 } 570 if let Some((idx, cfg)) = self.capability_configs.range_mut(..=reg_idx).last() { 571 if reg_idx < idx + cfg.num_regs() { 572 let cap_idx = reg_idx - idx; 573 let ret = cfg.write_reg(cap_idx, offset, data); 574 let new_val = cfg.read_reg(cap_idx); 575 let mask = cfg.read_mask()[cap_idx]; 576 self.set_reg(reg_idx, new_val, mask); 577 return ret; 578 } 579 } 580 None 581 } 582 583 /// Writes a 32bit dword to `offset`. `offset` must be 32bit aligned. write_dword(&mut self, offset: usize, value: u32)584 fn write_dword(&mut self, offset: usize, value: u32) { 585 if offset % 4 != 0 { 586 warn!("bad PCI config dword write offset {}", offset); 587 return; 588 } 589 let reg_idx = offset / 4; 590 if reg_idx < NUM_CONFIGURATION_REGISTERS { 591 let old_value = self.registers[reg_idx]; 592 let new_value = 593 (old_value & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]); 594 self.do_write(reg_idx, new_value) 595 } else { 596 warn!("bad PCI dword write {}", offset); 597 } 598 } 599 600 /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned. write_word(&mut self, offset: usize, value: u16)601 fn write_word(&mut self, offset: usize, value: u16) { 602 let shift = match offset % 4 { 603 0 => 0, 604 2 => 16, 605 _ => { 606 warn!("bad PCI config word write offset {}", offset); 607 return; 608 } 609 }; 610 let reg_idx = offset / 4; 611 612 if reg_idx < NUM_CONFIGURATION_REGISTERS { 613 let old_value = self.registers[reg_idx]; 614 let writable_mask = self.writable_bits[reg_idx]; 615 let mask = (0xffffu32 << shift) & writable_mask; 616 let shifted_value = (u32::from(value) << shift) & writable_mask; 617 let new_value = old_value & !mask | shifted_value; 618 self.do_write(reg_idx, new_value) 619 } else { 620 warn!("bad PCI config word write offset {}", offset); 621 } 622 } 623 624 /// Writes a byte to `offset`. write_byte(&mut self, offset: usize, value: u8)625 fn write_byte(&mut self, offset: usize, value: u8) { 626 self.write_byte_internal(offset, value, true); 627 } 628 629 /// Writes a byte to `offset`, optionally enforcing read-only bits. write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool)630 fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) { 631 let shift = (offset % 4) * 8; 632 let reg_idx = offset / 4; 633 634 if reg_idx < NUM_CONFIGURATION_REGISTERS { 635 let writable_mask = if apply_writable_mask { 636 self.writable_bits[reg_idx] 637 } else { 638 0xffff_ffff 639 }; 640 let old_value = self.registers[reg_idx]; 641 let mask = (0xffu32 << shift) & writable_mask; 642 let shifted_value = (u32::from(value) << shift) & writable_mask; 643 let new_value = old_value & !mask | shifted_value; 644 self.do_write(reg_idx, new_value) 645 } else { 646 warn!("bad PCI config byte write offset {}", offset); 647 } 648 } 649 650 /// Sets the value of a PciConfiguration register. This should be used when 651 /// device-internal events require changing the configuration space - as such, 652 /// the writable bits masks do not apply. 653 /// `reg_idx` - index into PciConfiguration.registers. 654 /// `data` - The data to write. 655 /// `mask` - The mask of which bits to modify. set_reg(&mut self, reg_idx: usize, data: u32, mask: u32)656 pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) { 657 if reg_idx >= NUM_CONFIGURATION_REGISTERS { 658 return; 659 } 660 let new_val = (self.registers[reg_idx] & !mask) | (data & mask); 661 self.do_write(reg_idx, new_val); 662 } 663 664 /// Adds a region specified by `config`. Configures the specified BAR(s) to 665 /// report this region and size to the guest kernel. Enforces a few constraints 666 /// (i.e, region size must be power of two, register not already used). Returns 'None' on 667 /// failure all, `Some(BarIndex)` on success. add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex>668 pub fn add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex> { 669 if config.bar_idx >= NUM_BAR_REGS { 670 return Err(Error::BarInvalid(config.bar_idx)); 671 } 672 673 if self.bar_used[config.bar_idx] { 674 return Err(Error::BarInUse(config.bar_idx)); 675 } 676 677 if config.size.count_ones() != 1 { 678 return Err(Error::BarSizeInvalid(config.size)); 679 } 680 681 if config.is_expansion_rom() && config.region_type != PciBarRegionType::Memory32BitRegion { 682 return Err(Error::BarInvalidRomType); 683 } 684 685 let min_size = if config.is_expansion_rom() { 686 BAR_ROM_MIN_SIZE 687 } else if config.region_type == PciBarRegionType::IoRegion { 688 BAR_IO_MIN_SIZE 689 } else { 690 BAR_MEM_MIN_SIZE 691 }; 692 693 if config.size < min_size { 694 return Err(Error::BarSizeInvalid(config.size)); 695 } 696 697 if config.addr % config.size != 0 { 698 return Err(Error::BarAlignmentInvalid(config.addr, config.size)); 699 } 700 701 let reg_idx = config.reg_index(); 702 let end_addr = config 703 .addr 704 .checked_add(config.size) 705 .ok_or(Error::BarAddressInvalid(config.addr, config.size))?; 706 match config.region_type { 707 PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => { 708 if end_addr > u64::from(u32::MAX) { 709 return Err(Error::BarAddressInvalid(config.addr, config.size)); 710 } 711 } 712 PciBarRegionType::Memory64BitRegion => { 713 // The expansion ROM BAR cannot be used for part of a 64-bit BAR. 714 if config.bar_idx + 1 >= ROM_BAR_IDX { 715 return Err(Error::BarInvalid64(config.bar_idx)); 716 } 717 718 if self.bar_used[config.bar_idx + 1] { 719 return Err(Error::BarInUse64(config.bar_idx)); 720 } 721 722 self.do_write(reg_idx + 1, (config.addr >> 32) as u32); 723 self.writable_bits[reg_idx + 1] = !((config.size - 1) >> 32) as u32; 724 self.bar_used[config.bar_idx + 1] = true; 725 } 726 } 727 728 let (mask, lower_bits) = match config.region_type { 729 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => { 730 self.registers[COMMAND_REG] |= COMMAND_REG_MEMORY_SPACE_MASK; 731 ( 732 BAR_MEM_ADDR_MASK, 733 config.prefetchable as u32 | config.region_type as u32, 734 ) 735 } 736 PciBarRegionType::IoRegion => { 737 self.registers[COMMAND_REG] |= COMMAND_REG_IO_SPACE_MASK; 738 (BAR_IO_ADDR_MASK, config.region_type as u32) 739 } 740 }; 741 742 self.do_write(reg_idx, ((config.addr as u32) & mask) | lower_bits); 743 self.writable_bits[reg_idx] = !(config.size - 1) as u32; 744 if config.is_expansion_rom() { 745 self.writable_bits[reg_idx] |= 1; // Expansion ROM enable bit. 746 } 747 self.bar_used[config.bar_idx] = true; 748 self.bar_configs[config.bar_idx] = Some(config); 749 Ok(config.bar_idx) 750 } 751 752 /// Returns an iterator of the currently configured base address registers. 753 #[allow(dead_code)] // TODO(dverkamp): remove this once used get_bars(&self) -> PciBarIter754 pub fn get_bars(&self) -> PciBarIter { 755 PciBarIter { 756 config: self, 757 bar_num: 0, 758 } 759 } 760 761 /// Returns the configuration of a base address register, if present. get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>762 pub fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> { 763 let config = self.bar_configs.get(bar_num)?; 764 765 if let Some(mut config) = config { 766 let command = self.read_reg(COMMAND_REG); 767 if (config.is_memory() && (command & COMMAND_REG_MEMORY_SPACE_MASK == 0)) 768 || (config.is_io() && (command & COMMAND_REG_IO_SPACE_MASK == 0)) 769 { 770 return None; 771 } 772 773 // The address may have been modified by the guest, so the value in bar_configs 774 // may be outdated. Replace it with the current value. 775 config.addr = self.get_bar_addr(bar_num); 776 Some(config) 777 } else { 778 None 779 } 780 } 781 782 /// Returns the type of the given BAR region. get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType>783 pub fn get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType> { 784 self.bar_configs.get(bar_num)?.map(|c| c.region_type) 785 } 786 787 /// Returns the address of the given BAR region. get_bar_addr(&self, bar_num: PciBarIndex) -> u64788 pub fn get_bar_addr(&self, bar_num: PciBarIndex) -> u64 { 789 let bar_idx = if bar_num == ROM_BAR_IDX { 790 ROM_BAR_REG 791 } else { 792 BAR0_REG + bar_num 793 }; 794 795 let bar_type = match self.get_bar_type(bar_num) { 796 Some(t) => t, 797 None => return 0, 798 }; 799 800 match bar_type { 801 PciBarRegionType::IoRegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK), 802 PciBarRegionType::Memory32BitRegion => { 803 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK) 804 } 805 PciBarRegionType::Memory64BitRegion => { 806 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK) 807 | u64::from(self.registers[bar_idx + 1]) << 32 808 } 809 } 810 } 811 812 /// Configures the IRQ line and pin used by this device. set_irq(&mut self, line: u8, pin: PciInterruptPin)813 pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) { 814 // `pin` is 1-based in the pci config space. 815 let pin_idx = (pin as u32) + 1; 816 let new_val = (self.registers[INTERRUPT_LINE_PIN_REG] & 0xffff_0000) 817 | (pin_idx << 8) 818 | u32::from(line); 819 self.do_write(INTERRUPT_LINE_PIN_REG, new_val) 820 } 821 822 /// Adds the capability `cap_data` to the list of capabilities. 823 /// `cap_data` should include the two-byte PCI capability header (type, next), 824 /// but not populate it. Correct values will be generated automatically based 825 /// on `cap_data.id()`. add_capability( &mut self, cap_data: &dyn PciCapability, cap_config: Option<Box<dyn PciCapConfig>>, ) -> Result<()>826 pub fn add_capability( 827 &mut self, 828 cap_data: &dyn PciCapability, 829 cap_config: Option<Box<dyn PciCapConfig>>, 830 ) -> Result<()> { 831 let total_len = cap_data.bytes().len(); 832 // Check that the length is valid. 833 if cap_data.bytes().is_empty() { 834 return Err(Error::CapabilityEmpty); 835 } 836 let (cap_offset, tail_offset) = match self.last_capability { 837 Some((offset, len)) => (Self::next_dword(offset, len), offset + 1), 838 None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET), 839 }; 840 let end_offset = cap_offset 841 .checked_add(total_len) 842 .ok_or(Error::CapabilitySpaceFull(total_len))?; 843 if end_offset > CAPABILITY_MAX_OFFSET { 844 return Err(Error::CapabilitySpaceFull(total_len)); 845 } 846 self.do_write( 847 STATUS_REG, 848 self.registers[STATUS_REG] | STATUS_REG_CAPABILITIES_USED_MASK, 849 ); 850 self.write_byte_internal(tail_offset, cap_offset as u8, false); 851 self.write_byte_internal(cap_offset, cap_data.id() as u8, false); 852 self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer. 853 for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) { 854 self.write_byte_internal(cap_offset + i, *byte, false); 855 } 856 let reg_idx = cap_offset / 4; 857 for (i, dword) in cap_data.writable_bits().iter().enumerate() { 858 self.writable_bits[reg_idx + i] = *dword; 859 } 860 self.last_capability = Some((cap_offset, total_len)); 861 if let Some(mut cap_config) = cap_config { 862 if let Some((mapping, offset)) = &self.mmio_mapping { 863 cap_config.set_cap_mapping(PciCapMapping { 864 mapping: mapping.clone(), 865 offset: reg_idx * 4 + offset, 866 num_regs: total_len / 4, 867 }); 868 } 869 self.capability_configs.insert(cap_offset / 4, cap_config); 870 } 871 Ok(()) 872 } 873 874 // Find the next aligned offset after the one given. next_dword(offset: usize, len: usize) -> usize875 fn next_dword(offset: usize, len: usize) -> usize { 876 let next = offset + len; 877 (next + 3) & !3 878 } 879 do_write(&mut self, reg_idx: usize, value: u32)880 fn do_write(&mut self, reg_idx: usize, value: u32) { 881 self.registers[reg_idx] = value; 882 if let Some((mmio_mapping, offset)) = self.mmio_mapping.as_ref() { 883 let mmio_mapping = mmio_mapping.lock(); 884 let reg_offset = offset + reg_idx * 4; 885 if reg_idx == HEADER_TYPE_REG { 886 // Skip writing the header type byte (reg_idx=2/offset=3) as 887 // per the requirements of PciDevice.setup_pci_config_mapping. 888 mmio_mapping 889 .write_obj_volatile((value & 0xffff) as u16, reg_offset) 890 .expect("bad register offset"); 891 // Skip HEADER_TYPE_REG_OFFSET (i.e. header+mfd byte) 892 mmio_mapping 893 .write_obj_volatile(((value >> 24) & 0xff) as u8, reg_offset + 3) 894 .expect("bad register offset"); 895 } else { 896 mmio_mapping 897 .write_obj_volatile(value, reg_offset) 898 .expect("bad register offset"); 899 } 900 if let Err(err) = mmio_mapping.flush_region(reg_offset, 4) { 901 error!( 902 "failed to flush write to pci mmio register ({}): {}", 903 reg_idx, err 904 ); 905 } 906 } 907 } 908 snapshot(&mut self) -> anyhow::Result<AnySnapshot>909 pub fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> { 910 AnySnapshot::to_any(PciConfigurationSerialized { 911 registers: self.registers, 912 writable_bits: self.writable_bits, 913 bar_used: self.bar_used, 914 bar_configs: self.bar_configs, 915 last_capability: self.last_capability, 916 }) 917 .context("failed to serialize PciConfiguration") 918 } 919 restore(&mut self, data: AnySnapshot) -> anyhow::Result<()>920 pub fn restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> { 921 let deser: PciConfigurationSerialized = 922 AnySnapshot::from_any(data).context("failed to deserialize PciConfiguration")?; 923 self.registers = deser.registers; 924 self.writable_bits = deser.writable_bits; 925 self.bar_used = deser.bar_used; 926 self.bar_configs = deser.bar_configs; 927 self.last_capability = deser.last_capability; 928 // Restore everything via do_write to avoid writing to the header type register 929 // and clobbering the multi-function device bit, as that bit is managed by the 930 // PciRoot. Since restore doesn't change the types or layout of PCI devices, the 931 // header type bits in the register are already correct anyway. 932 for i in 0..NUM_CONFIGURATION_REGISTERS { 933 self.do_write(i, self.registers[i]); 934 } 935 Ok(()) 936 } 937 setup_mapping( &mut self, shmem: &SharedMemory, base: usize, len: usize, ) -> anyhow::Result<()>938 pub fn setup_mapping( 939 &mut self, 940 shmem: &SharedMemory, 941 base: usize, 942 len: usize, 943 ) -> anyhow::Result<()> { 944 if self.mmio_mapping.is_some() { 945 bail!("PCIe config mmio mapping already initialized"); 946 } 947 let mapping = MemoryMappingBuilder::new(base::pagesize()) 948 .from_shared_memory(shmem) 949 .build() 950 .context("Failed to create mapping")?; 951 for i in 0..(len / 4) { 952 let val = self.registers.get(i).unwrap_or(&0xffff_ffff); 953 mapping 954 .write_obj_volatile(*val, base + i * 4) 955 .expect("memcpy failed"); 956 } 957 let mapping = Arc::new(Mutex::new(mapping)); 958 for (idx, cap) in self.capability_configs.iter_mut() { 959 let mut cap_mapping = PciCapMapping { 960 mapping: mapping.clone(), 961 offset: idx * 4 + base, 962 num_regs: cap.num_regs(), 963 }; 964 for i in 0..cap.num_regs() { 965 let val = cap.read_reg(i); 966 let mask = cap.read_mask()[i]; 967 cap_mapping.set_reg(i, val, mask); 968 } 969 cap.set_cap_mapping(cap_mapping); 970 } 971 self.mmio_mapping = Some((mapping, base)); 972 Ok(()) 973 } 974 } 975 976 impl PciBarConfiguration { new( bar_idx: PciBarIndex, size: u64, region_type: PciBarRegionType, prefetchable: PciBarPrefetchable, ) -> Self977 pub fn new( 978 bar_idx: PciBarIndex, 979 size: u64, 980 region_type: PciBarRegionType, 981 prefetchable: PciBarPrefetchable, 982 ) -> Self { 983 PciBarConfiguration { 984 bar_idx, 985 addr: 0, 986 size, 987 region_type, 988 prefetchable, 989 } 990 } 991 bar_index(&self) -> PciBarIndex992 pub fn bar_index(&self) -> PciBarIndex { 993 self.bar_idx 994 } 995 reg_index(&self) -> usize996 pub fn reg_index(&self) -> usize { 997 if self.bar_idx == ROM_BAR_IDX { 998 ROM_BAR_REG 999 } else { 1000 BAR0_REG + self.bar_idx 1001 } 1002 } 1003 address(&self) -> u641004 pub fn address(&self) -> u64 { 1005 self.addr 1006 } 1007 address_range(&self) -> std::ops::Range<u64>1008 pub fn address_range(&self) -> std::ops::Range<u64> { 1009 self.addr..self.addr + self.size 1010 } 1011 set_address(mut self, addr: u64) -> Self1012 pub fn set_address(mut self, addr: u64) -> Self { 1013 self.addr = addr; 1014 self 1015 } 1016 size(&self) -> u641017 pub fn size(&self) -> u64 { 1018 self.size 1019 } 1020 is_expansion_rom(&self) -> bool1021 pub fn is_expansion_rom(&self) -> bool { 1022 self.bar_idx == ROM_BAR_IDX 1023 } 1024 is_memory(&self) -> bool1025 pub fn is_memory(&self) -> bool { 1026 matches!( 1027 self.region_type, 1028 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion 1029 ) 1030 } 1031 is_64bit_memory(&self) -> bool1032 pub fn is_64bit_memory(&self) -> bool { 1033 self.region_type == PciBarRegionType::Memory64BitRegion 1034 } 1035 is_io(&self) -> bool1036 pub fn is_io(&self) -> bool { 1037 self.region_type == PciBarRegionType::IoRegion 1038 } 1039 is_prefetchable(&self) -> bool1040 pub fn is_prefetchable(&self) -> bool { 1041 self.is_memory() && self.prefetchable == PciBarPrefetchable::Prefetchable 1042 } 1043 } 1044 1045 impl<T: PciCapConfig + ?Sized> PciCapConfig for Arc<Mutex<T>> { read_mask(&self) -> &'static [u32]1046 fn read_mask(&self) -> &'static [u32] { 1047 self.lock().read_mask() 1048 } read_reg(&self, reg_idx: usize) -> u321049 fn read_reg(&self, reg_idx: usize) -> u32 { 1050 self.lock().read_reg(reg_idx) 1051 } write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>1052 fn write_reg( 1053 &mut self, 1054 reg_idx: usize, 1055 offset: u64, 1056 data: &[u8], 1057 ) -> Option<Box<dyn PciCapConfigWriteResult>> { 1058 self.lock().write_reg(reg_idx, offset, data) 1059 } set_cap_mapping(&mut self, mapping: PciCapMapping)1060 fn set_cap_mapping(&mut self, mapping: PciCapMapping) { 1061 self.lock().set_cap_mapping(mapping) 1062 } 1063 } 1064 1065 /// Struct for updating a capabilitiy's mmio mapping. 1066 pub struct PciCapMapping { 1067 mapping: Arc<Mutex<MemoryMapping>>, 1068 offset: usize, 1069 num_regs: usize, 1070 } 1071 1072 impl PciCapMapping { 1073 /// Set the bits of register `reg_idx` specified by `mask` to `data`. set_reg(&mut self, reg_idx: usize, data: u32, mask: u32)1074 pub fn set_reg(&mut self, reg_idx: usize, data: u32, mask: u32) { 1075 if reg_idx >= self.num_regs { 1076 error!( 1077 "out of bounds register write {} vs {}", 1078 self.num_regs, reg_idx 1079 ); 1080 return; 1081 } 1082 let mapping = self.mapping.lock(); 1083 let offset = self.offset + reg_idx * 4; 1084 let cur_value = mapping.read_obj::<u32>(offset).expect("memcpy failed"); 1085 let new_val = (cur_value & !mask) | (data & mask); 1086 mapping 1087 .write_obj_volatile(new_val, offset) 1088 .expect("memcpy failed"); 1089 if let Err(err) = mapping.flush_region(offset, 4) { 1090 error!( 1091 "failed to flush write to pci cap in mmio register ({}): {}", 1092 reg_idx, err 1093 ); 1094 } 1095 } 1096 } 1097 1098 #[cfg(test)] 1099 mod tests { 1100 use zerocopy::FromBytes; 1101 use zerocopy::Immutable; 1102 use zerocopy::IntoBytes; 1103 use zerocopy::KnownLayout; 1104 1105 use super::*; 1106 1107 #[repr(C, packed)] 1108 #[derive(Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)] 1109 #[allow(dead_code)] 1110 struct TestCap { 1111 _vndr: u8, 1112 _next: u8, 1113 len: u8, 1114 foo: u8, 1115 } 1116 1117 impl PciCapability for TestCap { bytes(&self) -> &[u8]1118 fn bytes(&self) -> &[u8] { 1119 self.as_bytes() 1120 } 1121 id(&self) -> PciCapabilityID1122 fn id(&self) -> PciCapabilityID { 1123 PciCapabilityID::VendorSpecific 1124 } 1125 writable_bits(&self) -> Vec<u32>1126 fn writable_bits(&self) -> Vec<u32> { 1127 vec![0u32; 1] 1128 } 1129 } 1130 1131 #[test] add_capability()1132 fn add_capability() { 1133 let mut cfg = PciConfiguration::new( 1134 0x1234, 1135 0x5678, 1136 PciClassCode::MultimediaController, 1137 &PciMultimediaSubclass::AudioController, 1138 None, 1139 PciHeaderType::Device, 1140 0xABCD, 1141 0x2468, 1142 0, 1143 ); 1144 1145 // Add two capabilities with different contents. 1146 let cap1 = TestCap { 1147 _vndr: 0, 1148 _next: 0, 1149 len: 4, 1150 foo: 0xAA, 1151 }; 1152 let cap1_offset = 64; 1153 cfg.add_capability(&cap1, None).unwrap(); 1154 1155 let cap2 = TestCap { 1156 _vndr: 0, 1157 _next: 0, 1158 len: 0x04, 1159 foo: 0x55, 1160 }; 1161 let cap2_offset = 68; 1162 cfg.add_capability(&cap2, None).unwrap(); 1163 1164 // The capability list head should be pointing to cap1. 1165 let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF; 1166 assert_eq!(cap1_offset, cap_ptr as usize); 1167 1168 // Verify the contents of the capabilities. 1169 let cap1_data = cfg.read_reg(cap1_offset / 4); 1170 assert_eq!(cap1_data & 0xFF, 0x09); // capability ID 1171 assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer 1172 assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len 1173 assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo 1174 1175 let cap2_data = cfg.read_reg(cap2_offset / 4); 1176 assert_eq!(cap2_data & 0xFF, 0x09); // capability ID 1177 assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer 1178 assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len 1179 assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo 1180 } 1181 1182 #[derive(Copy, Clone)] 1183 enum TestPI { 1184 Test = 0x5a, 1185 } 1186 1187 impl PciProgrammingInterface for TestPI { get_register_value(&self) -> u81188 fn get_register_value(&self) -> u8 { 1189 *self as u8 1190 } 1191 } 1192 1193 #[test] class_code()1194 fn class_code() { 1195 let cfg = PciConfiguration::new( 1196 0x1234, 1197 0x5678, 1198 PciClassCode::MultimediaController, 1199 &PciMultimediaSubclass::AudioController, 1200 Some(&TestPI::Test), 1201 PciHeaderType::Device, 1202 0xABCD, 1203 0x2468, 1204 0, 1205 ); 1206 1207 let class_reg = cfg.read_reg(2); 1208 let class_code = (class_reg >> 24) & 0xFF; 1209 let subclass = (class_reg >> 16) & 0xFF; 1210 let prog_if = (class_reg >> 8) & 0xFF; 1211 assert_eq!(class_code, 0x04); 1212 assert_eq!(subclass, 0x01); 1213 assert_eq!(prog_if, 0x5a); 1214 } 1215 1216 #[test] read_only_bits()1217 fn read_only_bits() { 1218 let mut cfg = PciConfiguration::new( 1219 0x1234, 1220 0x5678, 1221 PciClassCode::MultimediaController, 1222 &PciMultimediaSubclass::AudioController, 1223 Some(&TestPI::Test), 1224 PciHeaderType::Device, 1225 0xABCD, 1226 0x2468, 1227 0, 1228 ); 1229 1230 // Attempt to overwrite vendor ID and device ID, which are read-only 1231 cfg.write_reg(0, 0, &[0xBA, 0xAD, 0xF0, 0x0D]); 1232 // The original vendor and device ID should remain. 1233 assert_eq!(cfg.read_reg(0), 0x56781234); 1234 } 1235 1236 #[test] query_unused_bar()1237 fn query_unused_bar() { 1238 let cfg = PciConfiguration::new( 1239 0x1234, 1240 0x5678, 1241 PciClassCode::MultimediaController, 1242 &PciMultimediaSubclass::AudioController, 1243 Some(&TestPI::Test), 1244 PciHeaderType::Device, 1245 0xABCD, 1246 0x2468, 1247 0, 1248 ); 1249 1250 // No BAR 0 has been configured, so these should return None or 0 as appropriate. 1251 assert_eq!(cfg.get_bar_type(0), None); 1252 assert_eq!(cfg.get_bar_addr(0), 0); 1253 1254 let mut bar_iter = cfg.get_bars(); 1255 assert_eq!(bar_iter.next(), None); 1256 } 1257 1258 #[test] add_pci_bar_mem_64bit()1259 fn add_pci_bar_mem_64bit() { 1260 let mut cfg = PciConfiguration::new( 1261 0x1234, 1262 0x5678, 1263 PciClassCode::MultimediaController, 1264 &PciMultimediaSubclass::AudioController, 1265 Some(&TestPI::Test), 1266 PciHeaderType::Device, 1267 0xABCD, 1268 0x2468, 1269 0, 1270 ); 1271 1272 cfg.add_pci_bar( 1273 PciBarConfiguration::new( 1274 0, 1275 0x10, 1276 PciBarRegionType::Memory64BitRegion, 1277 PciBarPrefetchable::NotPrefetchable, 1278 ) 1279 .set_address(0x0123_4567_89AB_CDE0), 1280 ) 1281 .expect("add_pci_bar failed"); 1282 1283 assert_eq!( 1284 cfg.get_bar_type(0), 1285 Some(PciBarRegionType::Memory64BitRegion) 1286 ); 1287 assert_eq!(cfg.get_bar_addr(0), 0x0123_4567_89AB_CDE0); 1288 assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF); 1289 assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0); 1290 1291 let mut bar_iter = cfg.get_bars(); 1292 assert_eq!( 1293 bar_iter.next(), 1294 Some(PciBarConfiguration { 1295 addr: 0x0123_4567_89AB_CDE0, 1296 size: 0x10, 1297 bar_idx: 0, 1298 region_type: PciBarRegionType::Memory64BitRegion, 1299 prefetchable: PciBarPrefetchable::NotPrefetchable 1300 }) 1301 ); 1302 assert_eq!(bar_iter.next(), None); 1303 } 1304 1305 #[test] add_pci_bar_mem_32bit()1306 fn add_pci_bar_mem_32bit() { 1307 let mut cfg = PciConfiguration::new( 1308 0x1234, 1309 0x5678, 1310 PciClassCode::MultimediaController, 1311 &PciMultimediaSubclass::AudioController, 1312 Some(&TestPI::Test), 1313 PciHeaderType::Device, 1314 0xABCD, 1315 0x2468, 1316 0, 1317 ); 1318 1319 cfg.add_pci_bar( 1320 PciBarConfiguration::new( 1321 0, 1322 0x10, 1323 PciBarRegionType::Memory32BitRegion, 1324 PciBarPrefetchable::NotPrefetchable, 1325 ) 1326 .set_address(0x12345670), 1327 ) 1328 .expect("add_pci_bar failed"); 1329 1330 assert_eq!( 1331 cfg.get_bar_type(0), 1332 Some(PciBarRegionType::Memory32BitRegion) 1333 ); 1334 assert_eq!(cfg.get_bar_addr(0), 0x12345670); 1335 assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0); 1336 1337 let mut bar_iter = cfg.get_bars(); 1338 assert_eq!( 1339 bar_iter.next(), 1340 Some(PciBarConfiguration { 1341 addr: 0x12345670, 1342 size: 0x10, 1343 bar_idx: 0, 1344 region_type: PciBarRegionType::Memory32BitRegion, 1345 prefetchable: PciBarPrefetchable::NotPrefetchable 1346 }) 1347 ); 1348 assert_eq!(bar_iter.next(), None); 1349 } 1350 1351 #[test] add_pci_bar_io()1352 fn add_pci_bar_io() { 1353 let mut cfg = PciConfiguration::new( 1354 0x1234, 1355 0x5678, 1356 PciClassCode::MultimediaController, 1357 &PciMultimediaSubclass::AudioController, 1358 Some(&TestPI::Test), 1359 PciHeaderType::Device, 1360 0xABCD, 1361 0x2468, 1362 0, 1363 ); 1364 1365 cfg.add_pci_bar( 1366 PciBarConfiguration::new( 1367 0, 1368 0x4, 1369 PciBarRegionType::IoRegion, 1370 PciBarPrefetchable::NotPrefetchable, 1371 ) 1372 .set_address(0x1230), 1373 ) 1374 .expect("add_pci_bar failed"); 1375 1376 assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IoRegion)); 1377 assert_eq!(cfg.get_bar_addr(0), 0x1230); 1378 assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC); 1379 1380 let mut bar_iter = cfg.get_bars(); 1381 assert_eq!( 1382 bar_iter.next(), 1383 Some(PciBarConfiguration { 1384 addr: 0x1230, 1385 size: 0x4, 1386 bar_idx: 0, 1387 region_type: PciBarRegionType::IoRegion, 1388 prefetchable: PciBarPrefetchable::NotPrefetchable 1389 }) 1390 ); 1391 assert_eq!(bar_iter.next(), None); 1392 } 1393 1394 #[test] add_pci_bar_multiple()1395 fn add_pci_bar_multiple() { 1396 let mut cfg = PciConfiguration::new( 1397 0x1234, 1398 0x5678, 1399 PciClassCode::MultimediaController, 1400 &PciMultimediaSubclass::AudioController, 1401 Some(&TestPI::Test), 1402 PciHeaderType::Device, 1403 0xABCD, 1404 0x2468, 1405 0, 1406 ); 1407 1408 // bar_num 0-1: 64-bit memory 1409 cfg.add_pci_bar( 1410 PciBarConfiguration::new( 1411 0, 1412 0x10, 1413 PciBarRegionType::Memory64BitRegion, 1414 PciBarPrefetchable::NotPrefetchable, 1415 ) 1416 .set_address(0x0123_4567_89AB_CDE0), 1417 ) 1418 .expect("add_pci_bar failed"); 1419 1420 // bar 2: 32-bit memory 1421 cfg.add_pci_bar( 1422 PciBarConfiguration::new( 1423 2, 1424 0x10, 1425 PciBarRegionType::Memory32BitRegion, 1426 PciBarPrefetchable::NotPrefetchable, 1427 ) 1428 .set_address(0x12345670), 1429 ) 1430 .expect("add_pci_bar failed"); 1431 1432 // bar 3: I/O 1433 cfg.add_pci_bar( 1434 PciBarConfiguration::new( 1435 3, 1436 0x4, 1437 PciBarRegionType::IoRegion, 1438 PciBarPrefetchable::NotPrefetchable, 1439 ) 1440 .set_address(0x1230), 1441 ) 1442 .expect("add_pci_bar failed"); 1443 1444 // Confirm default memory and I/O region configurations. 1445 let mut bar_iter = cfg.get_bars(); 1446 assert_eq!( 1447 bar_iter.next(), 1448 Some(PciBarConfiguration { 1449 addr: 0x0123_4567_89AB_CDE0, 1450 size: 0x10, 1451 bar_idx: 0, 1452 region_type: PciBarRegionType::Memory64BitRegion, 1453 prefetchable: PciBarPrefetchable::NotPrefetchable 1454 }) 1455 ); 1456 assert_eq!( 1457 bar_iter.next(), 1458 Some(PciBarConfiguration { 1459 addr: 0x12345670, 1460 size: 0x10, 1461 bar_idx: 2, 1462 region_type: PciBarRegionType::Memory32BitRegion, 1463 prefetchable: PciBarPrefetchable::NotPrefetchable 1464 }) 1465 ); 1466 assert_eq!( 1467 bar_iter.next(), 1468 Some(PciBarConfiguration { 1469 addr: 0x1230, 1470 size: 0x4, 1471 bar_idx: 3, 1472 region_type: PciBarRegionType::IoRegion, 1473 prefetchable: PciBarPrefetchable::NotPrefetchable 1474 }) 1475 ); 1476 assert_eq!(bar_iter.next(), None); 1477 1478 // Reassign the address for BAR 0 and verify that get_memory_regions() matches. 1479 cfg.write_reg(4 + 0, 0, &0xBBAA9980u32.to_le_bytes()); 1480 cfg.write_reg(4 + 1, 0, &0xFFEEDDCCu32.to_le_bytes()); 1481 1482 let mut bar_iter = cfg.get_bars(); 1483 assert_eq!( 1484 bar_iter.next(), 1485 Some(PciBarConfiguration { 1486 addr: 0xFFEE_DDCC_BBAA_9980, 1487 size: 0x10, 1488 bar_idx: 0, 1489 region_type: PciBarRegionType::Memory64BitRegion, 1490 prefetchable: PciBarPrefetchable::NotPrefetchable 1491 }) 1492 ); 1493 assert_eq!( 1494 bar_iter.next(), 1495 Some(PciBarConfiguration { 1496 addr: 0x12345670, 1497 size: 0x10, 1498 bar_idx: 2, 1499 region_type: PciBarRegionType::Memory32BitRegion, 1500 prefetchable: PciBarPrefetchable::NotPrefetchable 1501 }) 1502 ); 1503 assert_eq!( 1504 bar_iter.next(), 1505 Some(PciBarConfiguration { 1506 addr: 0x1230, 1507 size: 0x4, 1508 bar_idx: 3, 1509 region_type: PciBarRegionType::IoRegion, 1510 prefetchable: PciBarPrefetchable::NotPrefetchable 1511 }) 1512 ); 1513 assert_eq!(bar_iter.next(), None); 1514 } 1515 1516 #[test] add_pci_bar_invalid_size()1517 fn add_pci_bar_invalid_size() { 1518 let mut cfg = PciConfiguration::new( 1519 0x1234, 1520 0x5678, 1521 PciClassCode::MultimediaController, 1522 &PciMultimediaSubclass::AudioController, 1523 Some(&TestPI::Test), 1524 PciHeaderType::Device, 1525 0xABCD, 1526 0x2468, 1527 0, 1528 ); 1529 1530 // I/O BAR with size 2 (too small) 1531 assert_eq!( 1532 cfg.add_pci_bar( 1533 PciBarConfiguration::new( 1534 0, 1535 0x2, 1536 PciBarRegionType::IoRegion, 1537 PciBarPrefetchable::NotPrefetchable, 1538 ) 1539 .set_address(0x1230), 1540 ), 1541 Err(Error::BarSizeInvalid(0x2)) 1542 ); 1543 1544 // I/O BAR with size 3 (not a power of 2) 1545 assert_eq!( 1546 cfg.add_pci_bar( 1547 PciBarConfiguration::new( 1548 0, 1549 0x3, 1550 PciBarRegionType::IoRegion, 1551 PciBarPrefetchable::NotPrefetchable, 1552 ) 1553 .set_address(0x1230), 1554 ), 1555 Err(Error::BarSizeInvalid(0x3)) 1556 ); 1557 1558 // Memory BAR with size 8 (too small) 1559 assert_eq!( 1560 cfg.add_pci_bar( 1561 PciBarConfiguration::new( 1562 0, 1563 0x8, 1564 PciBarRegionType::Memory32BitRegion, 1565 PciBarPrefetchable::NotPrefetchable, 1566 ) 1567 .set_address(0x12345670), 1568 ), 1569 Err(Error::BarSizeInvalid(0x8)) 1570 ); 1571 } 1572 1573 #[test] add_rom_bar()1574 fn add_rom_bar() { 1575 let mut cfg = PciConfiguration::new( 1576 0x1234, 1577 0x5678, 1578 PciClassCode::MultimediaController, 1579 &PciMultimediaSubclass::AudioController, 1580 Some(&TestPI::Test), 1581 PciHeaderType::Device, 1582 0xABCD, 1583 0x2468, 1584 0, 1585 ); 1586 1587 // Attempt to add a 64-bit memory BAR as the expansion ROM (invalid). 1588 assert_eq!( 1589 cfg.add_pci_bar(PciBarConfiguration::new( 1590 ROM_BAR_IDX, 1591 0x1000, 1592 PciBarRegionType::Memory64BitRegion, 1593 PciBarPrefetchable::NotPrefetchable, 1594 ),), 1595 Err(Error::BarInvalidRomType) 1596 ); 1597 1598 // Attempt to add an I/O BAR as the expansion ROM (invalid). 1599 assert_eq!( 1600 cfg.add_pci_bar(PciBarConfiguration::new( 1601 ROM_BAR_IDX, 1602 0x1000, 1603 PciBarRegionType::IoRegion, 1604 PciBarPrefetchable::NotPrefetchable, 1605 ),), 1606 Err(Error::BarInvalidRomType) 1607 ); 1608 1609 // Attempt to add a 1KB memory region as the expansion ROM (too small). 1610 assert_eq!( 1611 cfg.add_pci_bar(PciBarConfiguration::new( 1612 ROM_BAR_IDX, 1613 1024, 1614 PciBarRegionType::Memory32BitRegion, 1615 PciBarPrefetchable::NotPrefetchable, 1616 ),), 1617 Err(Error::BarSizeInvalid(1024)) 1618 ); 1619 1620 // Add a 32-bit memory BAR as the expansion ROM (valid). 1621 cfg.add_pci_bar( 1622 PciBarConfiguration::new( 1623 ROM_BAR_IDX, 1624 0x800, 1625 PciBarRegionType::Memory32BitRegion, 1626 PciBarPrefetchable::NotPrefetchable, 1627 ) 1628 .set_address(0x12345000), 1629 ) 1630 .expect("add_pci_bar failed"); 1631 1632 assert_eq!( 1633 cfg.get_bar_type(ROM_BAR_IDX), 1634 Some(PciBarRegionType::Memory32BitRegion) 1635 ); 1636 assert_eq!(cfg.get_bar_addr(ROM_BAR_IDX), 0x12345000); 1637 assert_eq!(cfg.read_reg(ROM_BAR_REG), 0x12345000); 1638 assert_eq!(cfg.writable_bits[ROM_BAR_REG], 0xFFFFF801); 1639 } 1640 1641 #[test] pci_configuration_capability_snapshot_restore() -> anyhow::Result<()>1642 fn pci_configuration_capability_snapshot_restore() -> anyhow::Result<()> { 1643 let mut cfg = PciConfiguration::new( 1644 0x1234, 1645 0x5678, 1646 PciClassCode::MultimediaController, 1647 &PciMultimediaSubclass::AudioController, 1648 Some(&TestPI::Test), 1649 PciHeaderType::Device, 1650 0xABCD, 1651 0x2468, 1652 0, 1653 ); 1654 1655 let snap_init = cfg.snapshot().context("failed to snapshot")?; 1656 1657 // Add a capability. 1658 let cap1 = TestCap { 1659 _vndr: 0, 1660 _next: 0, 1661 len: 4, 1662 foo: 0xAA, 1663 }; 1664 cfg.add_capability(&cap1, None).unwrap(); 1665 1666 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?; 1667 cfg.restore(snap_init.clone()) 1668 .context("failed to restore snap_init")?; 1669 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?; 1670 assert_eq!(snap_init, snap_restore_init); 1671 assert_ne!(snap_init, snap_mod); 1672 cfg.restore(snap_mod.clone()) 1673 .context("failed to restore snap_init")?; 1674 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?; 1675 assert_eq!(snap_mod, snap_restore_mod); 1676 Ok(()) 1677 } 1678 1679 #[test] pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()>1680 fn pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()> { 1681 let mut cfg = PciConfiguration::new( 1682 0x1234, 1683 0x5678, 1684 PciClassCode::MultimediaController, 1685 &PciMultimediaSubclass::AudioController, 1686 Some(&TestPI::Test), 1687 PciHeaderType::Device, 1688 0xABCD, 1689 0x2468, 1690 0, 1691 ); 1692 1693 let snap_init = cfg.snapshot().context("failed to snapshot")?; 1694 1695 // bar_num 0-1: 64-bit memory 1696 cfg.add_pci_bar( 1697 PciBarConfiguration::new( 1698 0, 1699 0x10, 1700 PciBarRegionType::Memory64BitRegion, 1701 PciBarPrefetchable::NotPrefetchable, 1702 ) 1703 .set_address(0x0123_4567_89AB_CDE0), 1704 ) 1705 .expect("add_pci_bar failed"); 1706 1707 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?; 1708 cfg.restore(snap_init.clone()) 1709 .context("failed to restore snap_init")?; 1710 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?; 1711 assert_eq!(snap_init, snap_restore_init); 1712 assert_ne!(snap_init, snap_mod); 1713 cfg.restore(snap_mod.clone()) 1714 .context("failed to restore snap_init")?; 1715 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?; 1716 assert_eq!(snap_mod, snap_restore_mod); 1717 Ok(()) 1718 } 1719 1720 #[test] pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()>1721 fn pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()> { 1722 let mut cfg = PciConfiguration::new( 1723 0x1234, 1724 0x5678, 1725 PciClassCode::MultimediaController, 1726 &PciMultimediaSubclass::AudioController, 1727 Some(&TestPI::Test), 1728 PciHeaderType::Device, 1729 0xABCD, 1730 0x2468, 1731 0, 1732 ); 1733 1734 let snap_init = cfg.snapshot().context("failed to snapshot")?; 1735 1736 // Add a capability. 1737 let cap1 = TestCap { 1738 _vndr: 0, 1739 _next: 0, 1740 len: 4, 1741 foo: 0xAA, 1742 }; 1743 cfg.add_capability(&cap1, None).unwrap(); 1744 1745 // bar_num 0-1: 64-bit memory 1746 cfg.add_pci_bar( 1747 PciBarConfiguration::new( 1748 0, 1749 0x10, 1750 PciBarRegionType::Memory64BitRegion, 1751 PciBarPrefetchable::NotPrefetchable, 1752 ) 1753 .set_address(0x0123_4567_89AB_CDE0), 1754 ) 1755 .expect("add_pci_bar failed"); 1756 1757 let snap_mod = cfg.snapshot().context("failed to snapshot mod")?; 1758 cfg.restore(snap_init.clone()) 1759 .context("failed to restore snap_init")?; 1760 let snap_restore_init = cfg.snapshot().context("failed to snapshot restored_init")?; 1761 assert_eq!(snap_init, snap_restore_init); 1762 assert_ne!(snap_init, snap_mod); 1763 cfg.restore(snap_mod.clone()) 1764 .context("failed to restore snap_init")?; 1765 let snap_restore_mod = cfg.snapshot().context("failed to snapshot restored_mod")?; 1766 assert_eq!(snap_mod, snap_restore_mod); 1767 Ok(()) 1768 } 1769 } 1770