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::convert::TryFrom; 6 use std::convert::TryInto; 7 8 use anyhow::Context; 9 use base::custom_serde::deserialize_seq_to_arr; 10 use base::custom_serde::serialize_arr; 11 use base::warn; 12 use remain::sorted; 13 use serde::Deserialize; 14 use serde::Serialize; 15 use thiserror::Error; 16 17 use crate::pci::PciInterruptPin; 18 19 // The number of 32bit registers in the config space, 256 bytes. 20 const NUM_CONFIGURATION_REGISTERS: usize = 64; 21 22 pub const PCI_ID_REG: usize = 0; 23 pub const COMMAND_REG: usize = 1; 24 pub const COMMAND_REG_IO_SPACE_MASK: u32 = 0x0000_0001; 25 pub const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002; 26 const STATUS_REG: usize = 1; 27 pub const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000; 28 #[allow(dead_code)] 29 #[cfg(unix)] 30 pub const CLASS_REG: usize = 2; 31 #[cfg(feature = "direct")] 32 pub const CLASS_REG_REVISION_ID_OFFSET: usize = 0; 33 pub const HEADER_TYPE_REG: usize = 3; 34 pub const HEADER_TYPE_MULTIFUNCTION_MASK: u32 = 0x0080_0000; 35 pub const BAR0_REG: usize = 4; 36 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc; 37 const BAR_IO_MIN_SIZE: u64 = 4; 38 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0; 39 const BAR_MEM_MIN_SIZE: u64 = 16; 40 const BAR_ROM_MIN_SIZE: u64 = 2048; 41 pub const NUM_BAR_REGS: usize = 7; // 6 normal BARs + expansion ROM BAR. 42 pub const ROM_BAR_IDX: PciBarIndex = 6; 43 pub const ROM_BAR_REG: usize = 12; 44 pub const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34; 45 #[cfg(unix)] 46 pub const PCI_CAP_NEXT_POINTER: usize = 0x1; 47 const FIRST_CAPABILITY_OFFSET: usize = 0x40; 48 pub const CAPABILITY_MAX_OFFSET: usize = 255; 49 50 const INTERRUPT_LINE_PIN_REG: usize = 15; 51 52 /// Represents the types of PCI headers allowed in the configuration registers. 53 #[allow(dead_code)] 54 #[derive(Copy, Clone)] 55 pub enum PciHeaderType { 56 Device, 57 Bridge, 58 } 59 60 /// Classes of PCI nodes. 61 #[allow(dead_code)] 62 #[derive(Copy, Clone, Debug, enumn::N, Serialize, Deserialize, PartialEq, Eq)] 63 pub enum PciClassCode { 64 TooOld, 65 MassStorage, 66 NetworkController, 67 DisplayController, 68 MultimediaController, 69 MemoryController, 70 BridgeDevice, 71 SimpleCommunicationController, 72 BaseSystemPeripheral, 73 InputDevice, 74 DockingStation, 75 Processor, 76 SerialBusController, 77 WirelessController, 78 IntelligentIoController, 79 SatelliteCommunicationController, 80 EncryptionController, 81 DataAcquisitionSignalProcessing, 82 ProcessingAccelerator, 83 NonEssentialInstrumentation, 84 Other = 0xff, 85 } 86 87 impl PciClassCode { get_register_value(&self) -> u888 pub fn get_register_value(&self) -> u8 { 89 *self as u8 90 } 91 } 92 93 #[sorted] 94 #[derive(Error, Debug)] 95 pub enum PciClassCodeParseError { 96 #[error("Unknown class code")] 97 Unknown, 98 } 99 100 impl TryFrom<u8> for PciClassCode { 101 type Error = PciClassCodeParseError; try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError>102 fn try_from(v: u8) -> std::result::Result<PciClassCode, PciClassCodeParseError> { 103 match PciClassCode::n(v) { 104 Some(class) => Ok(class), 105 None => Err(PciClassCodeParseError::Unknown), 106 } 107 } 108 } 109 110 /// A PCI sublcass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait 111 /// is implemented by each subclass. It allows use of a trait object to generate configurations. 112 pub trait PciSubclass { 113 /// Convert this subclass to the value used in the PCI specification. get_register_value(&self) -> u8114 fn get_register_value(&self) -> u8; 115 } 116 117 /// Subclasses of the DisplayController class. 118 #[allow(dead_code)] 119 #[derive(Copy, Clone)] 120 pub enum PciDisplaySubclass { 121 VgaCompatibleController = 0x00, 122 XgaCompatibleController = 0x01, 123 ThreeDController = 0x02, 124 Other = 0x80, 125 } 126 127 impl PciSubclass for PciDisplaySubclass { get_register_value(&self) -> u8128 fn get_register_value(&self) -> u8 { 129 *self as u8 130 } 131 } 132 133 /// Subclasses of the MultimediaController class. 134 #[allow(dead_code)] 135 #[derive(Copy, Clone)] 136 pub enum PciMultimediaSubclass { 137 VideoController = 0x00, 138 AudioController = 0x01, 139 TelephonyDevice = 0x02, 140 AudioDevice = 0x03, 141 Other = 0x80, 142 } 143 144 impl PciSubclass for PciMultimediaSubclass { get_register_value(&self) -> u8145 fn get_register_value(&self) -> u8 { 146 *self as u8 147 } 148 } 149 150 /// Subclasses of the BridgeDevice 151 #[allow(dead_code)] 152 #[derive(Copy, Clone)] 153 pub enum PciBridgeSubclass { 154 HostBridge = 0x00, 155 IsaBridge = 0x01, 156 EisaBridge = 0x02, 157 McaBridge = 0x03, 158 PciToPciBridge = 0x04, 159 PcmciaBridge = 0x05, 160 NuBusBridge = 0x06, 161 CardBusBridge = 0x07, 162 RaceWayBridge = 0x08, 163 PciToPciSemiTransparentBridge = 0x09, 164 InfiniBrandToPciHostBridge = 0x0a, 165 OtherBridgeDevice = 0x80, 166 } 167 168 impl PciSubclass for PciBridgeSubclass { get_register_value(&self) -> u8169 fn get_register_value(&self) -> u8 { 170 *self as u8 171 } 172 } 173 174 /// Subclass of the SerialBus 175 #[allow(dead_code)] 176 #[derive(Copy, Clone)] 177 pub enum PciSerialBusSubClass { 178 Firewire = 0x00, 179 AccessBus = 0x01, 180 Ssa = 0x02, 181 Usb = 0x03, 182 } 183 184 impl PciSubclass for PciSerialBusSubClass { get_register_value(&self) -> u8185 fn get_register_value(&self) -> u8 { 186 *self as u8 187 } 188 } 189 190 /// Subclasses for PciClassCode Other. 191 #[allow(dead_code)] 192 #[derive(Copy, Clone)] 193 #[repr(u8)] 194 pub enum PciOtherSubclass { 195 Other = 0xff, 196 } 197 198 impl PciSubclass for PciOtherSubclass { get_register_value(&self) -> u8199 fn get_register_value(&self) -> u8 { 200 *self as u8 201 } 202 } 203 204 /// A PCI class programming interface. Each combination of `PciClassCode` and 205 /// `PciSubclass` can specify a set of register-level programming interfaces. 206 /// This trait is implemented by each programming interface. 207 /// It allows use of a trait object to generate configurations. 208 pub trait PciProgrammingInterface { 209 /// Convert this programming interface to the value used in the PCI specification. get_register_value(&self) -> u8210 fn get_register_value(&self) -> u8; 211 } 212 213 /// Types of PCI capabilities. 214 pub enum PciCapabilityID { 215 ListID = 0, 216 PowerManagement = 0x01, 217 AcceleratedGraphicsPort = 0x02, 218 VitalProductData = 0x03, 219 SlotIdentification = 0x04, 220 MessageSignalledInterrupts = 0x05, 221 CompactPciHotSwap = 0x06, 222 Pcix = 0x07, 223 HyperTransport = 0x08, 224 VendorSpecific = 0x09, 225 Debugport = 0x0A, 226 CompactPciCentralResourceControl = 0x0B, 227 PciStandardHotPlugController = 0x0C, 228 BridgeSubsystemVendorDeviceID = 0x0D, 229 AgpTargetPciPciBridge = 0x0E, 230 SecureDevice = 0x0F, 231 PciExpress = 0x10, 232 Msix = 0x11, 233 SataDataIndexConf = 0x12, 234 PciAdvancedFeatures = 0x13, 235 PciEnhancedAllocation = 0x14, 236 } 237 238 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space. 239 pub trait PciCapability { bytes(&self) -> &[u8]240 fn bytes(&self) -> &[u8]; id(&self) -> PciCapabilityID241 fn id(&self) -> PciCapabilityID; writable_bits(&self) -> Vec<u32>242 fn writable_bits(&self) -> Vec<u32>; 243 } 244 245 /// Contains the configuration space of a PCI node. 246 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space). 247 /// The configuration space is accessed with DWORD reads and writes from the guest. 248 #[derive(Serialize, Deserialize)] 249 pub struct PciConfiguration { 250 #[serde( 251 serialize_with = "serialize_arr", 252 deserialize_with = "deserialize_seq_to_arr" 253 )] 254 registers: [u32; NUM_CONFIGURATION_REGISTERS], 255 #[serde( 256 serialize_with = "serialize_arr", 257 deserialize_with = "deserialize_seq_to_arr" 258 )] 259 writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register. 260 bar_used: [bool; NUM_BAR_REGS], 261 bar_configs: [Option<PciBarConfiguration>; NUM_BAR_REGS], 262 // Contains the byte offset and size of the last capability. 263 last_capability: Option<(usize, usize)>, 264 } 265 266 /// See pci_regs.h in kernel 267 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 268 pub enum PciBarRegionType { 269 Memory32BitRegion = 0, 270 IoRegion = 0x01, 271 Memory64BitRegion = 0x04, 272 } 273 274 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 275 pub enum PciBarPrefetchable { 276 NotPrefetchable = 0, 277 Prefetchable = 0x08, 278 } 279 280 pub type PciBarIndex = usize; 281 282 #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] 283 pub struct PciBarConfiguration { 284 addr: u64, 285 size: u64, 286 bar_idx: PciBarIndex, 287 region_type: PciBarRegionType, 288 prefetchable: PciBarPrefetchable, 289 } 290 291 pub struct PciBarIter<'a> { 292 config: &'a PciConfiguration, 293 bar_num: PciBarIndex, 294 } 295 296 impl<'a> Iterator for PciBarIter<'a> { 297 type Item = PciBarConfiguration; 298 next(&mut self) -> Option<Self::Item>299 fn next(&mut self) -> Option<Self::Item> { 300 while self.bar_num < NUM_BAR_REGS { 301 let bar_config = self.config.get_bar_configuration(self.bar_num); 302 self.bar_num += 1; 303 if let Some(bar_config) = bar_config { 304 return Some(bar_config); 305 } 306 } 307 308 None 309 } 310 } 311 312 #[sorted] 313 #[derive(Error, Debug, PartialEq, Eq)] 314 pub enum Error { 315 #[error("address {0} size {1} too big")] 316 BarAddressInvalid(u64, u64), 317 #[error("address {0} is not aligned to size {1}")] 318 BarAlignmentInvalid(u64, u64), 319 #[error("bar {0} already used")] 320 BarInUse(PciBarIndex), 321 #[error("64bit bar {0} already used (requires two regs)")] 322 BarInUse64(PciBarIndex), 323 #[error("bar {0} invalid, max {}", NUM_BAR_REGS - 1)] 324 BarInvalid(PciBarIndex), 325 #[error("64bitbar {0} invalid, requires two regs, max {}", ROM_BAR_IDX - 1)] 326 BarInvalid64(PciBarIndex), 327 #[error("expansion rom bar must be a memory region")] 328 BarInvalidRomType, 329 #[error("bar address {0} not a power of two")] 330 BarSizeInvalid(u64), 331 #[error("empty capabilities are invalid")] 332 CapabilityEmpty, 333 #[error("Invalid capability length {0}")] 334 CapabilityLengthInvalid(usize), 335 #[error("capability of size {0} doesn't fit")] 336 CapabilitySpaceFull(usize), 337 } 338 339 pub type Result<T> = std::result::Result<T, Error>; 340 341 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, ) -> Self342 pub fn new( 343 vendor_id: u16, 344 device_id: u16, 345 class_code: PciClassCode, 346 subclass: &dyn PciSubclass, 347 programming_interface: Option<&dyn PciProgrammingInterface>, 348 header_type: PciHeaderType, 349 subsystem_vendor_id: u16, 350 subsystem_id: u16, 351 revision_id: u8, 352 ) -> Self { 353 let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS]; 354 let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS]; 355 registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id); 356 // TODO(dverkamp): Status should be write-1-to-clear 357 writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w) 358 let pi = if let Some(pi) = programming_interface { 359 pi.get_register_value() 360 } else { 361 0 362 }; 363 registers[2] = u32::from(class_code.get_register_value()) << 24 364 | u32::from(subclass.get_register_value()) << 16 365 | u32::from(pi) << 8 366 | u32::from(revision_id); 367 writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w) 368 match header_type { 369 PciHeaderType::Device => { 370 registers[3] = 0x0000_0000; // Header type 0 (device) 371 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w) 372 registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id); 373 } 374 PciHeaderType::Bridge => { 375 registers[3] = 0x0001_0000; // Header type 1 (bridge) 376 writable_bits[6] = 0x00ff_ffff; // Primary/secondary/subordinate bus number, 377 // secondary latency timer 378 registers[7] = 0x0000_00f0; // IO base > IO Limit, no IO address on secondary side at initialize 379 writable_bits[7] = 0xf900_0000; // IO base and limit, secondary status, 380 registers[8] = 0x0000_fff0; // mem base > mem Limit, no MMIO address on secondary side at initialize 381 writable_bits[8] = 0xfff0_fff0; // Memory base and limit 382 registers[9] = 0x0001_fff1; // pmem base > pmem Limit, no prefetch MMIO address on secondary side at initialize 383 writable_bits[9] = 0xfff0_fff0; // Prefetchable base and limit 384 writable_bits[10] = 0xffff_ffff; // Prefetchable base upper 32 bits 385 writable_bits[11] = 0xffff_ffff; // Prefetchable limit upper 32 bits 386 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w) 387 } 388 }; 389 390 PciConfiguration { 391 registers, 392 writable_bits, 393 bar_used: [false; NUM_BAR_REGS], 394 bar_configs: [None; NUM_BAR_REGS], 395 last_capability: None, 396 } 397 } 398 399 /// Reads a 32bit register from `reg_idx` in the register map. read_reg(&self, reg_idx: usize) -> u32400 pub fn read_reg(&self, reg_idx: usize) -> u32 { 401 *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff)) 402 } 403 404 /// Writes data to PciConfiguration.registers. 405 /// `reg_idx` - index into PciConfiguration.registers. 406 /// `offset` - PciConfiguration.registers is in unit of DWord, offset define byte 407 /// offset in the DWrod. 408 /// `data` - The data to write. write_reg(&mut self, reg_idx: usize, offset: u64, data: &[u8])409 pub fn write_reg(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 410 let reg_offset = reg_idx * 4 + offset as usize; 411 match data.len() { 412 1 => self.write_byte(reg_offset, data[0]), 413 2 => self.write_word(reg_offset, u16::from_le_bytes(data.try_into().unwrap())), 414 4 => self.write_dword(reg_offset, u32::from_le_bytes(data.try_into().unwrap())), 415 _ => (), 416 } 417 } 418 419 /// Writes a 32bit dword to `offset`. `offset` must be 32bit aligned. write_dword(&mut self, offset: usize, value: u32)420 fn write_dword(&mut self, offset: usize, value: u32) { 421 if offset % 4 != 0 { 422 warn!("bad PCI config dword write offset {}", offset); 423 return; 424 } 425 let reg_idx = offset / 4; 426 if let Some(r) = self.registers.get_mut(reg_idx) { 427 *r = (*r & !self.writable_bits[reg_idx]) | (value & self.writable_bits[reg_idx]); 428 } else { 429 warn!("bad PCI dword write {}", offset); 430 } 431 } 432 433 /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned. write_word(&mut self, offset: usize, value: u16)434 fn write_word(&mut self, offset: usize, value: u16) { 435 let shift = match offset % 4 { 436 0 => 0, 437 2 => 16, 438 _ => { 439 warn!("bad PCI config word write offset {}", offset); 440 return; 441 } 442 }; 443 let reg_idx = offset / 4; 444 445 if let Some(r) = self.registers.get_mut(reg_idx) { 446 let writable_mask = self.writable_bits[reg_idx]; 447 let mask = (0xffffu32 << shift) & writable_mask; 448 let shifted_value = (u32::from(value) << shift) & writable_mask; 449 *r = *r & !mask | shifted_value; 450 } else { 451 warn!("bad PCI config word write offset {}", offset); 452 } 453 } 454 455 /// Writes a byte to `offset`. write_byte(&mut self, offset: usize, value: u8)456 fn write_byte(&mut self, offset: usize, value: u8) { 457 self.write_byte_internal(offset, value, true); 458 } 459 460 /// Writes a byte to `offset`, optionally enforcing read-only bits. write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool)461 fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) { 462 let shift = (offset % 4) * 8; 463 let reg_idx = offset / 4; 464 465 if let Some(r) = self.registers.get_mut(reg_idx) { 466 let writable_mask = if apply_writable_mask { 467 self.writable_bits[reg_idx] 468 } else { 469 0xffff_ffff 470 }; 471 let mask = (0xffu32 << shift) & writable_mask; 472 let shifted_value = (u32::from(value) << shift) & writable_mask; 473 *r = *r & !mask | shifted_value; 474 } else { 475 warn!("bad PCI config byte write offset {}", offset); 476 } 477 } 478 479 /// Adds a region specified by `config`. Configures the specified BAR(s) to 480 /// report this region and size to the guest kernel. Enforces a few constraints 481 /// (i.e, region size must be power of two, register not already used). Returns 'None' on 482 /// failure all, `Some(BarIndex)` on success. add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex>483 pub fn add_pci_bar(&mut self, config: PciBarConfiguration) -> Result<PciBarIndex> { 484 if config.bar_idx >= NUM_BAR_REGS { 485 return Err(Error::BarInvalid(config.bar_idx)); 486 } 487 488 if self.bar_used[config.bar_idx] { 489 return Err(Error::BarInUse(config.bar_idx)); 490 } 491 492 if config.size.count_ones() != 1 { 493 return Err(Error::BarSizeInvalid(config.size)); 494 } 495 496 if config.is_expansion_rom() && config.region_type != PciBarRegionType::Memory32BitRegion { 497 return Err(Error::BarInvalidRomType); 498 } 499 500 let min_size = if config.is_expansion_rom() { 501 BAR_ROM_MIN_SIZE 502 } else if config.region_type == PciBarRegionType::IoRegion { 503 BAR_IO_MIN_SIZE 504 } else { 505 BAR_MEM_MIN_SIZE 506 }; 507 508 if config.size < min_size { 509 return Err(Error::BarSizeInvalid(config.size)); 510 } 511 512 if config.addr % config.size != 0 { 513 return Err(Error::BarAlignmentInvalid(config.addr, config.size)); 514 } 515 516 let reg_idx = config.reg_index(); 517 let end_addr = config 518 .addr 519 .checked_add(config.size) 520 .ok_or(Error::BarAddressInvalid(config.addr, config.size))?; 521 match config.region_type { 522 PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => { 523 if end_addr > u64::from(u32::max_value()) { 524 return Err(Error::BarAddressInvalid(config.addr, config.size)); 525 } 526 } 527 PciBarRegionType::Memory64BitRegion => { 528 // The expansion ROM BAR cannot be used for part of a 64-bit BAR. 529 if config.bar_idx + 1 >= ROM_BAR_IDX { 530 return Err(Error::BarInvalid64(config.bar_idx)); 531 } 532 533 if end_addr > u64::max_value() { 534 return Err(Error::BarAddressInvalid(config.addr, config.size)); 535 } 536 537 if self.bar_used[config.bar_idx + 1] { 538 return Err(Error::BarInUse64(config.bar_idx)); 539 } 540 541 self.registers[reg_idx + 1] = (config.addr >> 32) as u32; 542 self.writable_bits[reg_idx + 1] = !((config.size - 1) >> 32) as u32; 543 self.bar_used[config.bar_idx + 1] = true; 544 } 545 } 546 547 let (mask, lower_bits) = match config.region_type { 548 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => { 549 self.registers[COMMAND_REG] |= COMMAND_REG_MEMORY_SPACE_MASK; 550 ( 551 BAR_MEM_ADDR_MASK, 552 config.prefetchable as u32 | config.region_type as u32, 553 ) 554 } 555 PciBarRegionType::IoRegion => { 556 self.registers[COMMAND_REG] |= COMMAND_REG_IO_SPACE_MASK; 557 (BAR_IO_ADDR_MASK, config.region_type as u32) 558 } 559 }; 560 561 self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits; 562 self.writable_bits[reg_idx] = !(config.size - 1) as u32; 563 if config.is_expansion_rom() { 564 self.writable_bits[reg_idx] |= 1; // Expansion ROM enable bit. 565 } 566 self.bar_used[config.bar_idx] = true; 567 self.bar_configs[config.bar_idx] = Some(config); 568 Ok(config.bar_idx) 569 } 570 571 /// Returns an iterator of the currently configured base address registers. 572 #[allow(dead_code)] // TODO(dverkamp): remove this once used get_bars(&self) -> PciBarIter573 pub fn get_bars(&self) -> PciBarIter { 574 PciBarIter { 575 config: self, 576 bar_num: 0, 577 } 578 } 579 580 /// Returns the configuration of a base address register, if present. get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>581 pub fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> { 582 let config = self.bar_configs.get(bar_num)?; 583 584 if let Some(mut config) = config { 585 let command = self.read_reg(COMMAND_REG); 586 if (config.is_memory() && (command & COMMAND_REG_MEMORY_SPACE_MASK == 0)) 587 || (config.is_io() && (command & COMMAND_REG_IO_SPACE_MASK == 0)) 588 { 589 return None; 590 } 591 592 // The address may have been modified by the guest, so the value in bar_configs 593 // may be outdated. Replace it with the current value. 594 config.addr = self.get_bar_addr(bar_num); 595 Some(config) 596 } else { 597 None 598 } 599 } 600 601 /// Returns the type of the given BAR region. get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType>602 pub fn get_bar_type(&self, bar_num: PciBarIndex) -> Option<PciBarRegionType> { 603 self.bar_configs.get(bar_num)?.map(|c| c.region_type) 604 } 605 606 /// Returns the address of the given BAR region. get_bar_addr(&self, bar_num: PciBarIndex) -> u64607 pub fn get_bar_addr(&self, bar_num: PciBarIndex) -> u64 { 608 let bar_idx = if bar_num == ROM_BAR_IDX { 609 ROM_BAR_REG 610 } else { 611 BAR0_REG + bar_num 612 }; 613 614 let bar_type = match self.get_bar_type(bar_num) { 615 Some(t) => t, 616 None => return 0, 617 }; 618 619 match bar_type { 620 PciBarRegionType::IoRegion => u64::from(self.registers[bar_idx] & BAR_IO_ADDR_MASK), 621 PciBarRegionType::Memory32BitRegion => { 622 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK) 623 } 624 PciBarRegionType::Memory64BitRegion => { 625 u64::from(self.registers[bar_idx] & BAR_MEM_ADDR_MASK) 626 | u64::from(self.registers[bar_idx + 1]) << 32 627 } 628 } 629 } 630 631 /// Configures the IRQ line and pin used by this device. set_irq(&mut self, line: u8, pin: PciInterruptPin)632 pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) { 633 // `pin` is 1-based in the pci config space. 634 let pin_idx = (pin as u32) + 1; 635 self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG] 636 & 0xffff_0000) 637 | (pin_idx << 8) 638 | u32::from(line); 639 } 640 641 /// Adds the capability `cap_data` to the list of capabilities. 642 /// `cap_data` should include the two-byte PCI capability header (type, next), 643 /// but not populate it. Correct values will be generated automatically based 644 /// on `cap_data.id()`. add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize>645 pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> { 646 let total_len = cap_data.bytes().len(); 647 // Check that the length is valid. 648 if cap_data.bytes().is_empty() { 649 return Err(Error::CapabilityEmpty); 650 } 651 let (cap_offset, tail_offset) = match self.last_capability { 652 Some((offset, len)) => (Self::next_dword(offset, len), offset + 1), 653 None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET), 654 }; 655 let end_offset = cap_offset 656 .checked_add(total_len) 657 .ok_or(Error::CapabilitySpaceFull(total_len))?; 658 if end_offset > CAPABILITY_MAX_OFFSET { 659 return Err(Error::CapabilitySpaceFull(total_len)); 660 } 661 self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK; 662 self.write_byte_internal(tail_offset, cap_offset as u8, false); 663 self.write_byte_internal(cap_offset, cap_data.id() as u8, false); 664 self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer. 665 for (i, byte) in cap_data.bytes().iter().enumerate().skip(2) { 666 self.write_byte_internal(cap_offset + i, *byte, false); 667 } 668 let reg_idx = cap_offset / 4; 669 for (i, dword) in cap_data.writable_bits().iter().enumerate() { 670 self.writable_bits[reg_idx + i] = *dword; 671 } 672 self.last_capability = Some((cap_offset, total_len)); 673 Ok(cap_offset) 674 } 675 676 // Find the next aligned offset after the one given. next_dword(offset: usize, len: usize) -> usize677 fn next_dword(offset: usize, len: usize) -> usize { 678 let next = offset + len; 679 (next + 3) & !3 680 } 681 restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>682 pub fn restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> { 683 let deser: PciConfiguration = 684 serde_json::from_value(data).context("failed to deserialize PciConfiguration")?; 685 *self = deser; 686 Ok(()) 687 } 688 } 689 690 impl PciBarConfiguration { new( bar_idx: PciBarIndex, size: u64, region_type: PciBarRegionType, prefetchable: PciBarPrefetchable, ) -> Self691 pub fn new( 692 bar_idx: PciBarIndex, 693 size: u64, 694 region_type: PciBarRegionType, 695 prefetchable: PciBarPrefetchable, 696 ) -> Self { 697 PciBarConfiguration { 698 bar_idx, 699 addr: 0, 700 size, 701 region_type, 702 prefetchable, 703 } 704 } 705 bar_index(&self) -> PciBarIndex706 pub fn bar_index(&self) -> PciBarIndex { 707 self.bar_idx 708 } 709 reg_index(&self) -> usize710 pub fn reg_index(&self) -> usize { 711 if self.bar_idx == ROM_BAR_IDX { 712 ROM_BAR_REG 713 } else { 714 BAR0_REG + self.bar_idx 715 } 716 } 717 address(&self) -> u64718 pub fn address(&self) -> u64 { 719 self.addr 720 } 721 address_range(&self) -> std::ops::Range<u64>722 pub fn address_range(&self) -> std::ops::Range<u64> { 723 self.addr..self.addr + self.size 724 } 725 set_address(mut self, addr: u64) -> Self726 pub fn set_address(mut self, addr: u64) -> Self { 727 self.addr = addr; 728 self 729 } 730 size(&self) -> u64731 pub fn size(&self) -> u64 { 732 self.size 733 } 734 is_expansion_rom(&self) -> bool735 pub fn is_expansion_rom(&self) -> bool { 736 self.bar_idx == ROM_BAR_IDX 737 } 738 is_memory(&self) -> bool739 pub fn is_memory(&self) -> bool { 740 matches!( 741 self.region_type, 742 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion 743 ) 744 } 745 is_64bit_memory(&self) -> bool746 pub fn is_64bit_memory(&self) -> bool { 747 self.region_type == PciBarRegionType::Memory64BitRegion 748 } 749 is_io(&self) -> bool750 pub fn is_io(&self) -> bool { 751 self.region_type == PciBarRegionType::IoRegion 752 } 753 is_prefetchable(&self) -> bool754 pub fn is_prefetchable(&self) -> bool { 755 self.is_memory() && self.prefetchable == PciBarPrefetchable::Prefetchable 756 } 757 } 758 759 #[cfg(test)] 760 mod tests { 761 use zerocopy::AsBytes; 762 763 use super::*; 764 765 #[repr(packed)] 766 #[derive(Clone, Copy, AsBytes)] 767 #[allow(dead_code)] 768 struct TestCap { 769 _vndr: u8, 770 _next: u8, 771 len: u8, 772 foo: u8, 773 } 774 775 impl PciCapability for TestCap { bytes(&self) -> &[u8]776 fn bytes(&self) -> &[u8] { 777 self.as_bytes() 778 } 779 id(&self) -> PciCapabilityID780 fn id(&self) -> PciCapabilityID { 781 PciCapabilityID::VendorSpecific 782 } 783 writable_bits(&self) -> Vec<u32>784 fn writable_bits(&self) -> Vec<u32> { 785 vec![0u32; 1] 786 } 787 } 788 789 #[test] add_capability()790 fn add_capability() { 791 let mut cfg = PciConfiguration::new( 792 0x1234, 793 0x5678, 794 PciClassCode::MultimediaController, 795 &PciMultimediaSubclass::AudioController, 796 None, 797 PciHeaderType::Device, 798 0xABCD, 799 0x2468, 800 0, 801 ); 802 803 // Add two capabilities with different contents. 804 let cap1 = TestCap { 805 _vndr: 0, 806 _next: 0, 807 len: 4, 808 foo: 0xAA, 809 }; 810 let cap1_offset = cfg.add_capability(&cap1).unwrap(); 811 assert_eq!(cap1_offset % 4, 0); 812 813 let cap2 = TestCap { 814 _vndr: 0, 815 _next: 0, 816 len: 0x04, 817 foo: 0x55, 818 }; 819 let cap2_offset = cfg.add_capability(&cap2).unwrap(); 820 assert_eq!(cap2_offset % 4, 0); 821 822 // The capability list head should be pointing to cap1. 823 let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF; 824 assert_eq!(cap1_offset, cap_ptr as usize); 825 826 // Verify the contents of the capabilities. 827 let cap1_data = cfg.read_reg(cap1_offset / 4); 828 assert_eq!(cap1_data & 0xFF, 0x09); // capability ID 829 assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer 830 assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len 831 assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo 832 833 let cap2_data = cfg.read_reg(cap2_offset / 4); 834 assert_eq!(cap2_data & 0xFF, 0x09); // capability ID 835 assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer 836 assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len 837 assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo 838 } 839 840 #[derive(Copy, Clone)] 841 enum TestPI { 842 Test = 0x5a, 843 } 844 845 impl PciProgrammingInterface for TestPI { get_register_value(&self) -> u8846 fn get_register_value(&self) -> u8 { 847 *self as u8 848 } 849 } 850 851 #[test] class_code()852 fn class_code() { 853 let cfg = PciConfiguration::new( 854 0x1234, 855 0x5678, 856 PciClassCode::MultimediaController, 857 &PciMultimediaSubclass::AudioController, 858 Some(&TestPI::Test), 859 PciHeaderType::Device, 860 0xABCD, 861 0x2468, 862 0, 863 ); 864 865 let class_reg = cfg.read_reg(2); 866 let class_code = (class_reg >> 24) & 0xFF; 867 let subclass = (class_reg >> 16) & 0xFF; 868 let prog_if = (class_reg >> 8) & 0xFF; 869 assert_eq!(class_code, 0x04); 870 assert_eq!(subclass, 0x01); 871 assert_eq!(prog_if, 0x5a); 872 } 873 874 #[test] read_only_bits()875 fn read_only_bits() { 876 let mut cfg = PciConfiguration::new( 877 0x1234, 878 0x5678, 879 PciClassCode::MultimediaController, 880 &PciMultimediaSubclass::AudioController, 881 Some(&TestPI::Test), 882 PciHeaderType::Device, 883 0xABCD, 884 0x2468, 885 0, 886 ); 887 888 // Attempt to overwrite vendor ID and device ID, which are read-only 889 cfg.write_reg(0, 0, &[0xBA, 0xAD, 0xF0, 0x0D]); 890 // The original vendor and device ID should remain. 891 assert_eq!(cfg.read_reg(0), 0x56781234); 892 } 893 894 #[test] query_unused_bar()895 fn query_unused_bar() { 896 let cfg = PciConfiguration::new( 897 0x1234, 898 0x5678, 899 PciClassCode::MultimediaController, 900 &PciMultimediaSubclass::AudioController, 901 Some(&TestPI::Test), 902 PciHeaderType::Device, 903 0xABCD, 904 0x2468, 905 0, 906 ); 907 908 // No BAR 0 has been configured, so these should return None or 0 as appropriate. 909 assert_eq!(cfg.get_bar_type(0), None); 910 assert_eq!(cfg.get_bar_addr(0), 0); 911 912 let mut bar_iter = cfg.get_bars(); 913 assert_eq!(bar_iter.next(), None); 914 } 915 916 #[test] add_pci_bar_mem_64bit()917 fn add_pci_bar_mem_64bit() { 918 let mut cfg = PciConfiguration::new( 919 0x1234, 920 0x5678, 921 PciClassCode::MultimediaController, 922 &PciMultimediaSubclass::AudioController, 923 Some(&TestPI::Test), 924 PciHeaderType::Device, 925 0xABCD, 926 0x2468, 927 0, 928 ); 929 930 cfg.add_pci_bar( 931 PciBarConfiguration::new( 932 0, 933 0x10, 934 PciBarRegionType::Memory64BitRegion, 935 PciBarPrefetchable::NotPrefetchable, 936 ) 937 .set_address(0x0123_4567_89AB_CDE0), 938 ) 939 .expect("add_pci_bar failed"); 940 941 assert_eq!( 942 cfg.get_bar_type(0), 943 Some(PciBarRegionType::Memory64BitRegion) 944 ); 945 assert_eq!(cfg.get_bar_addr(0), 0x0123_4567_89AB_CDE0); 946 assert_eq!(cfg.writable_bits[BAR0_REG + 1], 0xFFFFFFFF); 947 assert_eq!(cfg.writable_bits[BAR0_REG + 0], 0xFFFFFFF0); 948 949 let mut bar_iter = cfg.get_bars(); 950 assert_eq!( 951 bar_iter.next(), 952 Some(PciBarConfiguration { 953 addr: 0x0123_4567_89AB_CDE0, 954 size: 0x10, 955 bar_idx: 0, 956 region_type: PciBarRegionType::Memory64BitRegion, 957 prefetchable: PciBarPrefetchable::NotPrefetchable 958 }) 959 ); 960 assert_eq!(bar_iter.next(), None); 961 } 962 963 #[test] add_pci_bar_mem_32bit()964 fn add_pci_bar_mem_32bit() { 965 let mut cfg = PciConfiguration::new( 966 0x1234, 967 0x5678, 968 PciClassCode::MultimediaController, 969 &PciMultimediaSubclass::AudioController, 970 Some(&TestPI::Test), 971 PciHeaderType::Device, 972 0xABCD, 973 0x2468, 974 0, 975 ); 976 977 cfg.add_pci_bar( 978 PciBarConfiguration::new( 979 0, 980 0x10, 981 PciBarRegionType::Memory32BitRegion, 982 PciBarPrefetchable::NotPrefetchable, 983 ) 984 .set_address(0x12345670), 985 ) 986 .expect("add_pci_bar failed"); 987 988 assert_eq!( 989 cfg.get_bar_type(0), 990 Some(PciBarRegionType::Memory32BitRegion) 991 ); 992 assert_eq!(cfg.get_bar_addr(0), 0x12345670); 993 assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFF0); 994 995 let mut bar_iter = cfg.get_bars(); 996 assert_eq!( 997 bar_iter.next(), 998 Some(PciBarConfiguration { 999 addr: 0x12345670, 1000 size: 0x10, 1001 bar_idx: 0, 1002 region_type: PciBarRegionType::Memory32BitRegion, 1003 prefetchable: PciBarPrefetchable::NotPrefetchable 1004 }) 1005 ); 1006 assert_eq!(bar_iter.next(), None); 1007 } 1008 1009 #[test] add_pci_bar_io()1010 fn add_pci_bar_io() { 1011 let mut cfg = PciConfiguration::new( 1012 0x1234, 1013 0x5678, 1014 PciClassCode::MultimediaController, 1015 &PciMultimediaSubclass::AudioController, 1016 Some(&TestPI::Test), 1017 PciHeaderType::Device, 1018 0xABCD, 1019 0x2468, 1020 0, 1021 ); 1022 1023 cfg.add_pci_bar( 1024 PciBarConfiguration::new( 1025 0, 1026 0x4, 1027 PciBarRegionType::IoRegion, 1028 PciBarPrefetchable::NotPrefetchable, 1029 ) 1030 .set_address(0x1230), 1031 ) 1032 .expect("add_pci_bar failed"); 1033 1034 assert_eq!(cfg.get_bar_type(0), Some(PciBarRegionType::IoRegion)); 1035 assert_eq!(cfg.get_bar_addr(0), 0x1230); 1036 assert_eq!(cfg.writable_bits[BAR0_REG], 0xFFFFFFFC); 1037 1038 let mut bar_iter = cfg.get_bars(); 1039 assert_eq!( 1040 bar_iter.next(), 1041 Some(PciBarConfiguration { 1042 addr: 0x1230, 1043 size: 0x4, 1044 bar_idx: 0, 1045 region_type: PciBarRegionType::IoRegion, 1046 prefetchable: PciBarPrefetchable::NotPrefetchable 1047 }) 1048 ); 1049 assert_eq!(bar_iter.next(), None); 1050 } 1051 1052 #[test] add_pci_bar_multiple()1053 fn add_pci_bar_multiple() { 1054 let mut cfg = PciConfiguration::new( 1055 0x1234, 1056 0x5678, 1057 PciClassCode::MultimediaController, 1058 &PciMultimediaSubclass::AudioController, 1059 Some(&TestPI::Test), 1060 PciHeaderType::Device, 1061 0xABCD, 1062 0x2468, 1063 0, 1064 ); 1065 1066 // bar_num 0-1: 64-bit memory 1067 cfg.add_pci_bar( 1068 PciBarConfiguration::new( 1069 0, 1070 0x10, 1071 PciBarRegionType::Memory64BitRegion, 1072 PciBarPrefetchable::NotPrefetchable, 1073 ) 1074 .set_address(0x0123_4567_89AB_CDE0), 1075 ) 1076 .expect("add_pci_bar failed"); 1077 1078 // bar 2: 32-bit memory 1079 cfg.add_pci_bar( 1080 PciBarConfiguration::new( 1081 2, 1082 0x10, 1083 PciBarRegionType::Memory32BitRegion, 1084 PciBarPrefetchable::NotPrefetchable, 1085 ) 1086 .set_address(0x12345670), 1087 ) 1088 .expect("add_pci_bar failed"); 1089 1090 // bar 3: I/O 1091 cfg.add_pci_bar( 1092 PciBarConfiguration::new( 1093 3, 1094 0x4, 1095 PciBarRegionType::IoRegion, 1096 PciBarPrefetchable::NotPrefetchable, 1097 ) 1098 .set_address(0x1230), 1099 ) 1100 .expect("add_pci_bar failed"); 1101 1102 // Confirm default memory and I/O region configurations. 1103 let mut bar_iter = cfg.get_bars(); 1104 assert_eq!( 1105 bar_iter.next(), 1106 Some(PciBarConfiguration { 1107 addr: 0x0123_4567_89AB_CDE0, 1108 size: 0x10, 1109 bar_idx: 0, 1110 region_type: PciBarRegionType::Memory64BitRegion, 1111 prefetchable: PciBarPrefetchable::NotPrefetchable 1112 }) 1113 ); 1114 assert_eq!( 1115 bar_iter.next(), 1116 Some(PciBarConfiguration { 1117 addr: 0x12345670, 1118 size: 0x10, 1119 bar_idx: 2, 1120 region_type: PciBarRegionType::Memory32BitRegion, 1121 prefetchable: PciBarPrefetchable::NotPrefetchable 1122 }) 1123 ); 1124 assert_eq!( 1125 bar_iter.next(), 1126 Some(PciBarConfiguration { 1127 addr: 0x1230, 1128 size: 0x4, 1129 bar_idx: 3, 1130 region_type: PciBarRegionType::IoRegion, 1131 prefetchable: PciBarPrefetchable::NotPrefetchable 1132 }) 1133 ); 1134 assert_eq!(bar_iter.next(), None); 1135 1136 // Reassign the address for BAR 0 and verify that get_memory_regions() matches. 1137 cfg.write_reg(4 + 0, 0, &0xBBAA9980u32.to_le_bytes()); 1138 cfg.write_reg(4 + 1, 0, &0xFFEEDDCCu32.to_le_bytes()); 1139 1140 let mut bar_iter = cfg.get_bars(); 1141 assert_eq!( 1142 bar_iter.next(), 1143 Some(PciBarConfiguration { 1144 addr: 0xFFEE_DDCC_BBAA_9980, 1145 size: 0x10, 1146 bar_idx: 0, 1147 region_type: PciBarRegionType::Memory64BitRegion, 1148 prefetchable: PciBarPrefetchable::NotPrefetchable 1149 }) 1150 ); 1151 assert_eq!( 1152 bar_iter.next(), 1153 Some(PciBarConfiguration { 1154 addr: 0x12345670, 1155 size: 0x10, 1156 bar_idx: 2, 1157 region_type: PciBarRegionType::Memory32BitRegion, 1158 prefetchable: PciBarPrefetchable::NotPrefetchable 1159 }) 1160 ); 1161 assert_eq!( 1162 bar_iter.next(), 1163 Some(PciBarConfiguration { 1164 addr: 0x1230, 1165 size: 0x4, 1166 bar_idx: 3, 1167 region_type: PciBarRegionType::IoRegion, 1168 prefetchable: PciBarPrefetchable::NotPrefetchable 1169 }) 1170 ); 1171 assert_eq!(bar_iter.next(), None); 1172 } 1173 1174 #[test] add_pci_bar_invalid_size()1175 fn add_pci_bar_invalid_size() { 1176 let mut cfg = PciConfiguration::new( 1177 0x1234, 1178 0x5678, 1179 PciClassCode::MultimediaController, 1180 &PciMultimediaSubclass::AudioController, 1181 Some(&TestPI::Test), 1182 PciHeaderType::Device, 1183 0xABCD, 1184 0x2468, 1185 0, 1186 ); 1187 1188 // I/O BAR with size 2 (too small) 1189 assert_eq!( 1190 cfg.add_pci_bar( 1191 PciBarConfiguration::new( 1192 0, 1193 0x2, 1194 PciBarRegionType::IoRegion, 1195 PciBarPrefetchable::NotPrefetchable, 1196 ) 1197 .set_address(0x1230), 1198 ), 1199 Err(Error::BarSizeInvalid(0x2)) 1200 ); 1201 1202 // I/O BAR with size 3 (not a power of 2) 1203 assert_eq!( 1204 cfg.add_pci_bar( 1205 PciBarConfiguration::new( 1206 0, 1207 0x3, 1208 PciBarRegionType::IoRegion, 1209 PciBarPrefetchable::NotPrefetchable, 1210 ) 1211 .set_address(0x1230), 1212 ), 1213 Err(Error::BarSizeInvalid(0x3)) 1214 ); 1215 1216 // Memory BAR with size 8 (too small) 1217 assert_eq!( 1218 cfg.add_pci_bar( 1219 PciBarConfiguration::new( 1220 0, 1221 0x8, 1222 PciBarRegionType::Memory32BitRegion, 1223 PciBarPrefetchable::NotPrefetchable, 1224 ) 1225 .set_address(0x12345670), 1226 ), 1227 Err(Error::BarSizeInvalid(0x8)) 1228 ); 1229 } 1230 1231 #[test] add_rom_bar()1232 fn add_rom_bar() { 1233 let mut cfg = PciConfiguration::new( 1234 0x1234, 1235 0x5678, 1236 PciClassCode::MultimediaController, 1237 &PciMultimediaSubclass::AudioController, 1238 Some(&TestPI::Test), 1239 PciHeaderType::Device, 1240 0xABCD, 1241 0x2468, 1242 0, 1243 ); 1244 1245 // Attempt to add a 64-bit memory BAR as the expansion ROM (invalid). 1246 assert_eq!( 1247 cfg.add_pci_bar(PciBarConfiguration::new( 1248 ROM_BAR_IDX, 1249 0x1000, 1250 PciBarRegionType::Memory64BitRegion, 1251 PciBarPrefetchable::NotPrefetchable, 1252 ),), 1253 Err(Error::BarInvalidRomType) 1254 ); 1255 1256 // Attempt to add an I/O BAR as the expansion ROM (invalid). 1257 assert_eq!( 1258 cfg.add_pci_bar(PciBarConfiguration::new( 1259 ROM_BAR_IDX, 1260 0x1000, 1261 PciBarRegionType::IoRegion, 1262 PciBarPrefetchable::NotPrefetchable, 1263 ),), 1264 Err(Error::BarInvalidRomType) 1265 ); 1266 1267 // Attempt to add a 1KB memory region as the expansion ROM (too small). 1268 assert_eq!( 1269 cfg.add_pci_bar(PciBarConfiguration::new( 1270 ROM_BAR_IDX, 1271 1024, 1272 PciBarRegionType::Memory32BitRegion, 1273 PciBarPrefetchable::NotPrefetchable, 1274 ),), 1275 Err(Error::BarSizeInvalid(1024)) 1276 ); 1277 1278 // Add a 32-bit memory BAR as the expansion ROM (valid). 1279 cfg.add_pci_bar( 1280 PciBarConfiguration::new( 1281 ROM_BAR_IDX, 1282 0x800, 1283 PciBarRegionType::Memory32BitRegion, 1284 PciBarPrefetchable::NotPrefetchable, 1285 ) 1286 .set_address(0x12345000), 1287 ) 1288 .expect("add_pci_bar failed"); 1289 1290 assert_eq!( 1291 cfg.get_bar_type(ROM_BAR_IDX), 1292 Some(PciBarRegionType::Memory32BitRegion) 1293 ); 1294 assert_eq!(cfg.get_bar_addr(ROM_BAR_IDX), 0x12345000); 1295 assert_eq!(cfg.read_reg(ROM_BAR_REG), 0x12345000); 1296 assert_eq!(cfg.writable_bits[ROM_BAR_REG], 0xFFFFF801); 1297 } 1298 1299 #[test] pci_configuration_capability_snapshot_restore() -> anyhow::Result<()>1300 fn pci_configuration_capability_snapshot_restore() -> anyhow::Result<()> { 1301 let mut cfg = PciConfiguration::new( 1302 0x1234, 1303 0x5678, 1304 PciClassCode::MultimediaController, 1305 &PciMultimediaSubclass::AudioController, 1306 Some(&TestPI::Test), 1307 PciHeaderType::Device, 1308 0xABCD, 1309 0x2468, 1310 0, 1311 ); 1312 1313 let snap_init = serde_json::to_value(&cfg).context("failed to snapshot")?; 1314 1315 // Add a capability. 1316 let cap1 = TestCap { 1317 _vndr: 0, 1318 _next: 0, 1319 len: 4, 1320 foo: 0xAA, 1321 }; 1322 cfg.add_capability(&cap1).unwrap(); 1323 1324 let snap_mod = serde_json::to_value(&cfg).context("failed to snapshot mod")?; 1325 cfg.restore(snap_init.clone()) 1326 .context("failed to restore snap_init")?; 1327 let snap_restore_init = 1328 serde_json::to_value(&cfg).context("failed to snapshot restored_init")?; 1329 assert_eq!(snap_init, snap_restore_init); 1330 assert_ne!(snap_init, snap_mod); 1331 cfg.restore(snap_mod.clone()) 1332 .context("failed to restore snap_init")?; 1333 let snap_restore_mod = 1334 serde_json::to_value(&cfg).context("failed to snapshot restored_mod")?; 1335 assert_eq!(snap_mod, snap_restore_mod); 1336 Ok(()) 1337 } 1338 1339 #[test] pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()>1340 fn pci_configuration_pci_bar_snapshot_restore() -> anyhow::Result<()> { 1341 let mut cfg = PciConfiguration::new( 1342 0x1234, 1343 0x5678, 1344 PciClassCode::MultimediaController, 1345 &PciMultimediaSubclass::AudioController, 1346 Some(&TestPI::Test), 1347 PciHeaderType::Device, 1348 0xABCD, 1349 0x2468, 1350 0, 1351 ); 1352 1353 let snap_init = serde_json::to_value(&cfg).context("failed to snapshot")?; 1354 1355 // bar_num 0-1: 64-bit memory 1356 cfg.add_pci_bar( 1357 PciBarConfiguration::new( 1358 0, 1359 0x10, 1360 PciBarRegionType::Memory64BitRegion, 1361 PciBarPrefetchable::NotPrefetchable, 1362 ) 1363 .set_address(0x0123_4567_89AB_CDE0), 1364 ) 1365 .expect("add_pci_bar failed"); 1366 1367 let snap_mod = serde_json::to_value(&cfg).context("failed to snapshot mod")?; 1368 cfg.restore(snap_init.clone()) 1369 .context("failed to restore snap_init")?; 1370 let snap_restore_init = 1371 serde_json::to_value(&cfg).context("failed to snapshot restored_init")?; 1372 assert_eq!(snap_init, snap_restore_init); 1373 assert_ne!(snap_init, snap_mod); 1374 cfg.restore(snap_mod.clone()) 1375 .context("failed to restore snap_init")?; 1376 let snap_restore_mod = 1377 serde_json::to_value(&cfg).context("failed to snapshot restored_mod")?; 1378 assert_eq!(snap_mod, snap_restore_mod); 1379 Ok(()) 1380 } 1381 1382 #[test] pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()>1383 fn pci_configuration_capability_pci_bar_snapshot_restore() -> anyhow::Result<()> { 1384 let mut cfg = PciConfiguration::new( 1385 0x1234, 1386 0x5678, 1387 PciClassCode::MultimediaController, 1388 &PciMultimediaSubclass::AudioController, 1389 Some(&TestPI::Test), 1390 PciHeaderType::Device, 1391 0xABCD, 1392 0x2468, 1393 0, 1394 ); 1395 1396 let snap_init = serde_json::to_value(&cfg).context("failed to snapshot")?; 1397 1398 // Add a capability. 1399 let cap1 = TestCap { 1400 _vndr: 0, 1401 _next: 0, 1402 len: 4, 1403 foo: 0xAA, 1404 }; 1405 cfg.add_capability(&cap1).unwrap(); 1406 1407 // bar_num 0-1: 64-bit memory 1408 cfg.add_pci_bar( 1409 PciBarConfiguration::new( 1410 0, 1411 0x10, 1412 PciBarRegionType::Memory64BitRegion, 1413 PciBarPrefetchable::NotPrefetchable, 1414 ) 1415 .set_address(0x0123_4567_89AB_CDE0), 1416 ) 1417 .expect("add_pci_bar failed"); 1418 1419 let snap_mod = serde_json::to_value(&cfg).context("failed to snapshot mod")?; 1420 cfg.restore(snap_init.clone()) 1421 .context("failed to restore snap_init")?; 1422 let snap_restore_init = 1423 serde_json::to_value(&cfg).context("failed to snapshot restored_init")?; 1424 assert_eq!(snap_init, snap_restore_init); 1425 assert_ne!(snap_init, snap_mod); 1426 cfg.restore(snap_mod.clone()) 1427 .context("failed to restore snap_init")?; 1428 let snap_restore_mod = 1429 serde_json::to_value(&cfg).context("failed to snapshot restored_mod")?; 1430 assert_eq!(snap_mod, snap_restore_mod); 1431 Ok(()) 1432 } 1433 } 1434