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