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