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 impl From<PciBarRegionType> for PciBarType { 456 fn from(val: PciBarRegionType) -> Self { 457 match val { 458 PciBarRegionType::IoRegion => PciBarType::Io, 459 PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32, 460 PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64, 461 } 462 } 463 } 464 465 #[derive(Copy, Clone)] 466 pub enum PciBarPrefetchable { 467 NotPrefetchable = 0, 468 Prefetchable = 0x08, 469 } 470 471 impl From<PciBarPrefetchable> for bool { 472 fn from(val: PciBarPrefetchable) -> Self { 473 match val { 474 PciBarPrefetchable::NotPrefetchable => false, 475 PciBarPrefetchable::Prefetchable => true, 476 } 477 } 478 } 479 480 #[derive(Copy, Clone)] 481 pub struct PciBarConfiguration { 482 addr: u64, 483 size: u64, 484 idx: usize, 485 region_type: PciBarRegionType, 486 prefetchable: PciBarPrefetchable, 487 } 488 489 #[derive(Debug)] 490 pub enum Error { 491 BarAddressInvalid(u64, u64), 492 BarInUse(usize), 493 BarInUse64(usize), 494 BarInvalid(usize), 495 BarInvalid64(usize), 496 BarSizeInvalid(u64), 497 CapabilityEmpty, 498 CapabilityLengthInvalid(usize), 499 CapabilitySpaceFull(usize), 500 Decode32BarSize, 501 Decode64BarSize, 502 Encode32BarSize, 503 Encode64BarSize, 504 RomBarAddressInvalid(u64, u64), 505 RomBarInUse(usize), 506 RomBarInvalid(usize), 507 RomBarSizeInvalid(u64), 508 } 509 pub type Result<T> = std::result::Result<T, Error>; 510 511 impl std::error::Error for Error {} 512 513 impl Display for Error { 514 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 515 use self::Error::*; 516 match self { 517 BarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"), 518 BarInUse(b) => write!(f, "bar {b} already used"), 519 BarInUse64(b) => write!(f, "64bit bar {b} already used(requires two regs)"), 520 BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1), 521 BarInvalid64(b) => write!( 522 f, 523 "64bitbar {} invalid, requires two regs, max {}", 524 b, 525 NUM_BAR_REGS - 1 526 ), 527 BarSizeInvalid(s) => write!(f, "bar address {s} not a power of two"), 528 CapabilityEmpty => write!(f, "empty capabilities are invalid"), 529 CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {l}"), 530 CapabilitySpaceFull(s) => write!(f, "capability of size {s} doesn't fit"), 531 Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"), 532 Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"), 533 Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"), 534 Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"), 535 RomBarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"), 536 RomBarInUse(b) => write!(f, "rom bar {b} already used"), 537 RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1), 538 RomBarSizeInvalid(s) => write!(f, "rom bar address {s} not a power of two"), 539 } 540 } 541 } 542 543 impl PciConfiguration { 544 #[allow(clippy::too_many_arguments)] 545 pub fn new( 546 vendor_id: u16, 547 device_id: u16, 548 revision_id: u8, 549 class_code: PciClassCode, 550 subclass: &dyn PciSubclass, 551 programming_interface: Option<&dyn PciProgrammingInterface>, 552 header_type: PciHeaderType, 553 subsystem_vendor_id: u16, 554 subsystem_id: u16, 555 msix_config: Option<Arc<Mutex<MsixConfig>>>, 556 state: Option<PciConfigurationState>, 557 ) -> Self { 558 let ( 559 registers, 560 writable_bits, 561 bars, 562 rom_bar_addr, 563 rom_bar_size, 564 rom_bar_used, 565 last_capability, 566 msix_cap_reg_idx, 567 ) = if let Some(state) = state { 568 ( 569 state.registers.try_into().unwrap(), 570 state.writable_bits.try_into().unwrap(), 571 state.bars.try_into().unwrap(), 572 state.rom_bar_addr, 573 state.rom_bar_size, 574 state.rom_bar_used, 575 state.last_capability, 576 state.msix_cap_reg_idx, 577 ) 578 } else { 579 let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS]; 580 let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS]; 581 registers[0] = u32::from(device_id) << 16 | u32::from(vendor_id); 582 // TODO(dverkamp): Status should be write-1-to-clear 583 writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w) 584 let pi = if let Some(pi) = programming_interface { 585 pi.get_register_value() 586 } else { 587 0 588 }; 589 registers[2] = u32::from(class_code.get_register_value()) << 24 590 | u32::from(subclass.get_register_value()) << 16 591 | u32::from(pi) << 8 592 | u32::from(revision_id); 593 writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w) 594 match header_type { 595 PciHeaderType::Device => { 596 registers[3] = 0x0000_0000; // Header type 0 (device) 597 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w) 598 } 599 PciHeaderType::Bridge => { 600 registers[3] = 0x0001_0000; // Header type 1 (bridge) 601 writable_bits[9] = 0xfff0_fff0; // Memory base and limit 602 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w) 603 } 604 }; 605 registers[11] = u32::from(subsystem_id) << 16 | u32::from(subsystem_vendor_id); 606 607 ( 608 registers, 609 writable_bits, 610 [PciBar::default(); NUM_BAR_REGS], 611 0, 612 0, 613 false, 614 None, 615 None, 616 ) 617 }; 618 619 PciConfiguration { 620 registers, 621 writable_bits, 622 bars, 623 rom_bar_addr, 624 rom_bar_size, 625 rom_bar_used, 626 last_capability, 627 msix_cap_reg_idx, 628 msix_config, 629 } 630 } 631 632 fn state(&self) -> PciConfigurationState { 633 PciConfigurationState { 634 registers: self.registers.to_vec(), 635 writable_bits: self.writable_bits.to_vec(), 636 bars: self.bars.to_vec(), 637 rom_bar_addr: self.rom_bar_addr, 638 rom_bar_size: self.rom_bar_size, 639 rom_bar_used: self.rom_bar_used, 640 last_capability: self.last_capability, 641 msix_cap_reg_idx: self.msix_cap_reg_idx, 642 } 643 } 644 645 /// Reads a 32bit register from `reg_idx` in the register map. 646 pub fn read_reg(&self, reg_idx: usize) -> u32 { 647 *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff)) 648 } 649 650 /// Writes a 32bit register to `reg_idx` in the register map. 651 pub fn write_reg(&mut self, reg_idx: usize, value: u32) { 652 let mut mask = self.writable_bits[reg_idx]; 653 654 if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(®_idx) { 655 // Handle very specific case where the BAR is being written with 656 // all 1's to retrieve the BAR size during next BAR reading. 657 if value == 0xffff_ffff { 658 mask &= self.bars[reg_idx - 4].size; 659 } 660 } else if reg_idx == ROM_BAR_REG { 661 // Handle very specific case where the BAR is being written with 662 // all 1's on bits 31-11 to retrieve the BAR size during next BAR 663 // reading. 664 if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK { 665 mask &= self.rom_bar_size; 666 } 667 } 668 669 if let Some(r) = self.registers.get_mut(reg_idx) { 670 *r = (*r & !self.writable_bits[reg_idx]) | (value & mask); 671 } else { 672 warn!("bad PCI register write {}", reg_idx); 673 } 674 } 675 676 /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned. 677 pub fn write_word(&mut self, offset: usize, value: u16) { 678 let shift = match offset % 4 { 679 0 => 0, 680 2 => 16, 681 _ => { 682 warn!("bad PCI config write offset {}", offset); 683 return; 684 } 685 }; 686 let reg_idx = offset / 4; 687 688 if let Some(r) = self.registers.get_mut(reg_idx) { 689 let writable_mask = self.writable_bits[reg_idx]; 690 let mask = (0xffffu32 << shift) & writable_mask; 691 let shifted_value = (u32::from(value) << shift) & writable_mask; 692 *r = *r & !mask | shifted_value; 693 } else { 694 warn!("bad PCI config write offset {}", offset); 695 } 696 } 697 698 /// Writes a byte to `offset`. 699 pub fn write_byte(&mut self, offset: usize, value: u8) { 700 self.write_byte_internal(offset, value, true); 701 } 702 703 /// Writes a byte to `offset`, optionally enforcing read-only bits. 704 fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) { 705 let shift = (offset % 4) * 8; 706 let reg_idx = offset / 4; 707 708 if let Some(r) = self.registers.get_mut(reg_idx) { 709 let writable_mask = if apply_writable_mask { 710 self.writable_bits[reg_idx] 711 } else { 712 0xffff_ffff 713 }; 714 let mask = (0xffu32 << shift) & writable_mask; 715 let shifted_value = (u32::from(value) << shift) & writable_mask; 716 *r = *r & !mask | shifted_value; 717 } else { 718 warn!("bad PCI config write offset {}", offset); 719 } 720 } 721 722 /// Adds a region specified by `config`. Configures the specified BAR(s) to 723 /// report this region and size to the guest kernel. Enforces a few constraints 724 /// (i.e, region size must be power of two, register not already used). 725 pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> { 726 let bar_idx = config.idx; 727 let reg_idx = BAR0_REG + bar_idx; 728 729 if self.bars[bar_idx].used { 730 return Err(Error::BarInUse(bar_idx)); 731 } 732 733 if config.size.count_ones() != 1 { 734 return Err(Error::BarSizeInvalid(config.size)); 735 } 736 737 if bar_idx >= NUM_BAR_REGS { 738 return Err(Error::BarInvalid(bar_idx)); 739 } 740 741 let end_addr = config 742 .addr 743 .checked_add(config.size - 1) 744 .ok_or(Error::BarAddressInvalid(config.addr, config.size))?; 745 match config.region_type { 746 PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => { 747 if end_addr > u64::from(u32::max_value()) { 748 return Err(Error::BarAddressInvalid(config.addr, config.size)); 749 } 750 751 // Encode the BAR size as expected by the software running in 752 // the guest. 753 self.bars[bar_idx].size = 754 encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?; 755 } 756 PciBarRegionType::Memory64BitRegion => { 757 if bar_idx + 1 >= NUM_BAR_REGS { 758 return Err(Error::BarInvalid64(bar_idx)); 759 } 760 761 if end_addr > u64::max_value() { 762 return Err(Error::BarAddressInvalid(config.addr, config.size)); 763 } 764 765 if self.bars[bar_idx + 1].used { 766 return Err(Error::BarInUse64(bar_idx)); 767 } 768 769 // Encode the BAR size as expected by the software running in 770 // the guest. 771 let (bar_size_hi, bar_size_lo) = 772 encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?; 773 774 self.registers[reg_idx + 1] = (config.addr >> 32) as u32; 775 self.writable_bits[reg_idx + 1] = 0xffff_ffff; 776 self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1]; 777 self.bars[bar_idx].size = bar_size_lo; 778 self.bars[bar_idx + 1].size = bar_size_hi; 779 self.bars[bar_idx + 1].used = true; 780 } 781 } 782 783 let (mask, lower_bits) = match config.region_type { 784 PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => ( 785 BAR_MEM_ADDR_MASK, 786 config.prefetchable as u32 | config.region_type as u32, 787 ), 788 PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32), 789 }; 790 791 self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits; 792 self.writable_bits[reg_idx] = mask; 793 self.bars[bar_idx].addr = self.registers[reg_idx]; 794 self.bars[bar_idx].used = true; 795 self.bars[bar_idx].r#type = Some(config.region_type); 796 797 Ok(()) 798 } 799 800 /// Adds rom expansion BAR. 801 pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()> { 802 let bar_idx = config.idx; 803 let reg_idx = ROM_BAR_REG; 804 805 if self.rom_bar_used { 806 return Err(Error::RomBarInUse(bar_idx)); 807 } 808 809 if config.size.count_ones() != 1 { 810 return Err(Error::RomBarSizeInvalid(config.size)); 811 } 812 813 if bar_idx != ROM_BAR_IDX { 814 return Err(Error::RomBarInvalid(bar_idx)); 815 } 816 817 let end_addr = config 818 .addr 819 .checked_add(config.size - 1) 820 .ok_or(Error::RomBarAddressInvalid(config.addr, config.size))?; 821 822 if end_addr > u64::from(u32::max_value()) { 823 return Err(Error::RomBarAddressInvalid(config.addr, config.size)); 824 } 825 826 self.registers[reg_idx] = (config.addr as u32) | active; 827 self.writable_bits[reg_idx] = ROM_BAR_ADDR_MASK; 828 self.rom_bar_addr = self.registers[reg_idx]; 829 self.rom_bar_size = 830 encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?; 831 self.rom_bar_used = true; 832 833 Ok(()) 834 } 835 836 /// Returns the address of the given BAR region. 837 pub fn get_bar_addr(&self, bar_num: usize) -> u64 { 838 let bar_idx = BAR0_REG + bar_num; 839 840 let mut addr = u64::from(self.bars[bar_num].addr & self.writable_bits[bar_idx]); 841 842 if let Some(bar_type) = self.bars[bar_num].r#type { 843 if bar_type == PciBarRegionType::Memory64BitRegion { 844 addr |= u64::from(self.bars[bar_num + 1].addr) << 32; 845 } 846 } 847 848 addr 849 } 850 851 /// Configures the IRQ line and pin used by this device. 852 pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) { 853 // `pin` is 1-based in the pci config space. 854 let pin_idx = (pin as u32) + 1; 855 self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG] 856 & 0xffff_0000) 857 | (pin_idx << 8) 858 | u32::from(line); 859 } 860 861 /// Adds the capability `cap_data` to the list of capabilities. 862 /// `cap_data` should include the two-byte PCI capability header (type, next), 863 /// but not populate it. Correct values will be generated automatically based 864 /// on `cap_data.id()`. 865 pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> { 866 let total_len = cap_data.bytes().len(); 867 // Check that the length is valid. 868 if cap_data.bytes().is_empty() { 869 return Err(Error::CapabilityEmpty); 870 } 871 let (cap_offset, tail_offset) = match self.last_capability { 872 Some((offset, len)) => (Self::next_dword(offset, len), offset + 1), 873 None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET), 874 }; 875 let end_offset = cap_offset 876 .checked_add(total_len) 877 .ok_or(Error::CapabilitySpaceFull(total_len))?; 878 if end_offset > CAPABILITY_MAX_OFFSET { 879 return Err(Error::CapabilitySpaceFull(total_len)); 880 } 881 self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK; 882 self.write_byte_internal(tail_offset, cap_offset as u8, false); 883 self.write_byte_internal(cap_offset, cap_data.id() as u8, false); 884 self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer. 885 for (i, byte) in cap_data.bytes().iter().enumerate() { 886 self.write_byte_internal(cap_offset + i + 2, *byte, false); 887 } 888 self.last_capability = Some((cap_offset, total_len)); 889 890 match cap_data.id() { 891 PciCapabilityId::MessageSignalledInterrupts => { 892 self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK; 893 } 894 PciCapabilityId::MsiX => { 895 self.msix_cap_reg_idx = Some(cap_offset / 4); 896 self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK; 897 } 898 _ => {} 899 } 900 901 Ok(cap_offset) 902 } 903 904 // Find the next aligned offset after the one given. 905 fn next_dword(offset: usize, len: usize) -> usize { 906 let next = offset + len; 907 (next + 3) & !3 908 } 909 910 pub fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 911 if offset as usize + data.len() > 4 { 912 return; 913 } 914 915 // Handle potential write to MSI-X message control register 916 if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx { 917 if let Some(msix_config) = &self.msix_config { 918 if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 { 919 msix_config 920 .lock() 921 .unwrap() 922 .set_msg_ctl(LittleEndian::read_u16(data)); 923 } else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 { 924 msix_config 925 .lock() 926 .unwrap() 927 .set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16); 928 } 929 } 930 } 931 932 match data.len() { 933 1 => self.write_byte(reg_idx * 4 + offset as usize, data[0]), 934 2 => self.write_word( 935 reg_idx * 4 + offset as usize, 936 u16::from(data[0]) | u16::from(data[1]) << 8, 937 ), 938 4 => self.write_reg(reg_idx, LittleEndian::read_u32(data)), 939 _ => (), 940 } 941 } 942 943 pub fn read_config_register(&self, reg_idx: usize) -> u32 { 944 self.read_reg(reg_idx) 945 } 946 947 pub fn detect_bar_reprogramming( 948 &mut self, 949 reg_idx: usize, 950 data: &[u8], 951 ) -> Option<BarReprogrammingParams> { 952 if data.len() != 4 { 953 return None; 954 } 955 956 let value = LittleEndian::read_u32(data); 957 958 let mask = self.writable_bits[reg_idx]; 959 if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(®_idx) { 960 // Ignore the case where the BAR size is being asked for. 961 if value == 0xffff_ffff { 962 return None; 963 } 964 965 let bar_idx = reg_idx - 4; 966 // Handle special case where the address being written is 967 // different from the address initially provided. This is a 968 // BAR reprogramming case which needs to be properly caught. 969 if let Some(bar_type) = self.bars[bar_idx].r#type { 970 // In case of 64 bits memory BAR, we don't do anything until 971 // the upper BAR is modified, otherwise we would be moving the 972 // BAR to a wrong location in memory. 973 if bar_type == PciBarRegionType::Memory64BitRegion { 974 return None; 975 } 976 977 // Ignore the case where the value is unchanged. 978 if (value & mask) == (self.bars[bar_idx].addr & mask) { 979 return None; 980 } 981 982 info!( 983 "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}", 984 reg_idx, self.registers[reg_idx], value 985 ); 986 let old_base = u64::from(self.bars[bar_idx].addr & mask); 987 let new_base = u64::from(value & mask); 988 let len = u64::from( 989 decode_32_bits_bar_size(self.bars[bar_idx].size) 990 .ok_or(Error::Decode32BarSize) 991 .unwrap(), 992 ); 993 let region_type = bar_type; 994 995 self.bars[bar_idx].addr = value; 996 997 return Some(BarReprogrammingParams { 998 old_base, 999 new_base, 1000 len, 1001 region_type, 1002 }); 1003 } else if (reg_idx > BAR0_REG) 1004 && ((self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]) 1005 != (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]) 1006 || (value & mask) != (self.bars[bar_idx].addr & mask)) 1007 { 1008 info!( 1009 "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}", 1010 reg_idx, self.registers[reg_idx], value 1011 ); 1012 let old_base = u64::from(self.bars[bar_idx].addr & mask) << 32 1013 | u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]); 1014 let new_base = u64::from(value & mask) << 32 1015 | u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]); 1016 let len = 1017 decode_64_bits_bar_size(self.bars[bar_idx].size, self.bars[bar_idx - 1].size) 1018 .ok_or(Error::Decode64BarSize) 1019 .unwrap(); 1020 let region_type = PciBarRegionType::Memory64BitRegion; 1021 1022 self.bars[bar_idx].addr = value; 1023 self.bars[bar_idx - 1].addr = self.registers[reg_idx - 1]; 1024 1025 return Some(BarReprogrammingParams { 1026 old_base, 1027 new_base, 1028 len, 1029 region_type, 1030 }); 1031 } 1032 } else if reg_idx == ROM_BAR_REG && (value & mask) != (self.rom_bar_addr & mask) { 1033 // Ignore the case where the BAR size is being asked for. 1034 if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK { 1035 return None; 1036 } 1037 1038 info!( 1039 "Detected ROM BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}", 1040 reg_idx, self.registers[reg_idx], value 1041 ); 1042 let old_base = u64::from(self.rom_bar_addr & mask); 1043 let new_base = u64::from(value & mask); 1044 let len = u64::from( 1045 decode_32_bits_bar_size(self.rom_bar_size) 1046 .ok_or(Error::Decode32BarSize) 1047 .unwrap(), 1048 ); 1049 let region_type = PciBarRegionType::Memory32BitRegion; 1050 1051 self.rom_bar_addr = value; 1052 1053 return Some(BarReprogrammingParams { 1054 old_base, 1055 new_base, 1056 len, 1057 region_type, 1058 }); 1059 } 1060 1061 None 1062 } 1063 } 1064 1065 impl Pausable for PciConfiguration {} 1066 1067 impl Snapshottable for PciConfiguration { 1068 fn id(&self) -> String { 1069 String::from(PCI_CONFIGURATION_ID) 1070 } 1071 1072 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 1073 Snapshot::new_from_versioned_state(&self.state()) 1074 } 1075 } 1076 1077 impl Default for PciBarConfiguration { 1078 fn default() -> Self { 1079 PciBarConfiguration { 1080 idx: 0, 1081 addr: 0, 1082 size: 0, 1083 region_type: PciBarRegionType::Memory64BitRegion, 1084 prefetchable: PciBarPrefetchable::NotPrefetchable, 1085 } 1086 } 1087 } 1088 1089 impl PciBarConfiguration { 1090 pub fn new( 1091 idx: usize, 1092 size: u64, 1093 region_type: PciBarRegionType, 1094 prefetchable: PciBarPrefetchable, 1095 ) -> Self { 1096 PciBarConfiguration { 1097 idx, 1098 addr: 0, 1099 size, 1100 region_type, 1101 prefetchable, 1102 } 1103 } 1104 1105 #[must_use] 1106 pub fn set_index(mut self, idx: usize) -> Self { 1107 self.idx = idx; 1108 self 1109 } 1110 1111 #[must_use] 1112 pub fn set_address(mut self, addr: u64) -> Self { 1113 self.addr = addr; 1114 self 1115 } 1116 1117 #[must_use] 1118 pub fn set_size(mut self, size: u64) -> Self { 1119 self.size = size; 1120 self 1121 } 1122 1123 #[must_use] 1124 pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self { 1125 self.region_type = region_type; 1126 self 1127 } 1128 1129 #[must_use] 1130 pub fn set_prefetchable(mut self, prefetchable: PciBarPrefetchable) -> Self { 1131 self.prefetchable = prefetchable; 1132 self 1133 } 1134 1135 pub fn idx(&self) -> usize { 1136 self.idx 1137 } 1138 1139 pub fn addr(&self) -> u64 { 1140 self.addr 1141 } 1142 1143 pub fn size(&self) -> u64 { 1144 self.size 1145 } 1146 1147 pub fn region_type(&self) -> PciBarRegionType { 1148 self.region_type 1149 } 1150 1151 pub fn prefetchable(&self) -> PciBarPrefetchable { 1152 self.prefetchable 1153 } 1154 } 1155 1156 #[cfg(test)] 1157 mod tests { 1158 use vm_memory::ByteValued; 1159 1160 use super::*; 1161 1162 #[repr(packed)] 1163 #[derive(Clone, Copy, Default)] 1164 #[allow(dead_code)] 1165 struct TestCap { 1166 len: u8, 1167 foo: u8, 1168 } 1169 1170 // SAFETY: All members are simple numbers and any value is valid. 1171 unsafe impl ByteValued for TestCap {} 1172 1173 impl PciCapability for TestCap { 1174 fn bytes(&self) -> &[u8] { 1175 self.as_slice() 1176 } 1177 1178 fn id(&self) -> PciCapabilityId { 1179 PciCapabilityId::VendorSpecific 1180 } 1181 } 1182 1183 #[test] 1184 fn add_capability() { 1185 let mut cfg = PciConfiguration::new( 1186 0x1234, 1187 0x5678, 1188 0x1, 1189 PciClassCode::MultimediaController, 1190 &PciMultimediaSubclass::AudioController, 1191 None, 1192 PciHeaderType::Device, 1193 0xABCD, 1194 0x2468, 1195 None, 1196 None, 1197 ); 1198 1199 // Add two capabilities with different contents. 1200 let cap1 = TestCap { len: 4, foo: 0xAA }; 1201 let cap1_offset = cfg.add_capability(&cap1).unwrap(); 1202 assert_eq!(cap1_offset % 4, 0); 1203 1204 let cap2 = TestCap { 1205 len: 0x04, 1206 foo: 0x55, 1207 }; 1208 let cap2_offset = cfg.add_capability(&cap2).unwrap(); 1209 assert_eq!(cap2_offset % 4, 0); 1210 1211 // The capability list head should be pointing to cap1. 1212 let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF; 1213 assert_eq!(cap1_offset, cap_ptr as usize); 1214 1215 // Verify the contents of the capabilities. 1216 let cap1_data = cfg.read_reg(cap1_offset / 4); 1217 assert_eq!(cap1_data & 0xFF, 0x09); // capability ID 1218 assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer 1219 assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len 1220 assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo 1221 1222 let cap2_data = cfg.read_reg(cap2_offset / 4); 1223 assert_eq!(cap2_data & 0xFF, 0x09); // capability ID 1224 assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer 1225 assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len 1226 assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo 1227 } 1228 1229 #[derive(Copy, Clone)] 1230 enum TestPi { 1231 Test = 0x5a, 1232 } 1233 1234 impl PciProgrammingInterface for TestPi { 1235 fn get_register_value(&self) -> u8 { 1236 *self as u8 1237 } 1238 } 1239 1240 #[test] 1241 fn class_code() { 1242 let cfg = PciConfiguration::new( 1243 0x1234, 1244 0x5678, 1245 0x1, 1246 PciClassCode::MultimediaController, 1247 &PciMultimediaSubclass::AudioController, 1248 Some(&TestPi::Test), 1249 PciHeaderType::Device, 1250 0xABCD, 1251 0x2468, 1252 None, 1253 None, 1254 ); 1255 1256 let class_reg = cfg.read_reg(2); 1257 let class_code = (class_reg >> 24) & 0xFF; 1258 let subclass = (class_reg >> 16) & 0xFF; 1259 let prog_if = (class_reg >> 8) & 0xFF; 1260 assert_eq!(class_code, 0x04); 1261 assert_eq!(subclass, 0x01); 1262 assert_eq!(prog_if, 0x5a); 1263 } 1264 } 1265