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