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