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-BSD-3-Clause file. 4 5 use crate::device::BarReprogrammingParams; 6 use crate::{MsixConfig, PciInterruptPin}; 7 use byteorder::{ByteOrder, LittleEndian}; 8 use std::fmt::{self, Display}; 9 use std::sync::{Arc, Mutex}; 10 use versionize::{VersionMap, Versionize, VersionizeError, VersionizeResult}; 11 use versionize_derive::Versionize; 12 use vm_device::PciBarType; 13 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable, VersionMapped}; 14 15 // The number of 32bit registers in the config space, 4096 bytes. 16 const NUM_CONFIGURATION_REGISTERS: usize = 1024; 17 18 const STATUS_REG: usize = 1; 19 const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000; 20 const BAR0_REG: usize = 4; 21 const ROM_BAR_REG: usize = 12; 22 const ROM_BAR_IDX: usize = 6; 23 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc; 24 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0; 25 const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800; 26 const MSI_CAPABILITY_REGISTER_MASK: u32 = 0x0071_0000; 27 const MSIX_CAPABILITY_REGISTER_MASK: u32 = 0xc000_0000; 28 const NUM_BAR_REGS: usize = 6; 29 const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34; 30 const FIRST_CAPABILITY_OFFSET: usize = 0x40; 31 const CAPABILITY_MAX_OFFSET: usize = 192; 32 33 const INTERRUPT_LINE_PIN_REG: usize = 15; 34 35 pub const PCI_CONFIGURATION_ID: &str = "pci_configuration"; 36 37 /// Represents the types of PCI headers allowed in the configuration registers. 38 #[derive(Copy, Clone)] 39 pub enum PciHeaderType { 40 Device, 41 Bridge, 42 } 43 44 /// Classes of PCI nodes. 45 #[allow(dead_code)] 46 #[derive(Copy, Clone)] 47 pub enum PciClassCode { 48 TooOld, 49 MassStorage, 50 NetworkController, 51 DisplayController, 52 MultimediaController, 53 MemoryController, 54 BridgeDevice, 55 SimpleCommunicationController, 56 BaseSystemPeripheral, 57 InputDevice, 58 DockingStation, 59 Processor, 60 SerialBusController, 61 WirelessController, 62 IntelligentIoController, 63 EncryptionController, 64 DataAcquisitionSignalProcessing, 65 Other = 0xff, 66 } 67 68 impl PciClassCode { 69 pub fn get_register_value(self) -> u8 { 70 self as u8 71 } 72 } 73 74 /// A PCI subclass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait 75 /// is implemented by each subclass. It allows use of a trait object to generate configurations. 76 pub trait PciSubclass { 77 /// Convert this subclass to the value used in the PCI specification. 78 fn get_register_value(&self) -> u8; 79 } 80 81 /// Subclasses of the MultimediaController class. 82 #[allow(dead_code)] 83 #[derive(Copy, Clone)] 84 pub enum PciMultimediaSubclass { 85 VideoController = 0x00, 86 AudioController = 0x01, 87 TelephonyDevice = 0x02, 88 AudioDevice = 0x03, 89 Other = 0x80, 90 } 91 92 impl PciSubclass for PciMultimediaSubclass { 93 fn get_register_value(&self) -> u8 { 94 *self as u8 95 } 96 } 97 98 /// Subclasses of the BridgeDevice 99 #[allow(dead_code)] 100 #[derive(Copy, Clone)] 101 pub enum PciBridgeSubclass { 102 HostBridge = 0x00, 103 IsaBridge = 0x01, 104 EisaBridge = 0x02, 105 McaBridge = 0x03, 106 PciToPciBridge = 0x04, 107 PcmciaBridge = 0x05, 108 NuBusBridge = 0x06, 109 CardBusBridge = 0x07, 110 RacEwayBridge = 0x08, 111 PciToPciSemiTransparentBridge = 0x09, 112 InfiniBrandToPciHostBridge = 0x0a, 113 OtherBridgeDevice = 0x80, 114 } 115 116 impl PciSubclass for PciBridgeSubclass { 117 fn get_register_value(&self) -> u8 { 118 *self as u8 119 } 120 } 121 122 /// Subclass of the SerialBus 123 #[allow(dead_code)] 124 #[derive(Copy, Clone)] 125 pub enum PciSerialBusSubClass { 126 Firewire = 0x00, 127 Accessbus = 0x01, 128 Ssa = 0x02, 129 Usb = 0x03, 130 } 131 132 impl PciSubclass for PciSerialBusSubClass { 133 fn get_register_value(&self) -> u8 { 134 *self as u8 135 } 136 } 137 138 /// Mass Storage Sub Classes 139 #[allow(dead_code)] 140 #[derive(Copy, Clone)] 141 pub enum PciMassStorageSubclass { 142 ScsiStorage = 0x00, 143 IdeInterface = 0x01, 144 FloppyController = 0x02, 145 IpiController = 0x03, 146 RaidController = 0x04, 147 AtaController = 0x05, 148 SataController = 0x06, 149 SerialScsiController = 0x07, 150 NvmController = 0x08, 151 MassStorage = 0x80, 152 } 153 154 impl PciSubclass for PciMassStorageSubclass { 155 fn get_register_value(&self) -> u8 { 156 *self as u8 157 } 158 } 159 160 /// Network Controller Sub Classes 161 #[allow(dead_code)] 162 #[derive(Copy, Clone)] 163 pub enum PciNetworkControllerSubclass { 164 EthernetController = 0x00, 165 TokenRingController = 0x01, 166 FddiController = 0x02, 167 AtmController = 0x03, 168 IsdnController = 0x04, 169 WorldFipController = 0x05, 170 PicmgController = 0x06, 171 InfinibandController = 0x07, 172 FabricController = 0x08, 173 NetworkController = 0x80, 174 } 175 176 impl PciSubclass for PciNetworkControllerSubclass { 177 fn get_register_value(&self) -> u8 { 178 *self as u8 179 } 180 } 181 182 /// A PCI class programming interface. Each combination of `PciClassCode` and 183 /// `PciSubclass` can specify a set of register-level programming interfaces. 184 /// This trait is implemented by each programming interface. 185 /// It allows use of a trait object to generate configurations. 186 pub trait PciProgrammingInterface { 187 /// Convert this programming interface to the value used in the PCI specification. 188 fn get_register_value(&self) -> u8; 189 } 190 191 /// Types of PCI capabilities. 192 #[derive(PartialEq, Eq, Copy, Clone)] 193 #[allow(dead_code)] 194 #[allow(non_camel_case_types)] 195 #[repr(u8)] 196 pub enum PciCapabilityId { 197 ListId = 0, 198 PowerManagement = 0x01, 199 AcceleratedGraphicsPort = 0x02, 200 VitalProductData = 0x03, 201 SlotIdentification = 0x04, 202 MessageSignalledInterrupts = 0x05, 203 CompactPciHotSwap = 0x06, 204 PciX = 0x07, 205 HyperTransport = 0x08, 206 VendorSpecific = 0x09, 207 Debugport = 0x0A, 208 CompactPciCentralResourceControl = 0x0B, 209 PciStandardHotPlugController = 0x0C, 210 BridgeSubsystemVendorDeviceId = 0x0D, 211 AgpTargetPciPcibridge = 0x0E, 212 SecureDevice = 0x0F, 213 PciExpress = 0x10, 214 MsiX = 0x11, 215 SataDataIndexConf = 0x12, 216 PciAdvancedFeatures = 0x13, 217 PciEnhancedAllocation = 0x14, 218 } 219 220 impl From<u8> for PciCapabilityId { 221 fn from(c: u8) -> Self { 222 match c { 223 0 => PciCapabilityId::ListId, 224 0x01 => PciCapabilityId::PowerManagement, 225 0x02 => PciCapabilityId::AcceleratedGraphicsPort, 226 0x03 => PciCapabilityId::VitalProductData, 227 0x04 => PciCapabilityId::SlotIdentification, 228 0x05 => PciCapabilityId::MessageSignalledInterrupts, 229 0x06 => PciCapabilityId::CompactPciHotSwap, 230 0x07 => PciCapabilityId::PciX, 231 0x08 => PciCapabilityId::HyperTransport, 232 0x09 => PciCapabilityId::VendorSpecific, 233 0x0A => PciCapabilityId::Debugport, 234 0x0B => PciCapabilityId::CompactPciCentralResourceControl, 235 0x0C => PciCapabilityId::PciStandardHotPlugController, 236 0x0D => PciCapabilityId::BridgeSubsystemVendorDeviceId, 237 0x0E => PciCapabilityId::AgpTargetPciPcibridge, 238 0x0F => PciCapabilityId::SecureDevice, 239 0x10 => PciCapabilityId::PciExpress, 240 0x11 => PciCapabilityId::MsiX, 241 0x12 => PciCapabilityId::SataDataIndexConf, 242 0x13 => PciCapabilityId::PciAdvancedFeatures, 243 0x14 => PciCapabilityId::PciEnhancedAllocation, 244 _ => PciCapabilityId::ListId, 245 } 246 } 247 } 248 249 /// Types of PCI Express capabilities. 250 #[derive(PartialEq, Eq, Copy, Clone, Debug)] 251 #[allow(dead_code)] 252 #[repr(u16)] 253 pub enum PciExpressCapabilityId { 254 NullCapability = 0x0000, 255 AdvancedErrorReporting = 0x0001, 256 VirtualChannelMultiFunctionVirtualChannelNotPresent = 0x0002, 257 DeviceSerialNumber = 0x0003, 258 PowerBudgeting = 0x0004, 259 RootComplexLinkDeclaration = 0x0005, 260 RootComplexInternalLinkControl = 0x0006, 261 RootComplexEventCollectorEndpointAssociation = 0x0007, 262 MultiFunctionVirtualChannel = 0x0008, 263 VirtualChannelMultiFunctionVirtualChannelPresent = 0x0009, 264 RootComplexRegisterBlock = 0x000a, 265 VendorSpecificExtendedCapability = 0x000b, 266 ConfigurationAccessCorrelation = 0x000c, 267 AccessControlServices = 0x000d, 268 AlternativeRoutingIdentificationIntepretation = 0x000e, 269 AddressTranslationServices = 0x000f, 270 SingleRootIoVirtualization = 0x0010, 271 DeprecatedMultiRootIoVirtualzation = 0x0011, 272 Multicast = 0x0012, 273 PageRequestInterface = 0x0013, 274 ReservedForAmd = 0x0014, 275 ResizeableBar = 0x0015, 276 DynamicPowerAllocation = 0x0016, 277 ThpRequester = 0x0017, 278 LatencyToleranceReporting = 0x0018, 279 SecondaryPciExpress = 0x0019, 280 ProtocolMultiplexing = 0x001a, 281 ProcessAddressSpaceId = 0x001b, 282 LnRequestor = 0x001c, 283 DownstreamPortContainment = 0x001d, 284 L1PmSubstates = 0x001e, 285 PrecisionTimeMeasurement = 0x001f, 286 PciExpressOverMphy = 0x0020, 287 FRSQueueing = 0x0021, 288 ReadinessTimeReporting = 0x0022, 289 DesignatedVendorSpecificExtendedCapability = 0x0023, 290 VfResizeableBar = 0x0024, 291 DataLinkFeature = 0x0025, 292 PhysicalLayerSixteenGts = 0x0026, 293 LaneMargeningAtTheReceiver = 0x0027, 294 HierarchyId = 0x0028, 295 NativePcieEnclosureManagement = 0x0029, 296 PhysicalLayerThirtyTwoGts = 0x002a, 297 AlternateProtocol = 0x002b, 298 SystemFirmwareIntermediary = 0x002c, 299 ShadowFunctions = 0x002d, 300 DataObjectExchange = 0x002e, 301 Reserved = 0x002f, 302 ExtendedCapabilitiesAbsence = 0xffff, 303 } 304 305 impl From<u16> for PciExpressCapabilityId { 306 fn from(c: u16) -> Self { 307 match c { 308 0x0000 => PciExpressCapabilityId::NullCapability, 309 0x0001 => PciExpressCapabilityId::AdvancedErrorReporting, 310 0x0002 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelNotPresent, 311 0x0003 => PciExpressCapabilityId::DeviceSerialNumber, 312 0x0004 => PciExpressCapabilityId::PowerBudgeting, 313 0x0005 => PciExpressCapabilityId::RootComplexLinkDeclaration, 314 0x0006 => PciExpressCapabilityId::RootComplexInternalLinkControl, 315 0x0007 => PciExpressCapabilityId::RootComplexEventCollectorEndpointAssociation, 316 0x0008 => PciExpressCapabilityId::MultiFunctionVirtualChannel, 317 0x0009 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelPresent, 318 0x000a => PciExpressCapabilityId::RootComplexRegisterBlock, 319 0x000b => PciExpressCapabilityId::VendorSpecificExtendedCapability, 320 0x000c => PciExpressCapabilityId::ConfigurationAccessCorrelation, 321 0x000d => PciExpressCapabilityId::AccessControlServices, 322 0x000e => PciExpressCapabilityId::AlternativeRoutingIdentificationIntepretation, 323 0x000f => PciExpressCapabilityId::AddressTranslationServices, 324 0x0010 => PciExpressCapabilityId::SingleRootIoVirtualization, 325 0x0011 => PciExpressCapabilityId::DeprecatedMultiRootIoVirtualzation, 326 0x0012 => PciExpressCapabilityId::Multicast, 327 0x0013 => PciExpressCapabilityId::PageRequestInterface, 328 0x0014 => PciExpressCapabilityId::ReservedForAmd, 329 0x0015 => PciExpressCapabilityId::ResizeableBar, 330 0x0016 => PciExpressCapabilityId::DynamicPowerAllocation, 331 0x0017 => PciExpressCapabilityId::ThpRequester, 332 0x0018 => PciExpressCapabilityId::LatencyToleranceReporting, 333 0x0019 => PciExpressCapabilityId::SecondaryPciExpress, 334 0x001a => PciExpressCapabilityId::ProtocolMultiplexing, 335 0x001b => PciExpressCapabilityId::ProcessAddressSpaceId, 336 0x001c => PciExpressCapabilityId::LnRequestor, 337 0x001d => PciExpressCapabilityId::DownstreamPortContainment, 338 0x001e => PciExpressCapabilityId::L1PmSubstates, 339 0x001f => PciExpressCapabilityId::PrecisionTimeMeasurement, 340 0x0020 => PciExpressCapabilityId::PciExpressOverMphy, 341 0x0021 => PciExpressCapabilityId::FRSQueueing, 342 0x0022 => PciExpressCapabilityId::ReadinessTimeReporting, 343 0x0023 => PciExpressCapabilityId::DesignatedVendorSpecificExtendedCapability, 344 0x0024 => PciExpressCapabilityId::VfResizeableBar, 345 0x0025 => PciExpressCapabilityId::DataLinkFeature, 346 0x0026 => PciExpressCapabilityId::PhysicalLayerSixteenGts, 347 0x0027 => PciExpressCapabilityId::LaneMargeningAtTheReceiver, 348 0x0028 => PciExpressCapabilityId::HierarchyId, 349 0x0029 => PciExpressCapabilityId::NativePcieEnclosureManagement, 350 0x002a => PciExpressCapabilityId::PhysicalLayerThirtyTwoGts, 351 0x002b => PciExpressCapabilityId::AlternateProtocol, 352 0x002c => PciExpressCapabilityId::SystemFirmwareIntermediary, 353 0x002d => PciExpressCapabilityId::ShadowFunctions, 354 0x002e => PciExpressCapabilityId::DataObjectExchange, 355 0xffff => PciExpressCapabilityId::ExtendedCapabilitiesAbsence, 356 _ => PciExpressCapabilityId::Reserved, 357 } 358 } 359 } 360 361 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space. 362 pub trait PciCapability { 363 fn bytes(&self) -> &[u8]; 364 fn id(&self) -> PciCapabilityId; 365 } 366 367 fn encode_32_bits_bar_size(bar_size: u32) -> Option<u32> { 368 if bar_size > 0 { 369 return Some(!(bar_size - 1)); 370 } 371 None 372 } 373 374 fn decode_32_bits_bar_size(bar_size: u32) -> Option<u32> { 375 if bar_size > 0 { 376 return Some(!bar_size + 1); 377 } 378 None 379 } 380 381 fn encode_64_bits_bar_size(bar_size: u64) -> Option<(u32, u32)> { 382 if bar_size > 0 { 383 let result = !(bar_size - 1); 384 let result_hi = (result >> 32) as u32; 385 let result_lo = (result & 0xffff_ffff) as u32; 386 return Some((result_hi, result_lo)); 387 } 388 None 389 } 390 391 fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> { 392 let bar_size: u64 = ((bar_size_hi as u64) << 32) | (bar_size_lo as u64); 393 if bar_size > 0 { 394 return Some(!bar_size + 1); 395 } 396 None 397 } 398 399 #[derive(Debug, Default, Clone, Copy, Versionize)] 400 struct PciBar { 401 addr: u32, 402 size: u32, 403 used: bool, 404 r#type: Option<PciBarRegionType>, 405 } 406 407 #[derive(Versionize)] 408 pub struct PciConfigurationState { 409 registers: Vec<u32>, 410 writable_bits: Vec<u32>, 411 bars: Vec<PciBar>, 412 rom_bar_addr: u32, 413 rom_bar_size: u32, 414 rom_bar_used: bool, 415 last_capability: Option<(usize, usize)>, 416 msix_cap_reg_idx: Option<usize>, 417 } 418 419 impl VersionMapped for PciConfigurationState {} 420 421 /// Contains the configuration space of a PCI node. 422 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space). 423 /// The configuration space is accessed with DWORD reads and writes from the guest. 424 pub struct PciConfiguration { 425 registers: [u32; NUM_CONFIGURATION_REGISTERS], 426 writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register. 427 bars: [PciBar; NUM_BAR_REGS], 428 rom_bar_addr: u32, 429 rom_bar_size: u32, 430 rom_bar_used: bool, 431 // Contains the byte offset and size of the last capability. 432 last_capability: Option<(usize, usize)>, 433 msix_cap_reg_idx: Option<usize>, 434 msix_config: Option<Arc<Mutex<MsixConfig>>>, 435 } 436 437 /// See pci_regs.h in kernel 438 #[derive(Copy, Clone, PartialEq, Eq, Versionize, Debug)] 439 pub enum PciBarRegionType { 440 Memory32BitRegion = 0, 441 IoRegion = 0x01, 442 Memory64BitRegion = 0x04, 443 } 444 445 impl From<PciBarType> for PciBarRegionType { 446 fn from(type_: PciBarType) -> Self { 447 match type_ { 448 PciBarType::Io => PciBarRegionType::IoRegion, 449 PciBarType::Mmio32 => PciBarRegionType::Memory32BitRegion, 450 PciBarType::Mmio64 => PciBarRegionType::Memory64BitRegion, 451 } 452 } 453 } 454 455 #[allow(clippy::from_over_into)] 456 impl Into<PciBarType> for PciBarRegionType { 457 fn into(self) -> PciBarType { 458 match self { 459 PciBarRegionType::IoRegion => PciBarType::Io, 460 PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32, 461 PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64, 462 } 463 } 464 } 465 466 #[derive(Copy, Clone)] 467 pub enum PciBarPrefetchable { 468 NotPrefetchable = 0, 469 Prefetchable = 0x08, 470 } 471 472 #[allow(clippy::from_over_into)] 473 impl Into<bool> for PciBarPrefetchable { 474 fn into(self) -> bool { 475 match self { 476 PciBarPrefetchable::NotPrefetchable => false, 477 PciBarPrefetchable::Prefetchable => true, 478 } 479 } 480 } 481 482 #[derive(Copy, Clone)] 483 pub struct PciBarConfiguration { 484 addr: u64, 485 size: u64, 486 idx: usize, 487 region_type: PciBarRegionType, 488 prefetchable: PciBarPrefetchable, 489 } 490 491 #[derive(Debug)] 492 pub enum Error { 493 BarAddressInvalid(u64, u64), 494 BarInUse(usize), 495 BarInUse64(usize), 496 BarInvalid(usize), 497 BarInvalid64(usize), 498 BarSizeInvalid(u64), 499 CapabilityEmpty, 500 CapabilityLengthInvalid(usize), 501 CapabilitySpaceFull(usize), 502 Decode32BarSize, 503 Decode64BarSize, 504 Encode32BarSize, 505 Encode64BarSize, 506 RomBarAddressInvalid(u64, u64), 507 RomBarInUse(usize), 508 RomBarInvalid(usize), 509 RomBarSizeInvalid(u64), 510 } 511 pub type Result<T> = std::result::Result<T, Error>; 512 513 impl std::error::Error for Error {} 514 515 impl Display for Error { 516 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 517 use self::Error::*; 518 match self { 519 BarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s), 520 BarInUse(b) => write!(f, "bar {} already used", b), 521 BarInUse64(b) => write!(f, "64bit bar {} already used(requires two regs)", b), 522 BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1), 523 BarInvalid64(b) => write!( 524 f, 525 "64bitbar {} invalid, requires two regs, max {}", 526 b, 527 NUM_BAR_REGS - 1 528 ), 529 BarSizeInvalid(s) => write!(f, "bar address {} not a power of two", s), 530 CapabilityEmpty => write!(f, "empty capabilities are invalid"), 531 CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {}", l), 532 CapabilitySpaceFull(s) => write!(f, "capability of size {} doesn't fit", s), 533 Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"), 534 Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"), 535 Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"), 536 Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"), 537 RomBarAddressInvalid(a, s) => write!(f, "address {} size {} too big", a, s), 538 RomBarInUse(b) => write!(f, "rom bar {} already used", b), 539 RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1), 540 RomBarSizeInvalid(s) => write!(f, "rom bar address {} not a power of two", s), 541 } 542 } 543 } 544 545 impl PciConfiguration { 546 #[allow(clippy::too_many_arguments)] 547 pub fn new( 548 vendor_id: u16, 549 device_id: u16, 550 revision_id: u8, 551 class_code: PciClassCode, 552 subclass: &dyn PciSubclass, 553 programming_interface: Option<&dyn PciProgrammingInterface>, 554 header_type: PciHeaderType, 555 subsystem_vendor_id: u16, 556 subsystem_id: u16, 557 msix_config: Option<Arc<Mutex<MsixConfig>>>, 558 state: Option<PciConfigurationState>, 559 ) -> Self { 560 let ( 561 registers, 562 writable_bits, 563 bars, 564 rom_bar_addr, 565 rom_bar_size, 566 rom_bar_used, 567 last_capability, 568 msix_cap_reg_idx, 569 ) = if let Some(state) = state { 570 ( 571 state.registers.try_into().unwrap(), 572 state.writable_bits.try_into().unwrap(), 573 state.bars.try_into().unwrap(), 574 state.rom_bar_addr, 575 state.rom_bar_size, 576 state.rom_bar_used, 577 state.last_capability, 578 state.msix_cap_reg_idx, 579 ) 580 } else { 581 let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS]; 582 let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS]; 583 registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id); 584 // TODO(dverkamp): Status should be write-1-to-clear 585 writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w) 586 let pi = if let Some(pi) = programming_interface { 587 pi.get_register_value() 588 } else { 589 0 590 }; 591 registers[2] = u32::from(class_code.get_register_value()) << 24 592 | u32::from(subclass.get_register_value()) << 16 593 | u32::from(pi) << 8 594 | u32::from(revision_id); 595 writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w) 596 match header_type { 597 PciHeaderType::Device => { 598 registers[3] = 0x0000_0000; // Header type 0 (device) 599 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w) 600 } 601 PciHeaderType::Bridge => { 602 registers[3] = 0x0001_0000; // Header type 1 (bridge) 603 writable_bits[9] = 0xfff0_fff0; // Memory base and limit 604 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w) 605 } 606 }; 607 registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id); 608 609 ( 610 registers, 611 writable_bits, 612 [PciBar::default(); NUM_BAR_REGS], 613 0, 614 0, 615 false, 616 None, 617 None, 618 ) 619 }; 620 621 PciConfiguration { 622 registers, 623 writable_bits, 624 bars, 625 rom_bar_addr, 626 rom_bar_size, 627 rom_bar_used, 628 last_capability, 629 msix_cap_reg_idx, 630 msix_config, 631 } 632 } 633 634 fn state(&self) -> PciConfigurationState { 635 PciConfigurationState { 636 registers: self.registers.to_vec(), 637 writable_bits: self.writable_bits.to_vec(), 638 bars: self.bars.to_vec(), 639 rom_bar_addr: self.rom_bar_addr, 640 rom_bar_size: self.rom_bar_size, 641 rom_bar_used: self.rom_bar_used, 642 last_capability: self.last_capability, 643 msix_cap_reg_idx: self.msix_cap_reg_idx, 644 } 645 } 646 647 fn set_state(&mut self, state: &PciConfigurationState) { 648 self.registers.clone_from_slice(state.registers.as_slice()); 649 self.writable_bits 650 .clone_from_slice(state.writable_bits.as_slice()); 651 self.bars.clone_from_slice(state.bars.as_slice()); 652 self.rom_bar_addr = state.rom_bar_addr; 653 self.rom_bar_size = state.rom_bar_size; 654 self.rom_bar_used = state.rom_bar_used; 655 self.last_capability = state.last_capability; 656 self.msix_cap_reg_idx = state.msix_cap_reg_idx; 657 } 658 659 /// Reads a 32bit register from `reg_idx` in the register map. 660 pub fn read_reg(&self, reg_idx: usize) -> u32 { 661 *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff)) 662 } 663 664 /// Writes a 32bit register to `reg_idx` in the register map. 665 pub fn write_reg(&mut self, reg_idx: usize, value: u32) { 666 let mut mask = self.writable_bits[reg_idx]; 667 668 if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(®_idx) { 669 // Handle very specific case where the BAR is being written with 670 // all 1's to retrieve the BAR size during next BAR reading. 671 if value == 0xffff_ffff { 672 mask &= self.bars[reg_idx - 4].size; 673 } 674 } else if reg_idx == ROM_BAR_REG { 675 // Handle very specific case where the BAR is being written with 676 // all 1's on bits 31-11 to retrieve the BAR size during next BAR 677 // reading. 678 if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK { 679 mask &= self.rom_bar_size; 680 } 681 } 682 683 if let Some(r) = self.registers.get_mut(reg_idx) { 684 *r = (*r & !self.writable_bits[reg_idx]) | (value & mask); 685 } else { 686 warn!("bad PCI register write {}", reg_idx); 687 } 688 } 689 690 /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned. 691 pub fn write_word(&mut self, offset: usize, value: u16) { 692 let shift = match offset % 4 { 693 0 => 0, 694 2 => 16, 695 _ => { 696 warn!("bad PCI config write offset {}", offset); 697 return; 698 } 699 }; 700 let reg_idx = offset / 4; 701 702 if let Some(r) = self.registers.get_mut(reg_idx) { 703 let writable_mask = self.writable_bits[reg_idx]; 704 let mask = (0xffffu32 << shift) & writable_mask; 705 let shifted_value = (u32::from(value) << shift) & writable_mask; 706 *r = *r & !mask | shifted_value; 707 } else { 708 warn!("bad PCI config write offset {}", offset); 709 } 710 } 711 712 /// Writes a byte to `offset`. 713 pub fn write_byte(&mut self, offset: usize, value: u8) { 714 self.write_byte_internal(offset, value, true); 715 } 716 717 /// Writes a byte to `offset`, optionally enforcing read-only bits. 718 fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) { 719 let shift = (offset % 4) * 8; 720 let reg_idx = offset / 4; 721 722 if let Some(r) = self.registers.get_mut(reg_idx) { 723 let writable_mask = if apply_writable_mask { 724 self.writable_bits[reg_idx] 725 } else { 726 0xffff_ffff 727 }; 728 let mask = (0xffu32 << shift) & writable_mask; 729 let shifted_value = (u32::from(value) << shift) & writable_mask; 730 *r = *r & !mask | shifted_value; 731 } else { 732 warn!("bad PCI config write offset {}", offset); 733 } 734 } 735 736 /// Adds a region specified by `config`. Configures the specified BAR(s) to 737 /// report this region and size to the guest kernel. Enforces a few constraints 738 /// (i.e, region size must be power of two, register not already used). 739 pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> { 740 let bar_idx = config.idx; 741 let reg_idx = BAR0_REG + bar_idx; 742 743 if self.bars[bar_idx].used { 744 return Err(Error::BarInUse(bar_idx)); 745 } 746 747 if config.size.count_ones() != 1 { 748 return Err(Error::BarSizeInvalid(config.size)); 749 } 750 751 if bar_idx >= NUM_BAR_REGS { 752 return Err(Error::BarInvalid(bar_idx)); 753 } 754 755 let end_addr = config 756 .addr 757 .checked_add(config.size - 1) 758 .ok_or(Error::BarAddressInvalid(config.addr, config.size))?; 759 match config.region_type { 760 PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => { 761 if end_addr > u64::from(u32::max_value()) { 762 return Err(Error::BarAddressInvalid(config.addr, config.size)); 763 } 764 765 // Encode the BAR size as expected by the software running in 766 // the guest. 767 self.bars[bar_idx].size = 768 encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?; 769 } 770 PciBarRegionType::Memory64BitRegion => { 771 if bar_idx + 1 >= NUM_BAR_REGS { 772 return Err(Error::BarInvalid64(bar_idx)); 773 } 774 775 if end_addr > u64::max_value() { 776 return Err(Error::BarAddressInvalid(config.addr, config.size)); 777 } 778 779 if self.bars[bar_idx + 1].used { 780 return Err(Error::BarInUse64(bar_idx)); 781 } 782 783 // Encode the BAR size as expected by the software running in 784 // the guest. 785 let (bar_size_hi, bar_size_lo) = 786 encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?; 787 788 self.registers[reg_idx + 1] = (config.addr >> 32) as u32; 789 self.writable_bits[reg_idx + 1] = 0xffff_ffff; 790 self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1]; 791 self.bars[bar_idx].size = bar_size_lo; 792 self.bars[bar_idx + 1].size = bar_size_hi; 793 self.bars[bar_idx + 1].used = true; 794 } 795 } 796 797 let (mask, lower_bits) = match config.region_type { 798 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => ( 799 BAR_MEM_ADDR_MASK, 800 config.prefetchable as u32 | config.region_type as u32, 801 ), 802 PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32), 803 }; 804 805 self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits; 806 self.writable_bits[reg_idx] = mask; 807 self.bars[bar_idx].addr = self.registers[reg_idx]; 808 self.bars[bar_idx].used = true; 809 self.bars[bar_idx].r#type = Some(config.region_type); 810 811 Ok(()) 812 } 813 814 /// Adds rom expansion BAR. 815 pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()> { 816 let bar_idx = config.idx; 817 let reg_idx = ROM_BAR_REG; 818 819 if self.rom_bar_used { 820 return Err(Error::RomBarInUse(bar_idx)); 821 } 822 823 if config.size.count_ones() != 1 { 824 return Err(Error::RomBarSizeInvalid(config.size)); 825 } 826 827 if bar_idx != ROM_BAR_IDX { 828 return Err(Error::RomBarInvalid(bar_idx)); 829 } 830 831 let end_addr = config 832 .addr 833 .checked_add(config.size - 1) 834 .ok_or(Error::RomBarAddressInvalid(config.addr, config.size))?; 835 836 if end_addr > u64::from(u32::max_value()) { 837 return Err(Error::RomBarAddressInvalid(config.addr, config.size)); 838 } 839 840 self.registers[reg_idx] = (config.addr as u32) | active; 841 self.writable_bits[reg_idx] = ROM_BAR_ADDR_MASK; 842 self.rom_bar_addr = self.registers[reg_idx]; 843 self.rom_bar_size = 844 encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?; 845 self.rom_bar_used = true; 846 847 Ok(()) 848 } 849 850 /// Returns the address of the given BAR region. 851 pub fn get_bar_addr(&self, bar_num: usize) -> u64 { 852 let bar_idx = BAR0_REG + bar_num; 853 854 let mut addr = u64::from(self.bars[bar_num].addr & self.writable_bits[bar_idx]); 855 856 if let Some(bar_type) = self.bars[bar_num].r#type { 857 if bar_type == PciBarRegionType::Memory64BitRegion { 858 addr |= u64::from(self.bars[bar_num + 1].addr) << 32; 859 } 860 } 861 862 addr 863 } 864 865 /// Configures the IRQ line and pin used by this device. 866 pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) { 867 // `pin` is 1-based in the pci config space. 868 let pin_idx = (pin as u32) + 1; 869 self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG] 870 & 0xffff_0000) 871 | (pin_idx << 8) 872 | u32::from(line); 873 } 874 875 /// Adds the capability `cap_data` to the list of capabilities. 876 /// `cap_data` should include the two-byte PCI capability header (type, next), 877 /// but not populate it. Correct values will be generated automatically based 878 /// on `cap_data.id()`. 879 pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> { 880 let total_len = cap_data.bytes().len(); 881 // Check that the length is valid. 882 if cap_data.bytes().is_empty() { 883 return Err(Error::CapabilityEmpty); 884 } 885 let (cap_offset, tail_offset) = match self.last_capability { 886 Some((offset, len)) => (Self::next_dword(offset, len), offset + 1), 887 None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET), 888 }; 889 let end_offset = cap_offset 890 .checked_add(total_len) 891 .ok_or(Error::CapabilitySpaceFull(total_len))?; 892 if end_offset > CAPABILITY_MAX_OFFSET { 893 return Err(Error::CapabilitySpaceFull(total_len)); 894 } 895 self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK; 896 self.write_byte_internal(tail_offset, cap_offset as u8, false); 897 self.write_byte_internal(cap_offset, cap_data.id() as u8, false); 898 self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer. 899 for (i, byte) in cap_data.bytes().iter().enumerate() { 900 self.write_byte_internal(cap_offset + i + 2, *byte, false); 901 } 902 self.last_capability = Some((cap_offset, total_len)); 903 904 match cap_data.id() { 905 PciCapabilityId::MessageSignalledInterrupts => { 906 self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK; 907 } 908 PciCapabilityId::MsiX => { 909 self.msix_cap_reg_idx = Some(cap_offset / 4); 910 self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK; 911 } 912 _ => {} 913 } 914 915 Ok(cap_offset) 916 } 917 918 // Find the next aligned offset after the one given. 919 fn next_dword(offset: usize, len: usize) -> usize { 920 let next = offset + len; 921 (next + 3) & !3 922 } 923 924 pub fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 925 if offset as usize + data.len() > 4 { 926 return; 927 } 928 929 // Handle potential write to MSI-X message control register 930 if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx { 931 if let Some(msix_config) = &self.msix_config { 932 if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 { 933 msix_config 934 .lock() 935 .unwrap() 936 .set_msg_ctl(LittleEndian::read_u16(data)); 937 } else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 { 938 msix_config 939 .lock() 940 .unwrap() 941 .set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16); 942 } 943 } 944 } 945 946 match data.len() { 947 1 => self.write_byte(reg_idx * 4 + offset as usize, data[0]), 948 2 => self.write_word( 949 reg_idx * 4 + offset as usize, 950 u16::from(data[0]) | u16::from(data[1]) << 8, 951 ), 952 4 => self.write_reg(reg_idx, LittleEndian::read_u32(data)), 953 _ => (), 954 } 955 } 956 957 pub fn read_config_register(&self, reg_idx: usize) -> u32 { 958 self.read_reg(reg_idx) 959 } 960 961 pub fn detect_bar_reprogramming( 962 &mut self, 963 reg_idx: usize, 964 data: &[u8], 965 ) -> Option<BarReprogrammingParams> { 966 if data.len() != 4 { 967 return None; 968 } 969 970 let value = LittleEndian::read_u32(data); 971 972 let mask = self.writable_bits[reg_idx]; 973 if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(®_idx) { 974 // Ignore the case where the BAR size is being asked for. 975 if value == 0xffff_ffff { 976 return None; 977 } 978 979 let bar_idx = reg_idx - 4; 980 // Handle special case where the address being written is 981 // different from the address initially provided. This is a 982 // BAR reprogramming case which needs to be properly caught. 983 if let Some(bar_type) = self.bars[bar_idx].r#type { 984 // In case of 64 bits memory BAR, we don't do anything until 985 // the upper BAR is modified, otherwise we would be moving the 986 // BAR to a wrong location in memory. 987 if bar_type == PciBarRegionType::Memory64BitRegion { 988 return None; 989 } 990 991 // Ignore the case where the value is unchanged. 992 if (value & mask) == (self.bars[bar_idx].addr & mask) { 993 return None; 994 } 995 996 info!( 997 "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}", 998 reg_idx, self.registers[reg_idx], value 999 ); 1000 let old_base = u64::from(self.bars[bar_idx].addr & mask); 1001 let new_base = u64::from(value & mask); 1002 let len = u64::from( 1003 decode_32_bits_bar_size(self.bars[bar_idx].size) 1004 .ok_or(Error::Decode32BarSize) 1005 .unwrap(), 1006 ); 1007 let region_type = bar_type; 1008 1009 self.bars[bar_idx].addr = value; 1010 1011 return Some(BarReprogrammingParams { 1012 old_base, 1013 new_base, 1014 len, 1015 region_type, 1016 }); 1017 } else if (reg_idx > BAR0_REG) 1018 && ((self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]) 1019 != (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]) 1020 || (value & mask) != (self.bars[bar_idx].addr & mask)) 1021 { 1022 info!( 1023 "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}", 1024 reg_idx, self.registers[reg_idx], value 1025 ); 1026 let old_base = u64::from(self.bars[bar_idx].addr & mask) << 32 1027 | u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]); 1028 let new_base = u64::from(value & mask) << 32 1029 | u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]); 1030 let len = 1031 decode_64_bits_bar_size(self.bars[bar_idx].size, self.bars[bar_idx - 1].size) 1032 .ok_or(Error::Decode64BarSize) 1033 .unwrap(); 1034 let region_type = PciBarRegionType::Memory64BitRegion; 1035 1036 self.bars[bar_idx].addr = value; 1037 self.bars[bar_idx - 1].addr = self.registers[reg_idx - 1]; 1038 1039 return Some(BarReprogrammingParams { 1040 old_base, 1041 new_base, 1042 len, 1043 region_type, 1044 }); 1045 } 1046 } else if reg_idx == ROM_BAR_REG && (value & mask) != (self.rom_bar_addr & mask) { 1047 // Ignore the case where the BAR size is being asked for. 1048 if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK { 1049 return None; 1050 } 1051 1052 info!( 1053 "Detected ROM BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}", 1054 reg_idx, self.registers[reg_idx], value 1055 ); 1056 let old_base = u64::from(self.rom_bar_addr & mask); 1057 let new_base = u64::from(value & mask); 1058 let len = u64::from( 1059 decode_32_bits_bar_size(self.rom_bar_size) 1060 .ok_or(Error::Decode32BarSize) 1061 .unwrap(), 1062 ); 1063 let region_type = PciBarRegionType::Memory32BitRegion; 1064 1065 self.rom_bar_addr = value; 1066 1067 return Some(BarReprogrammingParams { 1068 old_base, 1069 new_base, 1070 len, 1071 region_type, 1072 }); 1073 } 1074 1075 None 1076 } 1077 } 1078 1079 impl Pausable for PciConfiguration {} 1080 1081 impl Snapshottable for PciConfiguration { 1082 fn id(&self) -> String { 1083 String::from(PCI_CONFIGURATION_ID) 1084 } 1085 1086 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 1087 Snapshot::new_from_versioned_state(&self.id(), &self.state()) 1088 } 1089 1090 fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { 1091 self.set_state(&snapshot.to_versioned_state(&self.id())?); 1092 Ok(()) 1093 } 1094 } 1095 1096 impl Default for PciBarConfiguration { 1097 fn default() -> Self { 1098 PciBarConfiguration { 1099 idx: 0, 1100 addr: 0, 1101 size: 0, 1102 region_type: PciBarRegionType::Memory64BitRegion, 1103 prefetchable: PciBarPrefetchable::NotPrefetchable, 1104 } 1105 } 1106 } 1107 1108 impl PciBarConfiguration { 1109 pub fn new( 1110 idx: usize, 1111 size: u64, 1112 region_type: PciBarRegionType, 1113 prefetchable: PciBarPrefetchable, 1114 ) -> Self { 1115 PciBarConfiguration { 1116 idx, 1117 addr: 0, 1118 size, 1119 region_type, 1120 prefetchable, 1121 } 1122 } 1123 1124 #[must_use] 1125 pub fn set_index(mut self, idx: usize) -> Self { 1126 self.idx = idx; 1127 self 1128 } 1129 1130 #[must_use] 1131 pub fn set_address(mut self, addr: u64) -> Self { 1132 self.addr = addr; 1133 self 1134 } 1135 1136 #[must_use] 1137 pub fn set_size(mut self, size: u64) -> Self { 1138 self.size = size; 1139 self 1140 } 1141 1142 #[must_use] 1143 pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self { 1144 self.region_type = region_type; 1145 self 1146 } 1147 1148 #[must_use] 1149 pub fn set_prefetchable(mut self, prefetchable: PciBarPrefetchable) -> Self { 1150 self.prefetchable = prefetchable; 1151 self 1152 } 1153 1154 pub fn idx(&self) -> usize { 1155 self.idx 1156 } 1157 1158 pub fn addr(&self) -> u64 { 1159 self.addr 1160 } 1161 1162 pub fn size(&self) -> u64 { 1163 self.size 1164 } 1165 1166 pub fn region_type(&self) -> PciBarRegionType { 1167 self.region_type 1168 } 1169 1170 pub fn prefetchable(&self) -> PciBarPrefetchable { 1171 self.prefetchable 1172 } 1173 } 1174 1175 #[cfg(test)] 1176 mod tests { 1177 use vm_memory::ByteValued; 1178 1179 use super::*; 1180 1181 #[repr(packed)] 1182 #[derive(Clone, Copy, Default)] 1183 #[allow(dead_code)] 1184 struct TestCap { 1185 len: u8, 1186 foo: u8, 1187 } 1188 1189 // SAFETY: All members are simple numbers and any value is valid. 1190 unsafe impl ByteValued for TestCap {} 1191 1192 impl PciCapability for TestCap { 1193 fn bytes(&self) -> &[u8] { 1194 self.as_slice() 1195 } 1196 1197 fn id(&self) -> PciCapabilityId { 1198 PciCapabilityId::VendorSpecific 1199 } 1200 } 1201 1202 #[test] 1203 fn add_capability() { 1204 let mut cfg = PciConfiguration::new( 1205 0x1234, 1206 0x5678, 1207 0x1, 1208 PciClassCode::MultimediaController, 1209 &PciMultimediaSubclass::AudioController, 1210 None, 1211 PciHeaderType::Device, 1212 0xABCD, 1213 0x2468, 1214 None, 1215 None, 1216 ); 1217 1218 // Add two capabilities with different contents. 1219 let cap1 = TestCap { len: 4, foo: 0xAA }; 1220 let cap1_offset = cfg.add_capability(&cap1).unwrap(); 1221 assert_eq!(cap1_offset % 4, 0); 1222 1223 let cap2 = TestCap { 1224 len: 0x04, 1225 foo: 0x55, 1226 }; 1227 let cap2_offset = cfg.add_capability(&cap2).unwrap(); 1228 assert_eq!(cap2_offset % 4, 0); 1229 1230 // The capability list head should be pointing to cap1. 1231 let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF; 1232 assert_eq!(cap1_offset, cap_ptr as usize); 1233 1234 // Verify the contents of the capabilities. 1235 let cap1_data = cfg.read_reg(cap1_offset / 4); 1236 assert_eq!(cap1_data & 0xFF, 0x09); // capability ID 1237 assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer 1238 assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len 1239 assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo 1240 1241 let cap2_data = cfg.read_reg(cap2_offset / 4); 1242 assert_eq!(cap2_data & 0xFF, 0x09); // capability ID 1243 assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer 1244 assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len 1245 assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo 1246 } 1247 1248 #[derive(Copy, Clone)] 1249 enum TestPi { 1250 Test = 0x5a, 1251 } 1252 1253 impl PciProgrammingInterface for TestPi { 1254 fn get_register_value(&self) -> u8 { 1255 *self as u8 1256 } 1257 } 1258 1259 #[test] 1260 fn class_code() { 1261 let cfg = PciConfiguration::new( 1262 0x1234, 1263 0x5678, 1264 0x1, 1265 PciClassCode::MultimediaController, 1266 &PciMultimediaSubclass::AudioController, 1267 Some(&TestPi::Test), 1268 PciHeaderType::Device, 1269 0xABCD, 1270 0x2468, 1271 None, 1272 None, 1273 ); 1274 1275 let class_reg = cfg.read_reg(2); 1276 let class_code = (class_reg >> 24) & 0xFF; 1277 let subclass = (class_reg >> 16) & 0xFF; 1278 let prog_if = (class_reg >> 8) & 0xFF; 1279 assert_eq!(class_code, 0x04); 1280 assert_eq!(subclass, 0x01); 1281 assert_eq!(prog_if, 0x5a); 1282 } 1283 } 1284