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 // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause 6 7 use std::fmt::{self, Display}; 8 use std::sync::{Arc, Mutex}; 9 10 use byteorder::{ByteOrder, LittleEndian}; 11 use serde::{Deserialize, Serialize}; 12 use vm_device::PciBarType; 13 use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable}; 14 15 use crate::device::BarReprogrammingParams; 16 use crate::{MsixConfig, PciInterruptPin}; 17 18 // The number of 32bit registers in the config space, 4096 bytes. 19 const NUM_CONFIGURATION_REGISTERS: usize = 1024; 20 21 const STATUS_REG: usize = 1; 22 const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000; 23 const BAR0_REG: usize = 4; 24 const ROM_BAR_REG: usize = 12; 25 const ROM_BAR_IDX: usize = 6; 26 const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc; 27 const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0; 28 const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800; 29 const MSI_CAPABILITY_REGISTER_MASK: u32 = 0x0071_0000; 30 const MSIX_CAPABILITY_REGISTER_MASK: u32 = 0xc000_0000; 31 const NUM_BAR_REGS: usize = 6; 32 const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34; 33 const FIRST_CAPABILITY_OFFSET: usize = 0x40; 34 const CAPABILITY_MAX_OFFSET: usize = 192; 35 36 const INTERRUPT_LINE_PIN_REG: usize = 15; 37 38 pub const PCI_CONFIGURATION_ID: &str = "pci_configuration"; 39 40 /// Represents the types of PCI headers allowed in the configuration registers. 41 #[derive(Copy, Clone)] 42 pub enum PciHeaderType { 43 Device, 44 Bridge, 45 } 46 47 /// Classes of PCI nodes. 48 #[allow(dead_code)] 49 #[derive(Copy, Clone)] 50 pub enum PciClassCode { 51 TooOld, 52 MassStorage, 53 NetworkController, 54 DisplayController, 55 MultimediaController, 56 MemoryController, 57 BridgeDevice, 58 SimpleCommunicationController, 59 BaseSystemPeripheral, 60 InputDevice, 61 DockingStation, 62 Processor, 63 SerialBusController, 64 WirelessController, 65 IntelligentIoController, 66 EncryptionController, 67 DataAcquisitionSignalProcessing, 68 Other = 0xff, 69 } 70 71 impl PciClassCode { 72 pub fn get_register_value(self) -> u8 { 73 self as u8 74 } 75 } 76 77 /// A PCI subclass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait 78 /// is implemented by each subclass. It allows use of a trait object to generate configurations. 79 pub trait PciSubclass { 80 /// Convert this subclass to the value used in the PCI specification. 81 fn get_register_value(&self) -> u8; 82 } 83 84 /// Subclasses of the MultimediaController class. 85 #[allow(dead_code)] 86 #[derive(Copy, Clone)] 87 pub enum PciMultimediaSubclass { 88 VideoController = 0x00, 89 AudioController = 0x01, 90 TelephonyDevice = 0x02, 91 AudioDevice = 0x03, 92 Other = 0x80, 93 } 94 95 impl PciSubclass for PciMultimediaSubclass { 96 fn get_register_value(&self) -> u8 { 97 *self as u8 98 } 99 } 100 101 /// Subclasses of the BridgeDevice 102 #[allow(dead_code)] 103 #[derive(Copy, Clone)] 104 pub enum PciBridgeSubclass { 105 HostBridge = 0x00, 106 IsaBridge = 0x01, 107 EisaBridge = 0x02, 108 McaBridge = 0x03, 109 PciToPciBridge = 0x04, 110 PcmciaBridge = 0x05, 111 NuBusBridge = 0x06, 112 CardBusBridge = 0x07, 113 RacEwayBridge = 0x08, 114 PciToPciSemiTransparentBridge = 0x09, 115 InfiniBrandToPciHostBridge = 0x0a, 116 OtherBridgeDevice = 0x80, 117 } 118 119 impl PciSubclass for PciBridgeSubclass { 120 fn get_register_value(&self) -> u8 { 121 *self as u8 122 } 123 } 124 125 /// Subclass of the SerialBus 126 #[allow(dead_code)] 127 #[derive(Copy, Clone)] 128 pub enum PciSerialBusSubClass { 129 Firewire = 0x00, 130 Accessbus = 0x01, 131 Ssa = 0x02, 132 Usb = 0x03, 133 } 134 135 impl PciSubclass for PciSerialBusSubClass { 136 fn get_register_value(&self) -> u8 { 137 *self as u8 138 } 139 } 140 141 /// Mass Storage Sub Classes 142 #[allow(dead_code)] 143 #[derive(Copy, Clone)] 144 pub enum PciMassStorageSubclass { 145 ScsiStorage = 0x00, 146 IdeInterface = 0x01, 147 FloppyController = 0x02, 148 IpiController = 0x03, 149 RaidController = 0x04, 150 AtaController = 0x05, 151 SataController = 0x06, 152 SerialScsiController = 0x07, 153 NvmController = 0x08, 154 MassStorage = 0x80, 155 } 156 157 impl PciSubclass for PciMassStorageSubclass { 158 fn get_register_value(&self) -> u8 { 159 *self as u8 160 } 161 } 162 163 /// Network Controller Sub Classes 164 #[allow(dead_code)] 165 #[derive(Copy, Clone)] 166 pub enum PciNetworkControllerSubclass { 167 EthernetController = 0x00, 168 TokenRingController = 0x01, 169 FddiController = 0x02, 170 AtmController = 0x03, 171 IsdnController = 0x04, 172 WorldFipController = 0x05, 173 PicmgController = 0x06, 174 InfinibandController = 0x07, 175 FabricController = 0x08, 176 NetworkController = 0x80, 177 } 178 179 impl PciSubclass for PciNetworkControllerSubclass { 180 fn get_register_value(&self) -> u8 { 181 *self as u8 182 } 183 } 184 185 /// Trait to define a PCI class programming interface 186 /// 187 /// Each combination of `PciClassCode` and `PciSubclass` can specify a 188 /// set of register-level programming interfaces. 189 /// This trait is implemented by each programming interface. 190 /// It allows use of a trait object to generate configurations. 191 pub trait PciProgrammingInterface { 192 /// Convert this programming interface to the value used in the PCI specification. 193 fn get_register_value(&self) -> u8; 194 } 195 196 /// Types of PCI capabilities. 197 #[derive(PartialEq, Eq, Copy, Clone)] 198 #[allow(dead_code)] 199 #[allow(non_camel_case_types)] 200 #[repr(u8)] 201 pub enum PciCapabilityId { 202 ListId = 0, 203 PowerManagement = 0x01, 204 AcceleratedGraphicsPort = 0x02, 205 VitalProductData = 0x03, 206 SlotIdentification = 0x04, 207 MessageSignalledInterrupts = 0x05, 208 CompactPciHotSwap = 0x06, 209 PciX = 0x07, 210 HyperTransport = 0x08, 211 VendorSpecific = 0x09, 212 Debugport = 0x0A, 213 CompactPciCentralResourceControl = 0x0B, 214 PciStandardHotPlugController = 0x0C, 215 BridgeSubsystemVendorDeviceId = 0x0D, 216 AgpTargetPciPcibridge = 0x0E, 217 SecureDevice = 0x0F, 218 PciExpress = 0x10, 219 MsiX = 0x11, 220 SataDataIndexConf = 0x12, 221 PciAdvancedFeatures = 0x13, 222 PciEnhancedAllocation = 0x14, 223 } 224 225 impl From<u8> for PciCapabilityId { 226 fn from(c: u8) -> Self { 227 match c { 228 0 => PciCapabilityId::ListId, 229 0x01 => PciCapabilityId::PowerManagement, 230 0x02 => PciCapabilityId::AcceleratedGraphicsPort, 231 0x03 => PciCapabilityId::VitalProductData, 232 0x04 => PciCapabilityId::SlotIdentification, 233 0x05 => PciCapabilityId::MessageSignalledInterrupts, 234 0x06 => PciCapabilityId::CompactPciHotSwap, 235 0x07 => PciCapabilityId::PciX, 236 0x08 => PciCapabilityId::HyperTransport, 237 0x09 => PciCapabilityId::VendorSpecific, 238 0x0A => PciCapabilityId::Debugport, 239 0x0B => PciCapabilityId::CompactPciCentralResourceControl, 240 0x0C => PciCapabilityId::PciStandardHotPlugController, 241 0x0D => PciCapabilityId::BridgeSubsystemVendorDeviceId, 242 0x0E => PciCapabilityId::AgpTargetPciPcibridge, 243 0x0F => PciCapabilityId::SecureDevice, 244 0x10 => PciCapabilityId::PciExpress, 245 0x11 => PciCapabilityId::MsiX, 246 0x12 => PciCapabilityId::SataDataIndexConf, 247 0x13 => PciCapabilityId::PciAdvancedFeatures, 248 0x14 => PciCapabilityId::PciEnhancedAllocation, 249 _ => PciCapabilityId::ListId, 250 } 251 } 252 } 253 254 /// Types of PCI Express capabilities. 255 #[derive(PartialEq, Eq, Copy, Clone, Debug)] 256 #[allow(dead_code)] 257 #[repr(u16)] 258 pub enum PciExpressCapabilityId { 259 NullCapability = 0x0000, 260 AdvancedErrorReporting = 0x0001, 261 VirtualChannelMultiFunctionVirtualChannelNotPresent = 0x0002, 262 DeviceSerialNumber = 0x0003, 263 PowerBudgeting = 0x0004, 264 RootComplexLinkDeclaration = 0x0005, 265 RootComplexInternalLinkControl = 0x0006, 266 RootComplexEventCollectorEndpointAssociation = 0x0007, 267 MultiFunctionVirtualChannel = 0x0008, 268 VirtualChannelMultiFunctionVirtualChannelPresent = 0x0009, 269 RootComplexRegisterBlock = 0x000a, 270 VendorSpecificExtendedCapability = 0x000b, 271 ConfigurationAccessCorrelation = 0x000c, 272 AccessControlServices = 0x000d, 273 AlternativeRoutingIdentificationInterpretation = 0x000e, 274 AddressTranslationServices = 0x000f, 275 SingleRootIoVirtualization = 0x0010, 276 DeprecatedMultiRootIoVirtualization = 0x0011, 277 Multicast = 0x0012, 278 PageRequestInterface = 0x0013, 279 ReservedForAmd = 0x0014, 280 ResizeableBar = 0x0015, 281 DynamicPowerAllocation = 0x0016, 282 ThpRequester = 0x0017, 283 LatencyToleranceReporting = 0x0018, 284 SecondaryPciExpress = 0x0019, 285 ProtocolMultiplexing = 0x001a, 286 ProcessAddressSpaceId = 0x001b, 287 LnRequester = 0x001c, 288 DownstreamPortContainment = 0x001d, 289 L1PmSubstates = 0x001e, 290 PrecisionTimeMeasurement = 0x001f, 291 PciExpressOverMphy = 0x0020, 292 FRSQueueing = 0x0021, 293 ReadinessTimeReporting = 0x0022, 294 DesignatedVendorSpecificExtendedCapability = 0x0023, 295 VfResizeableBar = 0x0024, 296 DataLinkFeature = 0x0025, 297 PhysicalLayerSixteenGts = 0x0026, 298 LaneMarginingAtTheReceiver = 0x0027, 299 HierarchyId = 0x0028, 300 NativePcieEnclosureManagement = 0x0029, 301 PhysicalLayerThirtyTwoGts = 0x002a, 302 AlternateProtocol = 0x002b, 303 SystemFirmwareIntermediary = 0x002c, 304 ShadowFunctions = 0x002d, 305 DataObjectExchange = 0x002e, 306 Reserved = 0x002f, 307 ExtendedCapabilitiesAbsence = 0xffff, 308 } 309 310 impl From<u16> for PciExpressCapabilityId { 311 fn from(c: u16) -> Self { 312 match c { 313 0x0000 => PciExpressCapabilityId::NullCapability, 314 0x0001 => PciExpressCapabilityId::AdvancedErrorReporting, 315 0x0002 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelNotPresent, 316 0x0003 => PciExpressCapabilityId::DeviceSerialNumber, 317 0x0004 => PciExpressCapabilityId::PowerBudgeting, 318 0x0005 => PciExpressCapabilityId::RootComplexLinkDeclaration, 319 0x0006 => PciExpressCapabilityId::RootComplexInternalLinkControl, 320 0x0007 => PciExpressCapabilityId::RootComplexEventCollectorEndpointAssociation, 321 0x0008 => PciExpressCapabilityId::MultiFunctionVirtualChannel, 322 0x0009 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelPresent, 323 0x000a => PciExpressCapabilityId::RootComplexRegisterBlock, 324 0x000b => PciExpressCapabilityId::VendorSpecificExtendedCapability, 325 0x000c => PciExpressCapabilityId::ConfigurationAccessCorrelation, 326 0x000d => PciExpressCapabilityId::AccessControlServices, 327 0x000e => PciExpressCapabilityId::AlternativeRoutingIdentificationInterpretation, 328 0x000f => PciExpressCapabilityId::AddressTranslationServices, 329 0x0010 => PciExpressCapabilityId::SingleRootIoVirtualization, 330 0x0011 => PciExpressCapabilityId::DeprecatedMultiRootIoVirtualization, 331 0x0012 => PciExpressCapabilityId::Multicast, 332 0x0013 => PciExpressCapabilityId::PageRequestInterface, 333 0x0014 => PciExpressCapabilityId::ReservedForAmd, 334 0x0015 => PciExpressCapabilityId::ResizeableBar, 335 0x0016 => PciExpressCapabilityId::DynamicPowerAllocation, 336 0x0017 => PciExpressCapabilityId::ThpRequester, 337 0x0018 => PciExpressCapabilityId::LatencyToleranceReporting, 338 0x0019 => PciExpressCapabilityId::SecondaryPciExpress, 339 0x001a => PciExpressCapabilityId::ProtocolMultiplexing, 340 0x001b => PciExpressCapabilityId::ProcessAddressSpaceId, 341 0x001c => PciExpressCapabilityId::LnRequester, 342 0x001d => PciExpressCapabilityId::DownstreamPortContainment, 343 0x001e => PciExpressCapabilityId::L1PmSubstates, 344 0x001f => PciExpressCapabilityId::PrecisionTimeMeasurement, 345 0x0020 => PciExpressCapabilityId::PciExpressOverMphy, 346 0x0021 => PciExpressCapabilityId::FRSQueueing, 347 0x0022 => PciExpressCapabilityId::ReadinessTimeReporting, 348 0x0023 => PciExpressCapabilityId::DesignatedVendorSpecificExtendedCapability, 349 0x0024 => PciExpressCapabilityId::VfResizeableBar, 350 0x0025 => PciExpressCapabilityId::DataLinkFeature, 351 0x0026 => PciExpressCapabilityId::PhysicalLayerSixteenGts, 352 0x0027 => PciExpressCapabilityId::LaneMarginingAtTheReceiver, 353 0x0028 => PciExpressCapabilityId::HierarchyId, 354 0x0029 => PciExpressCapabilityId::NativePcieEnclosureManagement, 355 0x002a => PciExpressCapabilityId::PhysicalLayerThirtyTwoGts, 356 0x002b => PciExpressCapabilityId::AlternateProtocol, 357 0x002c => PciExpressCapabilityId::SystemFirmwareIntermediary, 358 0x002d => PciExpressCapabilityId::ShadowFunctions, 359 0x002e => PciExpressCapabilityId::DataObjectExchange, 360 0xffff => PciExpressCapabilityId::ExtendedCapabilitiesAbsence, 361 _ => PciExpressCapabilityId::Reserved, 362 } 363 } 364 } 365 366 /// A PCI capability list. Devices can optionally specify capabilities in their configuration space. 367 pub trait PciCapability { 368 fn bytes(&self) -> &[u8]; 369 fn id(&self) -> PciCapabilityId; 370 } 371 372 fn encode_32_bits_bar_size(bar_size: u32) -> Option<u32> { 373 if bar_size > 0 { 374 return Some(!(bar_size - 1)); 375 } 376 None 377 } 378 379 fn decode_32_bits_bar_size(bar_size: u32) -> Option<u32> { 380 if bar_size > 0 { 381 return Some(!bar_size + 1); 382 } 383 None 384 } 385 386 fn encode_64_bits_bar_size(bar_size: u64) -> Option<(u32, u32)> { 387 if bar_size > 0 { 388 let result = !(bar_size - 1); 389 let result_hi = (result >> 32) as u32; 390 let result_lo = (result & 0xffff_ffff) as u32; 391 return Some((result_hi, result_lo)); 392 } 393 None 394 } 395 396 fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> { 397 let bar_size: u64 = ((bar_size_hi as u64) << 32) | (bar_size_lo as u64); 398 if bar_size > 0 { 399 return Some(!bar_size + 1); 400 } 401 None 402 } 403 404 #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)] 405 struct PciBar { 406 addr: u32, 407 size: u32, 408 used: bool, 409 r#type: Option<PciBarRegionType>, 410 } 411 412 #[derive(Serialize, Deserialize)] 413 pub struct PciConfigurationState { 414 registers: Vec<u32>, 415 writable_bits: Vec<u32>, 416 bars: Vec<PciBar>, 417 rom_bar_addr: u32, 418 rom_bar_size: u32, 419 rom_bar_used: bool, 420 last_capability: Option<(usize, usize)>, 421 msix_cap_reg_idx: Option<usize>, 422 } 423 424 /// Contains the configuration space of a PCI node. 425 /// 426 /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space). 427 /// The configuration space is accessed with DWORD reads and writes from the guest. 428 pub struct PciConfiguration { 429 registers: [u32; NUM_CONFIGURATION_REGISTERS], 430 writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register. 431 bars: [PciBar; NUM_BAR_REGS], 432 rom_bar_addr: u32, 433 rom_bar_size: u32, 434 rom_bar_used: bool, 435 // Contains the byte offset and size of the last capability. 436 last_capability: Option<(usize, usize)>, 437 msix_cap_reg_idx: Option<usize>, 438 msix_config: Option<Arc<Mutex<MsixConfig>>>, 439 } 440 441 /// See pci_regs.h in kernel 442 #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] 443 pub enum PciBarRegionType { 444 Memory32BitRegion = 0, 445 IoRegion = 0x01, 446 Memory64BitRegion = 0x04, 447 } 448 449 impl From<PciBarType> for PciBarRegionType { 450 fn from(type_: PciBarType) -> Self { 451 match type_ { 452 PciBarType::Io => PciBarRegionType::IoRegion, 453 PciBarType::Mmio32 => PciBarRegionType::Memory32BitRegion, 454 PciBarType::Mmio64 => PciBarRegionType::Memory64BitRegion, 455 } 456 } 457 } 458 459 impl From<PciBarRegionType> for PciBarType { 460 fn from(val: PciBarRegionType) -> Self { 461 match val { 462 PciBarRegionType::IoRegion => PciBarType::Io, 463 PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32, 464 PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64, 465 } 466 } 467 } 468 469 #[derive(Copy, Clone)] 470 pub enum PciBarPrefetchable { 471 NotPrefetchable = 0, 472 Prefetchable = 0x08, 473 } 474 475 impl From<PciBarPrefetchable> for bool { 476 fn from(val: PciBarPrefetchable) -> Self { 477 match val { 478 PciBarPrefetchable::NotPrefetchable => false, 479 PciBarPrefetchable::Prefetchable => true, 480 } 481 } 482 } 483 484 #[derive(Copy, Clone)] 485 pub struct PciBarConfiguration { 486 addr: u64, 487 size: u64, 488 idx: usize, 489 region_type: PciBarRegionType, 490 prefetchable: PciBarPrefetchable, 491 } 492 493 #[derive(Debug)] 494 pub enum Error { 495 BarAddressInvalid(u64, u64), 496 BarInUse(usize), 497 BarInUse64(usize), 498 BarInvalid(usize), 499 BarInvalid64(usize), 500 BarSizeInvalid(u64), 501 CapabilityEmpty, 502 CapabilityLengthInvalid(usize), 503 CapabilitySpaceFull(usize), 504 Decode32BarSize, 505 Decode64BarSize, 506 Encode32BarSize, 507 Encode64BarSize, 508 RomBarAddressInvalid(u64, u64), 509 RomBarInUse(usize), 510 RomBarInvalid(usize), 511 RomBarSizeInvalid(u64), 512 } 513 pub type Result<T> = std::result::Result<T, Error>; 514 515 impl std::error::Error for Error {} 516 517 impl Display for Error { 518 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 519 use self::Error::*; 520 match self { 521 BarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"), 522 BarInUse(b) => write!(f, "bar {b} already used"), 523 BarInUse64(b) => write!(f, "64bit bar {b} already used(requires two regs)"), 524 BarInvalid(b) => write!(f, "bar {} invalid, max {}", b, NUM_BAR_REGS - 1), 525 BarInvalid64(b) => write!( 526 f, 527 "64bitbar {} invalid, requires two regs, max {}", 528 b, 529 NUM_BAR_REGS - 1 530 ), 531 BarSizeInvalid(s) => write!(f, "bar address {s} not a power of two"), 532 CapabilityEmpty => write!(f, "empty capabilities are invalid"), 533 CapabilityLengthInvalid(l) => write!(f, "Invalid capability length {l}"), 534 CapabilitySpaceFull(s) => write!(f, "capability of size {s} doesn't fit"), 535 Decode32BarSize => write!(f, "failed to decode 32 bits BAR size"), 536 Decode64BarSize => write!(f, "failed to decode 64 bits BAR size"), 537 Encode32BarSize => write!(f, "failed to encode 32 bits BAR size"), 538 Encode64BarSize => write!(f, "failed to encode 64 bits BAR size"), 539 RomBarAddressInvalid(a, s) => write!(f, "address {a} size {s} too big"), 540 RomBarInUse(b) => write!(f, "rom bar {b} already used"), 541 RomBarInvalid(b) => write!(f, "rom bar {} invalid, max {}", b, NUM_BAR_REGS - 1), 542 RomBarSizeInvalid(s) => write!(f, "rom bar address {s} not a power of two"), 543 } 544 } 545 } 546 547 impl PciConfiguration { 548 #[allow(clippy::too_many_arguments)] 549 pub fn new( 550 vendor_id: u16, 551 device_id: u16, 552 revision_id: u8, 553 class_code: PciClassCode, 554 subclass: &dyn PciSubclass, 555 programming_interface: Option<&dyn PciProgrammingInterface>, 556 header_type: PciHeaderType, 557 subsystem_vendor_id: u16, 558 subsystem_id: u16, 559 msix_config: Option<Arc<Mutex<MsixConfig>>>, 560 state: Option<PciConfigurationState>, 561 ) -> Self { 562 let ( 563 registers, 564 writable_bits, 565 bars, 566 rom_bar_addr, 567 rom_bar_size, 568 rom_bar_used, 569 last_capability, 570 msix_cap_reg_idx, 571 ) = if let Some(state) = state { 572 ( 573 state.registers.try_into().unwrap(), 574 state.writable_bits.try_into().unwrap(), 575 state.bars.try_into().unwrap(), 576 state.rom_bar_addr, 577 state.rom_bar_size, 578 state.rom_bar_used, 579 state.last_capability, 580 state.msix_cap_reg_idx, 581 ) 582 } else { 583 let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS]; 584 let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS]; 585 registers[0] = (u32::from(device_id) << 16) | u32::from(vendor_id); 586 // TODO(dverkamp): Status should be write-1-to-clear 587 writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w) 588 let pi = if let Some(pi) = programming_interface { 589 pi.get_register_value() 590 } else { 591 0 592 }; 593 registers[2] = (u32::from(class_code.get_register_value()) << 24) 594 | (u32::from(subclass.get_register_value()) << 16) 595 | (u32::from(pi) << 8) 596 | u32::from(revision_id); 597 writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w) 598 match header_type { 599 PciHeaderType::Device => { 600 registers[3] = 0x0000_0000; // Header type 0 (device) 601 writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w) 602 } 603 PciHeaderType::Bridge => { 604 registers[3] = 0x0001_0000; // Header type 1 (bridge) 605 writable_bits[9] = 0xfff0_fff0; // Memory base and limit 606 writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w) 607 } 608 }; 609 registers[11] = (u32::from(subsystem_id) << 16) | u32::from(subsystem_vendor_id); 610 611 ( 612 registers, 613 writable_bits, 614 [PciBar::default(); NUM_BAR_REGS], 615 0, 616 0, 617 false, 618 None, 619 None, 620 ) 621 }; 622 623 PciConfiguration { 624 registers, 625 writable_bits, 626 bars, 627 rom_bar_addr, 628 rom_bar_size, 629 rom_bar_used, 630 last_capability, 631 msix_cap_reg_idx, 632 msix_config, 633 } 634 } 635 636 fn state(&self) -> PciConfigurationState { 637 PciConfigurationState { 638 registers: self.registers.to_vec(), 639 writable_bits: self.writable_bits.to_vec(), 640 bars: self.bars.to_vec(), 641 rom_bar_addr: self.rom_bar_addr, 642 rom_bar_size: self.rom_bar_size, 643 rom_bar_used: self.rom_bar_used, 644 last_capability: self.last_capability, 645 msix_cap_reg_idx: self.msix_cap_reg_idx, 646 } 647 } 648 649 /// Reads a 32bit register from `reg_idx` in the register map. 650 pub fn read_reg(&self, reg_idx: usize) -> u32 { 651 *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff)) 652 } 653 654 /// Writes a 32bit register to `reg_idx` in the register map. 655 pub fn write_reg(&mut self, reg_idx: usize, value: u32) { 656 let mut mask = self.writable_bits[reg_idx]; 657 658 if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(®_idx) { 659 // Handle very specific case where the BAR is being written with 660 // all 1's to retrieve the BAR size during next BAR reading. 661 if value == 0xffff_ffff { 662 mask &= self.bars[reg_idx - 4].size; 663 } 664 } else if reg_idx == ROM_BAR_REG { 665 // Handle very specific case where the BAR is being written with 666 // all 1's on bits 31-11 to retrieve the BAR size during next BAR 667 // reading. 668 if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK { 669 mask &= self.rom_bar_size; 670 } 671 } 672 673 if let Some(r) = self.registers.get_mut(reg_idx) { 674 *r = (*r & !self.writable_bits[reg_idx]) | (value & mask); 675 } else { 676 warn!("bad PCI register write {}", reg_idx); 677 } 678 } 679 680 /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned. 681 pub fn write_word(&mut self, offset: usize, value: u16) { 682 let shift = match offset % 4 { 683 0 => 0, 684 2 => 16, 685 _ => { 686 warn!("bad PCI config write offset {}", offset); 687 return; 688 } 689 }; 690 let reg_idx = offset / 4; 691 692 if let Some(r) = self.registers.get_mut(reg_idx) { 693 let writable_mask = self.writable_bits[reg_idx]; 694 let mask = (0xffffu32 << shift) & writable_mask; 695 let shifted_value = (u32::from(value) << shift) & writable_mask; 696 *r = *r & !mask | shifted_value; 697 } else { 698 warn!("bad PCI config write offset {}", offset); 699 } 700 } 701 702 /// Writes a byte to `offset`. 703 pub fn write_byte(&mut self, offset: usize, value: u8) { 704 self.write_byte_internal(offset, value, true); 705 } 706 707 /// Writes a byte to `offset`, optionally enforcing read-only bits. 708 fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) { 709 let shift = (offset % 4) * 8; 710 let reg_idx = offset / 4; 711 712 if let Some(r) = self.registers.get_mut(reg_idx) { 713 let writable_mask = if apply_writable_mask { 714 self.writable_bits[reg_idx] 715 } else { 716 0xffff_ffff 717 }; 718 let mask = (0xffu32 << shift) & writable_mask; 719 let shifted_value = (u32::from(value) << shift) & writable_mask; 720 *r = *r & !mask | shifted_value; 721 } else { 722 warn!("bad PCI config write offset {}", offset); 723 } 724 } 725 726 /// Adds a region specified by `config`. Configures the specified BAR(s) to 727 /// report this region and size to the guest kernel. Enforces a few constraints 728 /// (i.e, region size must be power of two, register not already used). 729 pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> { 730 let bar_idx = config.idx; 731 let reg_idx = BAR0_REG + bar_idx; 732 733 if self.bars[bar_idx].used { 734 return Err(Error::BarInUse(bar_idx)); 735 } 736 737 if !config.size.is_power_of_two() { 738 return Err(Error::BarSizeInvalid(config.size)); 739 } 740 741 if bar_idx >= NUM_BAR_REGS { 742 return Err(Error::BarInvalid(bar_idx)); 743 } 744 745 let end_addr = config 746 .addr 747 .checked_add(config.size - 1) 748 .ok_or(Error::BarAddressInvalid(config.addr, config.size))?; 749 match config.region_type { 750 PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => { 751 if end_addr > u64::from(u32::MAX) { 752 return Err(Error::BarAddressInvalid(config.addr, config.size)); 753 } 754 755 // Encode the BAR size as expected by the software running in 756 // the guest. 757 self.bars[bar_idx].size = 758 encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?; 759 } 760 PciBarRegionType::Memory64BitRegion => { 761 if bar_idx + 1 >= NUM_BAR_REGS { 762 return Err(Error::BarInvalid64(bar_idx)); 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.is_power_of_two() { 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) { 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_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(C, 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