1e8308dd1SSamuel Ortiz // Copyright 2018 The Chromium OS Authors. All rights reserved.
2e8308dd1SSamuel Ortiz // Use of this source code is governed by a BSD-style license that can be
3040ea543SSamuel Ortiz // found in the LICENSE-BSD-3-Clause file.
45e9886bbSRuslan Mstoi //
55e9886bbSRuslan Mstoi // SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
6e8308dd1SSamuel Ortiz
7e1701f11SSebastien Boeuf use std::sync::{Arc, Mutex};
888a9f799SRob Bradford
988a9f799SRob Bradford use byteorder::{ByteOrder, LittleEndian};
1088a9f799SRob Bradford use serde::{Deserialize, Serialize};
11*a007b750SPhilipp Schuster use thiserror::Error;
1211e9f433SSebastien Boeuf use vm_device::PciBarType;
1310ab87d6SRob Bradford use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable};
14e8308dd1SSamuel Ortiz
1588a9f799SRob Bradford use crate::device::BarReprogrammingParams;
1688a9f799SRob Bradford use crate::{MsixConfig, PciInterruptPin};
1788a9f799SRob Bradford
184cf89d37SQiu Wenbo // The number of 32bit registers in the config space, 4096 bytes.
194cf89d37SQiu Wenbo const NUM_CONFIGURATION_REGISTERS: usize = 1024;
20e8308dd1SSamuel Ortiz
218da7c13eSBo Chen pub(crate) const COMMAND_REG: usize = 1;
228da7c13eSBo Chen pub(crate) const COMMAND_REG_MEMORY_SPACE_MASK: u32 = 0x0000_0002;
23e8308dd1SSamuel Ortiz const STATUS_REG: usize = 1;
24e8308dd1SSamuel Ortiz const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
25e8308dd1SSamuel Ortiz const BAR0_REG: usize = 4;
26d217089bSSebastien Boeuf const ROM_BAR_REG: usize = 12;
27da95c0d7SSebastien Boeuf const ROM_BAR_IDX: usize = 6;
28e8308dd1SSamuel Ortiz const BAR_IO_ADDR_MASK: u32 = 0xffff_fffc;
29e8308dd1SSamuel Ortiz const BAR_MEM_ADDR_MASK: u32 = 0xffff_fff0;
30d217089bSSebastien Boeuf const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
3123fb4fa2SSebastien Boeuf const MSI_CAPABILITY_REGISTER_MASK: u32 = 0x0071_0000;
32a116add9SRob Bradford const MSIX_CAPABILITY_REGISTER_MASK: u32 = 0xc000_0000;
33e8308dd1SSamuel Ortiz const NUM_BAR_REGS: usize = 6;
34e8308dd1SSamuel Ortiz const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
35e8308dd1SSamuel Ortiz const FIRST_CAPABILITY_OFFSET: usize = 0x40;
36e8308dd1SSamuel Ortiz const CAPABILITY_MAX_OFFSET: usize = 192;
37e8308dd1SSamuel Ortiz
38e8308dd1SSamuel Ortiz const INTERRUPT_LINE_PIN_REG: usize = 15;
39e8308dd1SSamuel Ortiz
40eae80438SSebastien Boeuf pub const PCI_CONFIGURATION_ID: &str = "pci_configuration";
41eae80438SSebastien Boeuf
42e8308dd1SSamuel Ortiz /// Represents the types of PCI headers allowed in the configuration registers.
43e8308dd1SSamuel Ortiz #[derive(Copy, Clone)]
44e8308dd1SSamuel Ortiz pub enum PciHeaderType {
45e8308dd1SSamuel Ortiz Device,
46e8308dd1SSamuel Ortiz Bridge,
47e8308dd1SSamuel Ortiz }
48e8308dd1SSamuel Ortiz
49e8308dd1SSamuel Ortiz /// Classes of PCI nodes.
50e8308dd1SSamuel Ortiz #[allow(dead_code)]
51e8308dd1SSamuel Ortiz #[derive(Copy, Clone)]
52e8308dd1SSamuel Ortiz pub enum PciClassCode {
53e8308dd1SSamuel Ortiz TooOld,
54e8308dd1SSamuel Ortiz MassStorage,
55e8308dd1SSamuel Ortiz NetworkController,
56e8308dd1SSamuel Ortiz DisplayController,
57e8308dd1SSamuel Ortiz MultimediaController,
58e8308dd1SSamuel Ortiz MemoryController,
59e8308dd1SSamuel Ortiz BridgeDevice,
60e8308dd1SSamuel Ortiz SimpleCommunicationController,
61e8308dd1SSamuel Ortiz BaseSystemPeripheral,
62e8308dd1SSamuel Ortiz InputDevice,
63e8308dd1SSamuel Ortiz DockingStation,
64e8308dd1SSamuel Ortiz Processor,
65e8308dd1SSamuel Ortiz SerialBusController,
66e8308dd1SSamuel Ortiz WirelessController,
67e8308dd1SSamuel Ortiz IntelligentIoController,
68e8308dd1SSamuel Ortiz EncryptionController,
69e8308dd1SSamuel Ortiz DataAcquisitionSignalProcessing,
70e8308dd1SSamuel Ortiz Other = 0xff,
71e8308dd1SSamuel Ortiz }
72e8308dd1SSamuel Ortiz
73e8308dd1SSamuel Ortiz impl PciClassCode {
get_register_value(self) -> u874e8308dd1SSamuel Ortiz pub fn get_register_value(self) -> u8 {
75e8308dd1SSamuel Ortiz self as u8
76e8308dd1SSamuel Ortiz }
77e8308dd1SSamuel Ortiz }
78e8308dd1SSamuel Ortiz
795c3f4dbeSJosh Soref /// A PCI subclass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait
80e8308dd1SSamuel Ortiz /// is implemented by each subclass. It allows use of a trait object to generate configurations.
81e8308dd1SSamuel Ortiz pub trait PciSubclass {
82e8308dd1SSamuel Ortiz /// Convert this subclass to the value used in the PCI specification.
get_register_value(&self) -> u883e8308dd1SSamuel Ortiz fn get_register_value(&self) -> u8;
84e8308dd1SSamuel Ortiz }
85e8308dd1SSamuel Ortiz
86e8308dd1SSamuel Ortiz /// Subclasses of the MultimediaController class.
87e8308dd1SSamuel Ortiz #[allow(dead_code)]
88e8308dd1SSamuel Ortiz #[derive(Copy, Clone)]
89e8308dd1SSamuel Ortiz pub enum PciMultimediaSubclass {
90e8308dd1SSamuel Ortiz VideoController = 0x00,
91e8308dd1SSamuel Ortiz AudioController = 0x01,
92e8308dd1SSamuel Ortiz TelephonyDevice = 0x02,
93e8308dd1SSamuel Ortiz AudioDevice = 0x03,
94e8308dd1SSamuel Ortiz Other = 0x80,
95e8308dd1SSamuel Ortiz }
96e8308dd1SSamuel Ortiz
97e8308dd1SSamuel Ortiz impl PciSubclass for PciMultimediaSubclass {
get_register_value(&self) -> u898e8308dd1SSamuel Ortiz fn get_register_value(&self) -> u8 {
99e8308dd1SSamuel Ortiz *self as u8
100e8308dd1SSamuel Ortiz }
101e8308dd1SSamuel Ortiz }
102e8308dd1SSamuel Ortiz
103e8308dd1SSamuel Ortiz /// Subclasses of the BridgeDevice
104e8308dd1SSamuel Ortiz #[allow(dead_code)]
105e8308dd1SSamuel Ortiz #[derive(Copy, Clone)]
106e8308dd1SSamuel Ortiz pub enum PciBridgeSubclass {
107e8308dd1SSamuel Ortiz HostBridge = 0x00,
108e8308dd1SSamuel Ortiz IsaBridge = 0x01,
109e8308dd1SSamuel Ortiz EisaBridge = 0x02,
110e8308dd1SSamuel Ortiz McaBridge = 0x03,
111e8308dd1SSamuel Ortiz PciToPciBridge = 0x04,
112e8308dd1SSamuel Ortiz PcmciaBridge = 0x05,
113e8308dd1SSamuel Ortiz NuBusBridge = 0x06,
114e8308dd1SSamuel Ortiz CardBusBridge = 0x07,
115827229d8SRob Bradford RacEwayBridge = 0x08,
116e8308dd1SSamuel Ortiz PciToPciSemiTransparentBridge = 0x09,
117e8308dd1SSamuel Ortiz InfiniBrandToPciHostBridge = 0x0a,
118e8308dd1SSamuel Ortiz OtherBridgeDevice = 0x80,
119e8308dd1SSamuel Ortiz }
120e8308dd1SSamuel Ortiz
121e8308dd1SSamuel Ortiz impl PciSubclass for PciBridgeSubclass {
get_register_value(&self) -> u8122e8308dd1SSamuel Ortiz fn get_register_value(&self) -> u8 {
123e8308dd1SSamuel Ortiz *self as u8
124e8308dd1SSamuel Ortiz }
125e8308dd1SSamuel Ortiz }
126e8308dd1SSamuel Ortiz
127e8308dd1SSamuel Ortiz /// Subclass of the SerialBus
128e8308dd1SSamuel Ortiz #[allow(dead_code)]
129e8308dd1SSamuel Ortiz #[derive(Copy, Clone)]
130e8308dd1SSamuel Ortiz pub enum PciSerialBusSubClass {
131e8308dd1SSamuel Ortiz Firewire = 0x00,
132827229d8SRob Bradford Accessbus = 0x01,
133827229d8SRob Bradford Ssa = 0x02,
134827229d8SRob Bradford Usb = 0x03,
135e8308dd1SSamuel Ortiz }
136e8308dd1SSamuel Ortiz
137e8308dd1SSamuel Ortiz impl PciSubclass for PciSerialBusSubClass {
get_register_value(&self) -> u8138e8308dd1SSamuel Ortiz fn get_register_value(&self) -> u8 {
139e8308dd1SSamuel Ortiz *self as u8
140e8308dd1SSamuel Ortiz }
141e8308dd1SSamuel Ortiz }
142e8308dd1SSamuel Ortiz
1430b7fb42aSSamuel Ortiz /// Mass Storage Sub Classes
1440b7fb42aSSamuel Ortiz #[allow(dead_code)]
1450b7fb42aSSamuel Ortiz #[derive(Copy, Clone)]
1460b7fb42aSSamuel Ortiz pub enum PciMassStorageSubclass {
147827229d8SRob Bradford ScsiStorage = 0x00,
148827229d8SRob Bradford IdeInterface = 0x01,
1490b7fb42aSSamuel Ortiz FloppyController = 0x02,
150827229d8SRob Bradford IpiController = 0x03,
151827229d8SRob Bradford RaidController = 0x04,
152827229d8SRob Bradford AtaController = 0x05,
153827229d8SRob Bradford SataController = 0x06,
154827229d8SRob Bradford SerialScsiController = 0x07,
155827229d8SRob Bradford NvmController = 0x08,
1560b7fb42aSSamuel Ortiz MassStorage = 0x80,
1570b7fb42aSSamuel Ortiz }
1580b7fb42aSSamuel Ortiz
1590b7fb42aSSamuel Ortiz impl PciSubclass for PciMassStorageSubclass {
get_register_value(&self) -> u81600b7fb42aSSamuel Ortiz fn get_register_value(&self) -> u8 {
1610b7fb42aSSamuel Ortiz *self as u8
1620b7fb42aSSamuel Ortiz }
1630b7fb42aSSamuel Ortiz }
1640b7fb42aSSamuel Ortiz
1650b7fb42aSSamuel Ortiz /// Network Controller Sub Classes
1660b7fb42aSSamuel Ortiz #[allow(dead_code)]
1670b7fb42aSSamuel Ortiz #[derive(Copy, Clone)]
1680b7fb42aSSamuel Ortiz pub enum PciNetworkControllerSubclass {
1690b7fb42aSSamuel Ortiz EthernetController = 0x00,
1700b7fb42aSSamuel Ortiz TokenRingController = 0x01,
171827229d8SRob Bradford FddiController = 0x02,
172827229d8SRob Bradford AtmController = 0x03,
173827229d8SRob Bradford IsdnController = 0x04,
1740b7fb42aSSamuel Ortiz WorldFipController = 0x05,
175827229d8SRob Bradford PicmgController = 0x06,
1760b7fb42aSSamuel Ortiz InfinibandController = 0x07,
1770b7fb42aSSamuel Ortiz FabricController = 0x08,
1780b7fb42aSSamuel Ortiz NetworkController = 0x80,
1790b7fb42aSSamuel Ortiz }
1800b7fb42aSSamuel Ortiz
1810b7fb42aSSamuel Ortiz impl PciSubclass for PciNetworkControllerSubclass {
get_register_value(&self) -> u81820b7fb42aSSamuel Ortiz fn get_register_value(&self) -> u8 {
1830b7fb42aSSamuel Ortiz *self as u8
1840b7fb42aSSamuel Ortiz }
1850b7fb42aSSamuel Ortiz }
1860b7fb42aSSamuel Ortiz
18760c8a72eSBo Chen /// Trait to define a PCI class programming interface
18860c8a72eSBo Chen ///
18960c8a72eSBo Chen /// Each combination of `PciClassCode` and `PciSubclass` can specify a
19060c8a72eSBo Chen /// set of register-level programming interfaces.
191e8308dd1SSamuel Ortiz /// This trait is implemented by each programming interface.
192e8308dd1SSamuel Ortiz /// It allows use of a trait object to generate configurations.
193e8308dd1SSamuel Ortiz pub trait PciProgrammingInterface {
194e8308dd1SSamuel Ortiz /// Convert this programming interface to the value used in the PCI specification.
get_register_value(&self) -> u8195e8308dd1SSamuel Ortiz fn get_register_value(&self) -> u8;
196e8308dd1SSamuel Ortiz }
197e8308dd1SSamuel Ortiz
198e8308dd1SSamuel Ortiz /// Types of PCI capabilities.
1992716bc33SRob Bradford #[derive(PartialEq, Eq, Copy, Clone)]
20029878956SSamuel Ortiz #[allow(dead_code)]
20129878956SSamuel Ortiz #[allow(non_camel_case_types)]
202e45e3df6SSebastien Boeuf #[repr(u8)]
203827229d8SRob Bradford pub enum PciCapabilityId {
204827229d8SRob Bradford ListId = 0,
205e8308dd1SSamuel Ortiz PowerManagement = 0x01,
206e8308dd1SSamuel Ortiz AcceleratedGraphicsPort = 0x02,
207e8308dd1SSamuel Ortiz VitalProductData = 0x03,
208e8308dd1SSamuel Ortiz SlotIdentification = 0x04,
209e8308dd1SSamuel Ortiz MessageSignalledInterrupts = 0x05,
210827229d8SRob Bradford CompactPciHotSwap = 0x06,
211827229d8SRob Bradford PciX = 0x07,
212e8308dd1SSamuel Ortiz HyperTransport = 0x08,
213e8308dd1SSamuel Ortiz VendorSpecific = 0x09,
214e8308dd1SSamuel Ortiz Debugport = 0x0A,
215827229d8SRob Bradford CompactPciCentralResourceControl = 0x0B,
216827229d8SRob Bradford PciStandardHotPlugController = 0x0C,
217827229d8SRob Bradford BridgeSubsystemVendorDeviceId = 0x0D,
218827229d8SRob Bradford AgpTargetPciPcibridge = 0x0E,
219e8308dd1SSamuel Ortiz SecureDevice = 0x0F,
220827229d8SRob Bradford PciExpress = 0x10,
221827229d8SRob Bradford MsiX = 0x11,
222827229d8SRob Bradford SataDataIndexConf = 0x12,
223827229d8SRob Bradford PciAdvancedFeatures = 0x13,
224827229d8SRob Bradford PciEnhancedAllocation = 0x14,
225e8308dd1SSamuel Ortiz }
226e8308dd1SSamuel Ortiz
227827229d8SRob Bradford impl From<u8> for PciCapabilityId {
from(c: u8) -> Self22829878956SSamuel Ortiz fn from(c: u8) -> Self {
22929878956SSamuel Ortiz match c {
230827229d8SRob Bradford 0 => PciCapabilityId::ListId,
231827229d8SRob Bradford 0x01 => PciCapabilityId::PowerManagement,
232827229d8SRob Bradford 0x02 => PciCapabilityId::AcceleratedGraphicsPort,
233827229d8SRob Bradford 0x03 => PciCapabilityId::VitalProductData,
234827229d8SRob Bradford 0x04 => PciCapabilityId::SlotIdentification,
235827229d8SRob Bradford 0x05 => PciCapabilityId::MessageSignalledInterrupts,
236827229d8SRob Bradford 0x06 => PciCapabilityId::CompactPciHotSwap,
237827229d8SRob Bradford 0x07 => PciCapabilityId::PciX,
238827229d8SRob Bradford 0x08 => PciCapabilityId::HyperTransport,
239827229d8SRob Bradford 0x09 => PciCapabilityId::VendorSpecific,
240827229d8SRob Bradford 0x0A => PciCapabilityId::Debugport,
241827229d8SRob Bradford 0x0B => PciCapabilityId::CompactPciCentralResourceControl,
242827229d8SRob Bradford 0x0C => PciCapabilityId::PciStandardHotPlugController,
243827229d8SRob Bradford 0x0D => PciCapabilityId::BridgeSubsystemVendorDeviceId,
244827229d8SRob Bradford 0x0E => PciCapabilityId::AgpTargetPciPcibridge,
245827229d8SRob Bradford 0x0F => PciCapabilityId::SecureDevice,
246827229d8SRob Bradford 0x10 => PciCapabilityId::PciExpress,
247827229d8SRob Bradford 0x11 => PciCapabilityId::MsiX,
248827229d8SRob Bradford 0x12 => PciCapabilityId::SataDataIndexConf,
249827229d8SRob Bradford 0x13 => PciCapabilityId::PciAdvancedFeatures,
250827229d8SRob Bradford 0x14 => PciCapabilityId::PciEnhancedAllocation,
251827229d8SRob Bradford _ => PciCapabilityId::ListId,
25229878956SSamuel Ortiz }
25329878956SSamuel Ortiz }
25429878956SSamuel Ortiz }
25529878956SSamuel Ortiz
256e45e3df6SSebastien Boeuf /// Types of PCI Express capabilities.
257e45e3df6SSebastien Boeuf #[derive(PartialEq, Eq, Copy, Clone, Debug)]
258e45e3df6SSebastien Boeuf #[allow(dead_code)]
259e45e3df6SSebastien Boeuf #[repr(u16)]
260e45e3df6SSebastien Boeuf pub enum PciExpressCapabilityId {
261e45e3df6SSebastien Boeuf NullCapability = 0x0000,
262e45e3df6SSebastien Boeuf AdvancedErrorReporting = 0x0001,
263e45e3df6SSebastien Boeuf VirtualChannelMultiFunctionVirtualChannelNotPresent = 0x0002,
264e45e3df6SSebastien Boeuf DeviceSerialNumber = 0x0003,
265e45e3df6SSebastien Boeuf PowerBudgeting = 0x0004,
266e45e3df6SSebastien Boeuf RootComplexLinkDeclaration = 0x0005,
267e45e3df6SSebastien Boeuf RootComplexInternalLinkControl = 0x0006,
268e45e3df6SSebastien Boeuf RootComplexEventCollectorEndpointAssociation = 0x0007,
269e45e3df6SSebastien Boeuf MultiFunctionVirtualChannel = 0x0008,
270e45e3df6SSebastien Boeuf VirtualChannelMultiFunctionVirtualChannelPresent = 0x0009,
271e45e3df6SSebastien Boeuf RootComplexRegisterBlock = 0x000a,
272e45e3df6SSebastien Boeuf VendorSpecificExtendedCapability = 0x000b,
273e45e3df6SSebastien Boeuf ConfigurationAccessCorrelation = 0x000c,
274e45e3df6SSebastien Boeuf AccessControlServices = 0x000d,
2757bf0cc1eSPhilipp Schuster AlternativeRoutingIdentificationInterpretation = 0x000e,
276e45e3df6SSebastien Boeuf AddressTranslationServices = 0x000f,
277e45e3df6SSebastien Boeuf SingleRootIoVirtualization = 0x0010,
2787bf0cc1eSPhilipp Schuster DeprecatedMultiRootIoVirtualization = 0x0011,
279e45e3df6SSebastien Boeuf Multicast = 0x0012,
280e45e3df6SSebastien Boeuf PageRequestInterface = 0x0013,
281e45e3df6SSebastien Boeuf ReservedForAmd = 0x0014,
282e45e3df6SSebastien Boeuf ResizeableBar = 0x0015,
283e45e3df6SSebastien Boeuf DynamicPowerAllocation = 0x0016,
284e45e3df6SSebastien Boeuf ThpRequester = 0x0017,
285e45e3df6SSebastien Boeuf LatencyToleranceReporting = 0x0018,
286e45e3df6SSebastien Boeuf SecondaryPciExpress = 0x0019,
287e45e3df6SSebastien Boeuf ProtocolMultiplexing = 0x001a,
288e45e3df6SSebastien Boeuf ProcessAddressSpaceId = 0x001b,
2897bf0cc1eSPhilipp Schuster LnRequester = 0x001c,
290e45e3df6SSebastien Boeuf DownstreamPortContainment = 0x001d,
291e45e3df6SSebastien Boeuf L1PmSubstates = 0x001e,
292e45e3df6SSebastien Boeuf PrecisionTimeMeasurement = 0x001f,
293e45e3df6SSebastien Boeuf PciExpressOverMphy = 0x0020,
294e45e3df6SSebastien Boeuf FRSQueueing = 0x0021,
295e45e3df6SSebastien Boeuf ReadinessTimeReporting = 0x0022,
296e45e3df6SSebastien Boeuf DesignatedVendorSpecificExtendedCapability = 0x0023,
297e45e3df6SSebastien Boeuf VfResizeableBar = 0x0024,
298e45e3df6SSebastien Boeuf DataLinkFeature = 0x0025,
299e45e3df6SSebastien Boeuf PhysicalLayerSixteenGts = 0x0026,
30042e9632cSJosh Soref LaneMarginingAtTheReceiver = 0x0027,
301e45e3df6SSebastien Boeuf HierarchyId = 0x0028,
302e45e3df6SSebastien Boeuf NativePcieEnclosureManagement = 0x0029,
303e45e3df6SSebastien Boeuf PhysicalLayerThirtyTwoGts = 0x002a,
304e45e3df6SSebastien Boeuf AlternateProtocol = 0x002b,
305e45e3df6SSebastien Boeuf SystemFirmwareIntermediary = 0x002c,
306e45e3df6SSebastien Boeuf ShadowFunctions = 0x002d,
307e45e3df6SSebastien Boeuf DataObjectExchange = 0x002e,
308e45e3df6SSebastien Boeuf Reserved = 0x002f,
309e45e3df6SSebastien Boeuf ExtendedCapabilitiesAbsence = 0xffff,
310e45e3df6SSebastien Boeuf }
311e45e3df6SSebastien Boeuf
312e45e3df6SSebastien Boeuf impl From<u16> for PciExpressCapabilityId {
from(c: u16) -> Self313e45e3df6SSebastien Boeuf fn from(c: u16) -> Self {
314e45e3df6SSebastien Boeuf match c {
315e45e3df6SSebastien Boeuf 0x0000 => PciExpressCapabilityId::NullCapability,
316e45e3df6SSebastien Boeuf 0x0001 => PciExpressCapabilityId::AdvancedErrorReporting,
317e45e3df6SSebastien Boeuf 0x0002 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelNotPresent,
318e45e3df6SSebastien Boeuf 0x0003 => PciExpressCapabilityId::DeviceSerialNumber,
319e45e3df6SSebastien Boeuf 0x0004 => PciExpressCapabilityId::PowerBudgeting,
320e45e3df6SSebastien Boeuf 0x0005 => PciExpressCapabilityId::RootComplexLinkDeclaration,
321e45e3df6SSebastien Boeuf 0x0006 => PciExpressCapabilityId::RootComplexInternalLinkControl,
322e45e3df6SSebastien Boeuf 0x0007 => PciExpressCapabilityId::RootComplexEventCollectorEndpointAssociation,
323e45e3df6SSebastien Boeuf 0x0008 => PciExpressCapabilityId::MultiFunctionVirtualChannel,
324e45e3df6SSebastien Boeuf 0x0009 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelPresent,
325e45e3df6SSebastien Boeuf 0x000a => PciExpressCapabilityId::RootComplexRegisterBlock,
326e45e3df6SSebastien Boeuf 0x000b => PciExpressCapabilityId::VendorSpecificExtendedCapability,
327e45e3df6SSebastien Boeuf 0x000c => PciExpressCapabilityId::ConfigurationAccessCorrelation,
328e45e3df6SSebastien Boeuf 0x000d => PciExpressCapabilityId::AccessControlServices,
3297bf0cc1eSPhilipp Schuster 0x000e => PciExpressCapabilityId::AlternativeRoutingIdentificationInterpretation,
330e45e3df6SSebastien Boeuf 0x000f => PciExpressCapabilityId::AddressTranslationServices,
331e45e3df6SSebastien Boeuf 0x0010 => PciExpressCapabilityId::SingleRootIoVirtualization,
3327bf0cc1eSPhilipp Schuster 0x0011 => PciExpressCapabilityId::DeprecatedMultiRootIoVirtualization,
333e45e3df6SSebastien Boeuf 0x0012 => PciExpressCapabilityId::Multicast,
334e45e3df6SSebastien Boeuf 0x0013 => PciExpressCapabilityId::PageRequestInterface,
335e45e3df6SSebastien Boeuf 0x0014 => PciExpressCapabilityId::ReservedForAmd,
336e45e3df6SSebastien Boeuf 0x0015 => PciExpressCapabilityId::ResizeableBar,
337e45e3df6SSebastien Boeuf 0x0016 => PciExpressCapabilityId::DynamicPowerAllocation,
338e45e3df6SSebastien Boeuf 0x0017 => PciExpressCapabilityId::ThpRequester,
339e45e3df6SSebastien Boeuf 0x0018 => PciExpressCapabilityId::LatencyToleranceReporting,
340e45e3df6SSebastien Boeuf 0x0019 => PciExpressCapabilityId::SecondaryPciExpress,
341e45e3df6SSebastien Boeuf 0x001a => PciExpressCapabilityId::ProtocolMultiplexing,
342e45e3df6SSebastien Boeuf 0x001b => PciExpressCapabilityId::ProcessAddressSpaceId,
3437bf0cc1eSPhilipp Schuster 0x001c => PciExpressCapabilityId::LnRequester,
344e45e3df6SSebastien Boeuf 0x001d => PciExpressCapabilityId::DownstreamPortContainment,
345e45e3df6SSebastien Boeuf 0x001e => PciExpressCapabilityId::L1PmSubstates,
346e45e3df6SSebastien Boeuf 0x001f => PciExpressCapabilityId::PrecisionTimeMeasurement,
347e45e3df6SSebastien Boeuf 0x0020 => PciExpressCapabilityId::PciExpressOverMphy,
348e45e3df6SSebastien Boeuf 0x0021 => PciExpressCapabilityId::FRSQueueing,
349e45e3df6SSebastien Boeuf 0x0022 => PciExpressCapabilityId::ReadinessTimeReporting,
350e45e3df6SSebastien Boeuf 0x0023 => PciExpressCapabilityId::DesignatedVendorSpecificExtendedCapability,
351e45e3df6SSebastien Boeuf 0x0024 => PciExpressCapabilityId::VfResizeableBar,
352e45e3df6SSebastien Boeuf 0x0025 => PciExpressCapabilityId::DataLinkFeature,
353e45e3df6SSebastien Boeuf 0x0026 => PciExpressCapabilityId::PhysicalLayerSixteenGts,
35442e9632cSJosh Soref 0x0027 => PciExpressCapabilityId::LaneMarginingAtTheReceiver,
355e45e3df6SSebastien Boeuf 0x0028 => PciExpressCapabilityId::HierarchyId,
356e45e3df6SSebastien Boeuf 0x0029 => PciExpressCapabilityId::NativePcieEnclosureManagement,
357e45e3df6SSebastien Boeuf 0x002a => PciExpressCapabilityId::PhysicalLayerThirtyTwoGts,
358e45e3df6SSebastien Boeuf 0x002b => PciExpressCapabilityId::AlternateProtocol,
359e45e3df6SSebastien Boeuf 0x002c => PciExpressCapabilityId::SystemFirmwareIntermediary,
360e45e3df6SSebastien Boeuf 0x002d => PciExpressCapabilityId::ShadowFunctions,
361e45e3df6SSebastien Boeuf 0x002e => PciExpressCapabilityId::DataObjectExchange,
362e45e3df6SSebastien Boeuf 0xffff => PciExpressCapabilityId::ExtendedCapabilitiesAbsence,
363e45e3df6SSebastien Boeuf _ => PciExpressCapabilityId::Reserved,
364e45e3df6SSebastien Boeuf }
365e45e3df6SSebastien Boeuf }
366e45e3df6SSebastien Boeuf }
367e45e3df6SSebastien Boeuf
368e8308dd1SSamuel Ortiz /// A PCI capability list. Devices can optionally specify capabilities in their configuration space.
369e8308dd1SSamuel Ortiz pub trait PciCapability {
bytes(&self) -> &[u8]370e8308dd1SSamuel Ortiz fn bytes(&self) -> &[u8];
id(&self) -> PciCapabilityId371827229d8SRob Bradford fn id(&self) -> PciCapabilityId;
372e8308dd1SSamuel Ortiz }
373e8308dd1SSamuel Ortiz
encode_32_bits_bar_size(bar_size: u32) -> Option<u32>374b8cfdab8SRob Bradford fn encode_32_bits_bar_size(bar_size: u32) -> Option<u32> {
375b8cfdab8SRob Bradford if bar_size > 0 {
376b8cfdab8SRob Bradford return Some(!(bar_size - 1));
377b8cfdab8SRob Bradford }
378b8cfdab8SRob Bradford None
379b8cfdab8SRob Bradford }
380b8cfdab8SRob Bradford
decode_32_bits_bar_size(bar_size: u32) -> Option<u32>381b8cfdab8SRob Bradford fn decode_32_bits_bar_size(bar_size: u32) -> Option<u32> {
382b8cfdab8SRob Bradford if bar_size > 0 {
383b8cfdab8SRob Bradford return Some(!bar_size + 1);
384b8cfdab8SRob Bradford }
385b8cfdab8SRob Bradford None
386b8cfdab8SRob Bradford }
387b8cfdab8SRob Bradford
encode_64_bits_bar_size(bar_size: u64) -> Option<(u32, u32)>388b8cfdab8SRob Bradford fn encode_64_bits_bar_size(bar_size: u64) -> Option<(u32, u32)> {
389b8cfdab8SRob Bradford if bar_size > 0 {
390b8cfdab8SRob Bradford let result = !(bar_size - 1);
391b8cfdab8SRob Bradford let result_hi = (result >> 32) as u32;
392b8cfdab8SRob Bradford let result_lo = (result & 0xffff_ffff) as u32;
393b8cfdab8SRob Bradford return Some((result_hi, result_lo));
394b8cfdab8SRob Bradford }
395b8cfdab8SRob Bradford None
396b8cfdab8SRob Bradford }
397b8cfdab8SRob Bradford
decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64>398b8cfdab8SRob Bradford fn decode_64_bits_bar_size(bar_size_hi: u32, bar_size_lo: u32) -> Option<u64> {
399b8cfdab8SRob Bradford let bar_size: u64 = ((bar_size_hi as u64) << 32) | (bar_size_lo as u64);
400b8cfdab8SRob Bradford if bar_size > 0 {
401b8cfdab8SRob Bradford return Some(!bar_size + 1);
402b8cfdab8SRob Bradford }
403b8cfdab8SRob Bradford None
404b8cfdab8SRob Bradford }
405b8cfdab8SRob Bradford
40610ab87d6SRob Bradford #[derive(Debug, Default, Clone, Copy, Serialize, Deserialize)]
407dc55e459SRob Bradford struct PciBar {
408dc55e459SRob Bradford addr: u32,
409dc55e459SRob Bradford size: u32,
410dc55e459SRob Bradford used: bool,
411dc55e459SRob Bradford r#type: Option<PciBarRegionType>,
412dc55e459SRob Bradford }
413dc55e459SRob Bradford
41410ab87d6SRob Bradford #[derive(Serialize, Deserialize)]
415eae80438SSebastien Boeuf pub struct PciConfigurationState {
416e1701f11SSebastien Boeuf registers: Vec<u32>,
417e1701f11SSebastien Boeuf writable_bits: Vec<u32>,
418dc55e459SRob Bradford bars: Vec<PciBar>,
419e1701f11SSebastien Boeuf rom_bar_addr: u32,
420e1701f11SSebastien Boeuf rom_bar_size: u32,
421e1701f11SSebastien Boeuf rom_bar_used: bool,
422e1701f11SSebastien Boeuf last_capability: Option<(usize, usize)>,
423e1701f11SSebastien Boeuf msix_cap_reg_idx: Option<usize>,
424e1701f11SSebastien Boeuf }
425e1701f11SSebastien Boeuf
426e8308dd1SSamuel Ortiz /// Contains the configuration space of a PCI node.
42760c8a72eSBo Chen ///
428e8308dd1SSamuel Ortiz /// See the [specification](https://en.wikipedia.org/wiki/PCI_configuration_space).
429e8308dd1SSamuel Ortiz /// The configuration space is accessed with DWORD reads and writes from the guest.
430e8308dd1SSamuel Ortiz pub struct PciConfiguration {
431e8308dd1SSamuel Ortiz registers: [u32; NUM_CONFIGURATION_REGISTERS],
432e8308dd1SSamuel Ortiz writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
433dc55e459SRob Bradford bars: [PciBar; NUM_BAR_REGS],
434149b61b2SSebastien Boeuf rom_bar_addr: u32,
435d217089bSSebastien Boeuf rom_bar_size: u32,
436d217089bSSebastien Boeuf rom_bar_used: bool,
437e8308dd1SSamuel Ortiz // Contains the byte offset and size of the last capability.
438e8308dd1SSamuel Ortiz last_capability: Option<(usize, usize)>,
4394d98dcb0SSebastien Boeuf msix_cap_reg_idx: Option<usize>,
4404d98dcb0SSebastien Boeuf msix_config: Option<Arc<Mutex<MsixConfig>>>,
441aaf86ef2SBo Chen pending_bar_reprogram: Vec<BarReprogrammingParams>,
442e8308dd1SSamuel Ortiz }
443e8308dd1SSamuel Ortiz
444e8308dd1SSamuel Ortiz /// See pci_regs.h in kernel
44510ab87d6SRob Bradford #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
446e8308dd1SSamuel Ortiz pub enum PciBarRegionType {
447e8308dd1SSamuel Ortiz Memory32BitRegion = 0,
448827229d8SRob Bradford IoRegion = 0x01,
449e8308dd1SSamuel Ortiz Memory64BitRegion = 0x04,
450e8308dd1SSamuel Ortiz }
451e8308dd1SSamuel Ortiz
45211e9f433SSebastien Boeuf impl From<PciBarType> for PciBarRegionType {
from(type_: PciBarType) -> Self45311e9f433SSebastien Boeuf fn from(type_: PciBarType) -> Self {
45411e9f433SSebastien Boeuf match type_ {
45511e9f433SSebastien Boeuf PciBarType::Io => PciBarRegionType::IoRegion,
45611e9f433SSebastien Boeuf PciBarType::Mmio32 => PciBarRegionType::Memory32BitRegion,
45711e9f433SSebastien Boeuf PciBarType::Mmio64 => PciBarRegionType::Memory64BitRegion,
45811e9f433SSebastien Boeuf }
45911e9f433SSebastien Boeuf }
46011e9f433SSebastien Boeuf }
46111e9f433SSebastien Boeuf
4625b51024eSRavi kumar Veeramally impl From<PciBarRegionType> for PciBarType {
from(val: PciBarRegionType) -> Self4635b51024eSRavi kumar Veeramally fn from(val: PciBarRegionType) -> Self {
4645b51024eSRavi kumar Veeramally match val {
46511e9f433SSebastien Boeuf PciBarRegionType::IoRegion => PciBarType::Io,
46611e9f433SSebastien Boeuf PciBarRegionType::Memory32BitRegion => PciBarType::Mmio32,
46711e9f433SSebastien Boeuf PciBarRegionType::Memory64BitRegion => PciBarType::Mmio64,
46811e9f433SSebastien Boeuf }
46911e9f433SSebastien Boeuf }
47011e9f433SSebastien Boeuf }
47111e9f433SSebastien Boeuf
472e8308dd1SSamuel Ortiz #[derive(Copy, Clone)]
473e8308dd1SSamuel Ortiz pub enum PciBarPrefetchable {
474e8308dd1SSamuel Ortiz NotPrefetchable = 0,
475e8308dd1SSamuel Ortiz Prefetchable = 0x08,
476e8308dd1SSamuel Ortiz }
477e8308dd1SSamuel Ortiz
4785b51024eSRavi kumar Veeramally impl From<PciBarPrefetchable> for bool {
from(val: PciBarPrefetchable) -> Self4795b51024eSRavi kumar Veeramally fn from(val: PciBarPrefetchable) -> Self {
4805b51024eSRavi kumar Veeramally match val {
48111e9f433SSebastien Boeuf PciBarPrefetchable::NotPrefetchable => false,
48211e9f433SSebastien Boeuf PciBarPrefetchable::Prefetchable => true,
48311e9f433SSebastien Boeuf }
48411e9f433SSebastien Boeuf }
48511e9f433SSebastien Boeuf }
48611e9f433SSebastien Boeuf
487e8308dd1SSamuel Ortiz #[derive(Copy, Clone)]
488e8308dd1SSamuel Ortiz pub struct PciBarConfiguration {
489e8308dd1SSamuel Ortiz addr: u64,
490e8308dd1SSamuel Ortiz size: u64,
491da95c0d7SSebastien Boeuf idx: usize,
492e8308dd1SSamuel Ortiz region_type: PciBarRegionType,
493e8308dd1SSamuel Ortiz prefetchable: PciBarPrefetchable,
494e8308dd1SSamuel Ortiz }
495e8308dd1SSamuel Ortiz
496*a007b750SPhilipp Schuster #[derive(Error, Debug)]
497e8308dd1SSamuel Ortiz pub enum Error {
498*a007b750SPhilipp Schuster #[error("address {0} size {1} too big")]
499e8308dd1SSamuel Ortiz BarAddressInvalid(u64, u64),
500*a007b750SPhilipp Schuster #[error("bar {0} already used")]
501e8308dd1SSamuel Ortiz BarInUse(usize),
502*a007b750SPhilipp Schuster #[error("64bit bar {0} already used (requires two regs)")]
503e8308dd1SSamuel Ortiz BarInUse64(usize),
504*a007b750SPhilipp Schuster #[error("bar {0} invalid, max {max}", max = NUM_BAR_REGS - 1)]
505e8308dd1SSamuel Ortiz BarInvalid(usize),
506*a007b750SPhilipp Schuster #[error("64bitbar {0} invalid, requires two regs, max {max}", max = NUM_BAR_REGS - 1)]
507e8308dd1SSamuel Ortiz BarInvalid64(usize),
508*a007b750SPhilipp Schuster #[error("bar address {0} not a power of two")]
509e8308dd1SSamuel Ortiz BarSizeInvalid(u64),
510*a007b750SPhilipp Schuster #[error("empty capabilities are invalid")]
511e8308dd1SSamuel Ortiz CapabilityEmpty,
512*a007b750SPhilipp Schuster #[error("Invalid capability length {0}")]
513e8308dd1SSamuel Ortiz CapabilityLengthInvalid(usize),
514*a007b750SPhilipp Schuster #[error("capability of size {0} doesn't fit")]
515e8308dd1SSamuel Ortiz CapabilitySpaceFull(usize),
516*a007b750SPhilipp Schuster #[error("failed to decode 32 bits BAR size")]
517b8cfdab8SRob Bradford Decode32BarSize,
518*a007b750SPhilipp Schuster #[error("failed to decode 64 bits BAR size")]
519b8cfdab8SRob Bradford Decode64BarSize,
520*a007b750SPhilipp Schuster #[error("failed to encode 32 bits BAR size")]
521b8cfdab8SRob Bradford Encode32BarSize,
522*a007b750SPhilipp Schuster #[error("failed to encode 64 bits BAR size")]
523b8cfdab8SRob Bradford Encode64BarSize,
524*a007b750SPhilipp Schuster #[error("address {0} size {1} too big")]
525d217089bSSebastien Boeuf RomBarAddressInvalid(u64, u64),
526*a007b750SPhilipp Schuster #[error("rom bar {0} already used")]
527d217089bSSebastien Boeuf RomBarInUse(usize),
528*a007b750SPhilipp Schuster #[error("rom bar {0} invalid, max {max}", max = NUM_BAR_REGS - 1)]
529d217089bSSebastien Boeuf RomBarInvalid(usize),
530*a007b750SPhilipp Schuster #[error("rom bar address {0} not a power of two")]
531d217089bSSebastien Boeuf RomBarSizeInvalid(u64),
532e8308dd1SSamuel Ortiz }
533e8308dd1SSamuel Ortiz pub type Result<T> = std::result::Result<T, Error>;
534e8308dd1SSamuel Ortiz
535e8308dd1SSamuel Ortiz impl PciConfiguration {
536e8308dd1SSamuel Ortiz #[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>, ) -> Self537e8308dd1SSamuel Ortiz pub fn new(
538e8308dd1SSamuel Ortiz vendor_id: u16,
539e8308dd1SSamuel Ortiz device_id: u16,
5409bd5ec89SRob Bradford revision_id: u8,
541e8308dd1SSamuel Ortiz class_code: PciClassCode,
542e8308dd1SSamuel Ortiz subclass: &dyn PciSubclass,
543e8308dd1SSamuel Ortiz programming_interface: Option<&dyn PciProgrammingInterface>,
544e8308dd1SSamuel Ortiz header_type: PciHeaderType,
545e8308dd1SSamuel Ortiz subsystem_vendor_id: u16,
546e8308dd1SSamuel Ortiz subsystem_id: u16,
5474d98dcb0SSebastien Boeuf msix_config: Option<Arc<Mutex<MsixConfig>>>,
548eae80438SSebastien Boeuf state: Option<PciConfigurationState>,
549e8308dd1SSamuel Ortiz ) -> Self {
550eae80438SSebastien Boeuf let (
551eae80438SSebastien Boeuf registers,
552eae80438SSebastien Boeuf writable_bits,
553eae80438SSebastien Boeuf bars,
554eae80438SSebastien Boeuf rom_bar_addr,
555eae80438SSebastien Boeuf rom_bar_size,
556eae80438SSebastien Boeuf rom_bar_used,
557eae80438SSebastien Boeuf last_capability,
558eae80438SSebastien Boeuf msix_cap_reg_idx,
559eae80438SSebastien Boeuf ) = if let Some(state) = state {
560eae80438SSebastien Boeuf (
561eae80438SSebastien Boeuf state.registers.try_into().unwrap(),
562eae80438SSebastien Boeuf state.writable_bits.try_into().unwrap(),
563eae80438SSebastien Boeuf state.bars.try_into().unwrap(),
564eae80438SSebastien Boeuf state.rom_bar_addr,
565eae80438SSebastien Boeuf state.rom_bar_size,
566eae80438SSebastien Boeuf state.rom_bar_used,
567eae80438SSebastien Boeuf state.last_capability,
568eae80438SSebastien Boeuf state.msix_cap_reg_idx,
569eae80438SSebastien Boeuf )
570eae80438SSebastien Boeuf } else {
571e8308dd1SSamuel Ortiz let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
572e8308dd1SSamuel Ortiz let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
573b57cc3d7SRob Bradford registers[0] = (u32::from(device_id) << 16) | u32::from(vendor_id);
574e8308dd1SSamuel Ortiz // TODO(dverkamp): Status should be write-1-to-clear
575e8308dd1SSamuel Ortiz writable_bits[1] = 0x0000_ffff; // Status (r/o), command (r/w)
576e8308dd1SSamuel Ortiz let pi = if let Some(pi) = programming_interface {
577e8308dd1SSamuel Ortiz pi.get_register_value()
578e8308dd1SSamuel Ortiz } else {
579e8308dd1SSamuel Ortiz 0
580e8308dd1SSamuel Ortiz };
581b57cc3d7SRob Bradford registers[2] = (u32::from(class_code.get_register_value()) << 24)
582b57cc3d7SRob Bradford | (u32::from(subclass.get_register_value()) << 16)
583b57cc3d7SRob Bradford | (u32::from(pi) << 8)
5849bd5ec89SRob Bradford | u32::from(revision_id);
585e8308dd1SSamuel Ortiz writable_bits[3] = 0x0000_00ff; // Cacheline size (r/w)
586e8308dd1SSamuel Ortiz match header_type {
587e8308dd1SSamuel Ortiz PciHeaderType::Device => {
588e8308dd1SSamuel Ortiz registers[3] = 0x0000_0000; // Header type 0 (device)
589e8308dd1SSamuel Ortiz writable_bits[15] = 0x0000_00ff; // Interrupt line (r/w)
590e8308dd1SSamuel Ortiz }
591e8308dd1SSamuel Ortiz PciHeaderType::Bridge => {
592e8308dd1SSamuel Ortiz registers[3] = 0x0001_0000; // Header type 1 (bridge)
593e8308dd1SSamuel Ortiz writable_bits[9] = 0xfff0_fff0; // Memory base and limit
594e8308dd1SSamuel Ortiz writable_bits[15] = 0xffff_00ff; // Bridge control (r/w), interrupt line (r/w)
595e8308dd1SSamuel Ortiz }
596e8308dd1SSamuel Ortiz };
597b57cc3d7SRob Bradford registers[11] = (u32::from(subsystem_id) << 16) | u32::from(subsystem_vendor_id);
598e8308dd1SSamuel Ortiz
599eae80438SSebastien Boeuf (
600eae80438SSebastien Boeuf registers,
601eae80438SSebastien Boeuf writable_bits,
602eae80438SSebastien Boeuf [PciBar::default(); NUM_BAR_REGS],
603eae80438SSebastien Boeuf 0,
604eae80438SSebastien Boeuf 0,
605eae80438SSebastien Boeuf false,
606eae80438SSebastien Boeuf None,
607eae80438SSebastien Boeuf None,
608eae80438SSebastien Boeuf )
609eae80438SSebastien Boeuf };
610dc55e459SRob Bradford
611e8308dd1SSamuel Ortiz PciConfiguration {
612e8308dd1SSamuel Ortiz registers,
613e8308dd1SSamuel Ortiz writable_bits,
614dc55e459SRob Bradford bars,
615eae80438SSebastien Boeuf rom_bar_addr,
616eae80438SSebastien Boeuf rom_bar_size,
617eae80438SSebastien Boeuf rom_bar_used,
618eae80438SSebastien Boeuf last_capability,
619eae80438SSebastien Boeuf msix_cap_reg_idx,
6204d98dcb0SSebastien Boeuf msix_config,
621aaf86ef2SBo Chen pending_bar_reprogram: Vec::new(),
622e8308dd1SSamuel Ortiz }
623e8308dd1SSamuel Ortiz }
624e8308dd1SSamuel Ortiz
state(&self) -> PciConfigurationState625e1701f11SSebastien Boeuf fn state(&self) -> PciConfigurationState {
626e1701f11SSebastien Boeuf PciConfigurationState {
627e1701f11SSebastien Boeuf registers: self.registers.to_vec(),
628e1701f11SSebastien Boeuf writable_bits: self.writable_bits.to_vec(),
629dc55e459SRob Bradford bars: self.bars.to_vec(),
630e1701f11SSebastien Boeuf rom_bar_addr: self.rom_bar_addr,
631e1701f11SSebastien Boeuf rom_bar_size: self.rom_bar_size,
632e1701f11SSebastien Boeuf rom_bar_used: self.rom_bar_used,
633e1701f11SSebastien Boeuf last_capability: self.last_capability,
634e1701f11SSebastien Boeuf msix_cap_reg_idx: self.msix_cap_reg_idx,
635e1701f11SSebastien Boeuf }
636e1701f11SSebastien Boeuf }
637e1701f11SSebastien Boeuf
638e8308dd1SSamuel Ortiz /// Reads a 32bit register from `reg_idx` in the register map.
read_reg(&self, reg_idx: usize) -> u32639e8308dd1SSamuel Ortiz pub fn read_reg(&self, reg_idx: usize) -> u32 {
640e8308dd1SSamuel Ortiz *(self.registers.get(reg_idx).unwrap_or(&0xffff_ffff))
641e8308dd1SSamuel Ortiz }
642e8308dd1SSamuel Ortiz
643e8308dd1SSamuel Ortiz /// Writes a 32bit register to `reg_idx` in the register map.
write_reg(&mut self, reg_idx: usize, value: u32)644e8308dd1SSamuel Ortiz pub fn write_reg(&mut self, reg_idx: usize, value: u32) {
645b1571816SSebastien Boeuf let mut mask = self.writable_bits[reg_idx];
646149b61b2SSebastien Boeuf
6476ccd32c9SRob Bradford if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(®_idx) {
648b1571816SSebastien Boeuf // Handle very specific case where the BAR is being written with
64907bad79fSSebastien Boeuf // all 1's to retrieve the BAR size during next BAR reading.
65007bad79fSSebastien Boeuf if value == 0xffff_ffff {
651dc55e459SRob Bradford mask &= self.bars[reg_idx - 4].size;
65207bad79fSSebastien Boeuf }
653149b61b2SSebastien Boeuf } else if reg_idx == ROM_BAR_REG {
65407bad79fSSebastien Boeuf // Handle very specific case where the BAR is being written with
65507bad79fSSebastien Boeuf // all 1's on bits 31-11 to retrieve the BAR size during next BAR
65607bad79fSSebastien Boeuf // reading.
65707bad79fSSebastien Boeuf if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
658b8cfdab8SRob Bradford mask &= self.rom_bar_size;
659b1571816SSebastien Boeuf }
660149b61b2SSebastien Boeuf }
661b1571816SSebastien Boeuf
662e8308dd1SSamuel Ortiz if let Some(r) = self.registers.get_mut(reg_idx) {
663b1571816SSebastien Boeuf *r = (*r & !self.writable_bits[reg_idx]) | (value & mask);
664e8308dd1SSamuel Ortiz } else {
665e8308dd1SSamuel Ortiz warn!("bad PCI register write {}", reg_idx);
666e8308dd1SSamuel Ortiz }
667e8308dd1SSamuel Ortiz }
668e8308dd1SSamuel Ortiz
669e8308dd1SSamuel Ortiz /// Writes a 16bit word to `offset`. `offset` must be 16bit aligned.
write_word(&mut self, offset: usize, value: u16)670e8308dd1SSamuel Ortiz pub fn write_word(&mut self, offset: usize, value: u16) {
671e8308dd1SSamuel Ortiz let shift = match offset % 4 {
672e8308dd1SSamuel Ortiz 0 => 0,
673e8308dd1SSamuel Ortiz 2 => 16,
674e8308dd1SSamuel Ortiz _ => {
675e8308dd1SSamuel Ortiz warn!("bad PCI config write offset {}", offset);
676e8308dd1SSamuel Ortiz return;
677e8308dd1SSamuel Ortiz }
678e8308dd1SSamuel Ortiz };
679e8308dd1SSamuel Ortiz let reg_idx = offset / 4;
680e8308dd1SSamuel Ortiz
681e8308dd1SSamuel Ortiz if let Some(r) = self.registers.get_mut(reg_idx) {
682e8308dd1SSamuel Ortiz let writable_mask = self.writable_bits[reg_idx];
683e8308dd1SSamuel Ortiz let mask = (0xffffu32 << shift) & writable_mask;
684e8308dd1SSamuel Ortiz let shifted_value = (u32::from(value) << shift) & writable_mask;
685e8308dd1SSamuel Ortiz *r = *r & !mask | shifted_value;
686e8308dd1SSamuel Ortiz } else {
687e8308dd1SSamuel Ortiz warn!("bad PCI config write offset {}", offset);
688e8308dd1SSamuel Ortiz }
689e8308dd1SSamuel Ortiz }
690e8308dd1SSamuel Ortiz
691e8308dd1SSamuel Ortiz /// Writes a byte to `offset`.
write_byte(&mut self, offset: usize, value: u8)692e8308dd1SSamuel Ortiz pub fn write_byte(&mut self, offset: usize, value: u8) {
693e8308dd1SSamuel Ortiz self.write_byte_internal(offset, value, true);
694e8308dd1SSamuel Ortiz }
695e8308dd1SSamuel Ortiz
696e8308dd1SSamuel Ortiz /// Writes a byte to `offset`, optionally enforcing read-only bits.
write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool)697e8308dd1SSamuel Ortiz fn write_byte_internal(&mut self, offset: usize, value: u8, apply_writable_mask: bool) {
698e8308dd1SSamuel Ortiz let shift = (offset % 4) * 8;
699e8308dd1SSamuel Ortiz let reg_idx = offset / 4;
700e8308dd1SSamuel Ortiz
701e8308dd1SSamuel Ortiz if let Some(r) = self.registers.get_mut(reg_idx) {
702e8308dd1SSamuel Ortiz let writable_mask = if apply_writable_mask {
703e8308dd1SSamuel Ortiz self.writable_bits[reg_idx]
704e8308dd1SSamuel Ortiz } else {
705e8308dd1SSamuel Ortiz 0xffff_ffff
706e8308dd1SSamuel Ortiz };
707e8308dd1SSamuel Ortiz let mask = (0xffu32 << shift) & writable_mask;
708e8308dd1SSamuel Ortiz let shifted_value = (u32::from(value) << shift) & writable_mask;
709e8308dd1SSamuel Ortiz *r = *r & !mask | shifted_value;
710e8308dd1SSamuel Ortiz } else {
711e8308dd1SSamuel Ortiz warn!("bad PCI config write offset {}", offset);
712e8308dd1SSamuel Ortiz }
713e8308dd1SSamuel Ortiz }
714e8308dd1SSamuel Ortiz
715e8308dd1SSamuel Ortiz /// Adds a region specified by `config`. Configures the specified BAR(s) to
716e8308dd1SSamuel Ortiz /// report this region and size to the guest kernel. Enforces a few constraints
717da95c0d7SSebastien Boeuf /// (i.e, region size must be power of two, register not already used).
add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()>718da95c0d7SSebastien Boeuf pub fn add_pci_bar(&mut self, config: &PciBarConfiguration) -> Result<()> {
719da95c0d7SSebastien Boeuf let bar_idx = config.idx;
720da95c0d7SSebastien Boeuf let reg_idx = BAR0_REG + bar_idx;
721da95c0d7SSebastien Boeuf
722da95c0d7SSebastien Boeuf if self.bars[bar_idx].used {
723da95c0d7SSebastien Boeuf return Err(Error::BarInUse(bar_idx));
724e8308dd1SSamuel Ortiz }
725e8308dd1SSamuel Ortiz
726b41daddcSRuoqing He if !config.size.is_power_of_two() {
727e8308dd1SSamuel Ortiz return Err(Error::BarSizeInvalid(config.size));
728e8308dd1SSamuel Ortiz }
729e8308dd1SSamuel Ortiz
730da95c0d7SSebastien Boeuf if bar_idx >= NUM_BAR_REGS {
731da95c0d7SSebastien Boeuf return Err(Error::BarInvalid(bar_idx));
732e8308dd1SSamuel Ortiz }
733e8308dd1SSamuel Ortiz
734e8308dd1SSamuel Ortiz let end_addr = config
735e8308dd1SSamuel Ortiz .addr
736927861ceSSebastien Boeuf .checked_add(config.size - 1)
73772bb255fSSamuel Ortiz .ok_or(Error::BarAddressInvalid(config.addr, config.size))?;
738e8308dd1SSamuel Ortiz match config.region_type {
739827229d8SRob Bradford PciBarRegionType::Memory32BitRegion | PciBarRegionType::IoRegion => {
740f6cd3bd8SWei Liu if end_addr > u64::from(u32::MAX) {
741e8308dd1SSamuel Ortiz return Err(Error::BarAddressInvalid(config.addr, config.size));
742e8308dd1SSamuel Ortiz }
743b8cfdab8SRob Bradford
744b8cfdab8SRob Bradford // Encode the BAR size as expected by the software running in
745b8cfdab8SRob Bradford // the guest.
746da95c0d7SSebastien Boeuf self.bars[bar_idx].size =
747b8cfdab8SRob Bradford encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
748e8308dd1SSamuel Ortiz }
749e8308dd1SSamuel Ortiz PciBarRegionType::Memory64BitRegion => {
750da95c0d7SSebastien Boeuf if bar_idx + 1 >= NUM_BAR_REGS {
751da95c0d7SSebastien Boeuf return Err(Error::BarInvalid64(bar_idx));
752e8308dd1SSamuel Ortiz }
753e8308dd1SSamuel Ortiz
754da95c0d7SSebastien Boeuf if self.bars[bar_idx + 1].used {
755da95c0d7SSebastien Boeuf return Err(Error::BarInUse64(bar_idx));
756e8308dd1SSamuel Ortiz }
757e8308dd1SSamuel Ortiz
758b8cfdab8SRob Bradford // Encode the BAR size as expected by the software running in
759b8cfdab8SRob Bradford // the guest.
760b8cfdab8SRob Bradford let (bar_size_hi, bar_size_lo) =
761b8cfdab8SRob Bradford encode_64_bits_bar_size(config.size).ok_or(Error::Encode64BarSize)?;
762b8cfdab8SRob Bradford
763da95c0d7SSebastien Boeuf self.registers[reg_idx + 1] = (config.addr >> 32) as u32;
764da95c0d7SSebastien Boeuf self.writable_bits[reg_idx + 1] = 0xffff_ffff;
765da95c0d7SSebastien Boeuf self.bars[bar_idx + 1].addr = self.registers[reg_idx + 1];
766da95c0d7SSebastien Boeuf self.bars[bar_idx].size = bar_size_lo;
767da95c0d7SSebastien Boeuf self.bars[bar_idx + 1].size = bar_size_hi;
768da95c0d7SSebastien Boeuf self.bars[bar_idx + 1].used = true;
769e8308dd1SSamuel Ortiz }
770e8308dd1SSamuel Ortiz }
771e8308dd1SSamuel Ortiz
772e8308dd1SSamuel Ortiz let (mask, lower_bits) = match config.region_type {
773e8308dd1SSamuel Ortiz PciBarRegionType::Memory32BitRegion | PciBarRegionType::Memory64BitRegion => (
774e8308dd1SSamuel Ortiz BAR_MEM_ADDR_MASK,
775e8308dd1SSamuel Ortiz config.prefetchable as u32 | config.region_type as u32,
776e8308dd1SSamuel Ortiz ),
777827229d8SRob Bradford PciBarRegionType::IoRegion => (BAR_IO_ADDR_MASK, config.region_type as u32),
778e8308dd1SSamuel Ortiz };
779e8308dd1SSamuel Ortiz
780da95c0d7SSebastien Boeuf self.registers[reg_idx] = ((config.addr as u32) & mask) | lower_bits;
781da95c0d7SSebastien Boeuf self.writable_bits[reg_idx] = mask;
782da95c0d7SSebastien Boeuf self.bars[bar_idx].addr = self.registers[reg_idx];
783da95c0d7SSebastien Boeuf self.bars[bar_idx].used = true;
784da95c0d7SSebastien Boeuf self.bars[bar_idx].r#type = Some(config.region_type);
785da95c0d7SSebastien Boeuf
786da95c0d7SSebastien Boeuf Ok(())
787e8308dd1SSamuel Ortiz }
788e8308dd1SSamuel Ortiz
789d217089bSSebastien Boeuf /// Adds rom expansion BAR.
add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()>790da95c0d7SSebastien Boeuf pub fn add_pci_rom_bar(&mut self, config: &PciBarConfiguration, active: u32) -> Result<()> {
791da95c0d7SSebastien Boeuf let bar_idx = config.idx;
792da95c0d7SSebastien Boeuf let reg_idx = ROM_BAR_REG;
793da95c0d7SSebastien Boeuf
794d217089bSSebastien Boeuf if self.rom_bar_used {
795da95c0d7SSebastien Boeuf return Err(Error::RomBarInUse(bar_idx));
796d217089bSSebastien Boeuf }
797d217089bSSebastien Boeuf
798b41daddcSRuoqing He if !config.size.is_power_of_two() {
799d217089bSSebastien Boeuf return Err(Error::RomBarSizeInvalid(config.size));
800d217089bSSebastien Boeuf }
801d217089bSSebastien Boeuf
802da95c0d7SSebastien Boeuf if bar_idx != ROM_BAR_IDX {
803da95c0d7SSebastien Boeuf return Err(Error::RomBarInvalid(bar_idx));
804d217089bSSebastien Boeuf }
805d217089bSSebastien Boeuf
806d217089bSSebastien Boeuf let end_addr = config
807d217089bSSebastien Boeuf .addr
808d217089bSSebastien Boeuf .checked_add(config.size - 1)
80972bb255fSSamuel Ortiz .ok_or(Error::RomBarAddressInvalid(config.addr, config.size))?;
810d217089bSSebastien Boeuf
811f6cd3bd8SWei Liu if end_addr > u64::from(u32::MAX) {
812d217089bSSebastien Boeuf return Err(Error::RomBarAddressInvalid(config.addr, config.size));
813d217089bSSebastien Boeuf }
814d217089bSSebastien Boeuf
815da95c0d7SSebastien Boeuf self.registers[reg_idx] = (config.addr as u32) | active;
816da95c0d7SSebastien Boeuf self.writable_bits[reg_idx] = ROM_BAR_ADDR_MASK;
817da95c0d7SSebastien Boeuf self.rom_bar_addr = self.registers[reg_idx];
818b8cfdab8SRob Bradford self.rom_bar_size =
819b8cfdab8SRob Bradford encode_32_bits_bar_size(config.size as u32).ok_or(Error::Encode32BarSize)?;
820d217089bSSebastien Boeuf self.rom_bar_used = true;
821da95c0d7SSebastien Boeuf
822da95c0d7SSebastien Boeuf Ok(())
823d217089bSSebastien Boeuf }
824d217089bSSebastien Boeuf
8254f8054faSSebastien Boeuf /// Returns the address of the given BAR region.
get_bar_addr(&self, bar_num: usize) -> u648264f8054faSSebastien Boeuf pub fn get_bar_addr(&self, bar_num: usize) -> u64 {
827e8308dd1SSamuel Ortiz let bar_idx = BAR0_REG + bar_num;
828e8308dd1SSamuel Ortiz
829dc55e459SRob Bradford let mut addr = u64::from(self.bars[bar_num].addr & self.writable_bits[bar_idx]);
8304f8054faSSebastien Boeuf
831dc55e459SRob Bradford if let Some(bar_type) = self.bars[bar_num].r#type {
8324f8054faSSebastien Boeuf if bar_type == PciBarRegionType::Memory64BitRegion {
833dc55e459SRob Bradford addr |= u64::from(self.bars[bar_num + 1].addr) << 32;
8344f8054faSSebastien Boeuf }
835e8308dd1SSamuel Ortiz }
836e8308dd1SSamuel Ortiz
8374f8054faSSebastien Boeuf addr
838b67e0b3dSSebastien Boeuf }
839b67e0b3dSSebastien Boeuf
840e8308dd1SSamuel Ortiz /// Configures the IRQ line and pin used by this device.
set_irq(&mut self, line: u8, pin: PciInterruptPin)841e8308dd1SSamuel Ortiz pub fn set_irq(&mut self, line: u8, pin: PciInterruptPin) {
842e8308dd1SSamuel Ortiz // `pin` is 1-based in the pci config space.
843e8308dd1SSamuel Ortiz let pin_idx = (pin as u32) + 1;
844e8308dd1SSamuel Ortiz self.registers[INTERRUPT_LINE_PIN_REG] = (self.registers[INTERRUPT_LINE_PIN_REG]
845e8308dd1SSamuel Ortiz & 0xffff_0000)
846e8308dd1SSamuel Ortiz | (pin_idx << 8)
847e8308dd1SSamuel Ortiz | u32::from(line);
848e8308dd1SSamuel Ortiz }
849e8308dd1SSamuel Ortiz
850e8308dd1SSamuel Ortiz /// Adds the capability `cap_data` to the list of capabilities.
851e8308dd1SSamuel Ortiz /// `cap_data` should include the two-byte PCI capability header (type, next),
852e8308dd1SSamuel Ortiz /// but not populate it. Correct values will be generated automatically based
853e8308dd1SSamuel Ortiz /// on `cap_data.id()`.
add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize>854e8308dd1SSamuel Ortiz pub fn add_capability(&mut self, cap_data: &dyn PciCapability) -> Result<usize> {
855e8308dd1SSamuel Ortiz let total_len = cap_data.bytes().len();
856e8308dd1SSamuel Ortiz // Check that the length is valid.
857e8308dd1SSamuel Ortiz if cap_data.bytes().is_empty() {
858e8308dd1SSamuel Ortiz return Err(Error::CapabilityEmpty);
859e8308dd1SSamuel Ortiz }
860e8308dd1SSamuel Ortiz let (cap_offset, tail_offset) = match self.last_capability {
861e8308dd1SSamuel Ortiz Some((offset, len)) => (Self::next_dword(offset, len), offset + 1),
862e8308dd1SSamuel Ortiz None => (FIRST_CAPABILITY_OFFSET, CAPABILITY_LIST_HEAD_OFFSET),
863e8308dd1SSamuel Ortiz };
864e8308dd1SSamuel Ortiz let end_offset = cap_offset
865e8308dd1SSamuel Ortiz .checked_add(total_len)
86672bb255fSSamuel Ortiz .ok_or(Error::CapabilitySpaceFull(total_len))?;
867e8308dd1SSamuel Ortiz if end_offset > CAPABILITY_MAX_OFFSET {
868e8308dd1SSamuel Ortiz return Err(Error::CapabilitySpaceFull(total_len));
869e8308dd1SSamuel Ortiz }
870e8308dd1SSamuel Ortiz self.registers[STATUS_REG] |= STATUS_REG_CAPABILITIES_USED_MASK;
871e8308dd1SSamuel Ortiz self.write_byte_internal(tail_offset, cap_offset as u8, false);
872e8308dd1SSamuel Ortiz self.write_byte_internal(cap_offset, cap_data.id() as u8, false);
873e8308dd1SSamuel Ortiz self.write_byte_internal(cap_offset + 1, 0, false); // Next pointer.
874e8308dd1SSamuel Ortiz for (i, byte) in cap_data.bytes().iter().enumerate() {
875e8308dd1SSamuel Ortiz self.write_byte_internal(cap_offset + i + 2, *byte, false);
876e8308dd1SSamuel Ortiz }
877e8308dd1SSamuel Ortiz self.last_capability = Some((cap_offset, total_len));
8784d98dcb0SSebastien Boeuf
87923fb4fa2SSebastien Boeuf match cap_data.id() {
88023fb4fa2SSebastien Boeuf PciCapabilityId::MessageSignalledInterrupts => {
88123fb4fa2SSebastien Boeuf self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
88223fb4fa2SSebastien Boeuf }
88323fb4fa2SSebastien Boeuf PciCapabilityId::MsiX => {
8844d98dcb0SSebastien Boeuf self.msix_cap_reg_idx = Some(cap_offset / 4);
885a116add9SRob Bradford self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK;
8864d98dcb0SSebastien Boeuf }
88723fb4fa2SSebastien Boeuf _ => {}
88823fb4fa2SSebastien Boeuf }
8894d98dcb0SSebastien Boeuf
890e8308dd1SSamuel Ortiz Ok(cap_offset)
891e8308dd1SSamuel Ortiz }
892e8308dd1SSamuel Ortiz
893e8308dd1SSamuel Ortiz // Find the next aligned offset after the one given.
next_dword(offset: usize, len: usize) -> usize894e8308dd1SSamuel Ortiz fn next_dword(offset: usize, len: usize) -> usize {
895e8308dd1SSamuel Ortiz let next = offset + len;
896e8308dd1SSamuel Ortiz (next + 3) & !3
897e8308dd1SSamuel Ortiz }
898e8308dd1SSamuel Ortiz
write_config_register( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Vec<BarReprogrammingParams>899cb52cf91SBo Chen pub fn write_config_register(
900cb52cf91SBo Chen &mut self,
901cb52cf91SBo Chen reg_idx: usize,
902cb52cf91SBo Chen offset: u64,
903cb52cf91SBo Chen data: &[u8],
904aaf86ef2SBo Chen ) -> Vec<BarReprogrammingParams> {
905e8308dd1SSamuel Ortiz if offset as usize + data.len() > 4 {
906aaf86ef2SBo Chen return Vec::new();
907e8308dd1SSamuel Ortiz }
908e8308dd1SSamuel Ortiz
9094d98dcb0SSebastien Boeuf // Handle potential write to MSI-X message control register
9104d98dcb0SSebastien Boeuf if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx {
9114d98dcb0SSebastien Boeuf if let Some(msix_config) = &self.msix_config {
9124d98dcb0SSebastien Boeuf if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 {
9134d98dcb0SSebastien Boeuf msix_config
9144d98dcb0SSebastien Boeuf .lock()
9154d98dcb0SSebastien Boeuf .unwrap()
9164d98dcb0SSebastien Boeuf .set_msg_ctl(LittleEndian::read_u16(data));
9179c6e7c4aSRob Bradford } else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
9189c6e7c4aSRob Bradford msix_config
9199c6e7c4aSRob Bradford .lock()
9209c6e7c4aSRob Bradford .unwrap()
9219c6e7c4aSRob Bradford .set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
9224d98dcb0SSebastien Boeuf }
9234d98dcb0SSebastien Boeuf }
9244d98dcb0SSebastien Boeuf }
9254d98dcb0SSebastien Boeuf
926e8308dd1SSamuel Ortiz match data.len() {
927e8308dd1SSamuel Ortiz 1 => self.write_byte(reg_idx * 4 + offset as usize, data[0]),
928e8308dd1SSamuel Ortiz 2 => self.write_word(
929e8308dd1SSamuel Ortiz reg_idx * 4 + offset as usize,
930b57cc3d7SRob Bradford u16::from(data[0]) | (u16::from(data[1]) << 8),
931e8308dd1SSamuel Ortiz ),
932e8308dd1SSamuel Ortiz 4 => self.write_reg(reg_idx, LittleEndian::read_u32(data)),
933e8308dd1SSamuel Ortiz _ => (),
934e8308dd1SSamuel Ortiz }
935cb52cf91SBo Chen
936aaf86ef2SBo Chen if let Some(param) = self.detect_bar_reprogramming(reg_idx, data) {
937aaf86ef2SBo Chen self.pending_bar_reprogram.push(param);
938aaf86ef2SBo Chen }
939aaf86ef2SBo Chen
940aaf86ef2SBo Chen if !self.pending_bar_reprogram.is_empty() {
941aaf86ef2SBo Chen // Return bar reprogramming only if the MSE bit is enabled;
942aaf86ef2SBo Chen if self.read_config_register(COMMAND_REG) & COMMAND_REG_MEMORY_SPACE_MASK
943aaf86ef2SBo Chen == COMMAND_REG_MEMORY_SPACE_MASK
944aaf86ef2SBo Chen {
945aaf86ef2SBo Chen info!(
946aaf86ef2SBo Chen "BAR reprogramming parameter is returned: {:x?}",
947aaf86ef2SBo Chen self.pending_bar_reprogram
948aaf86ef2SBo Chen );
949aaf86ef2SBo Chen return self.pending_bar_reprogram.drain(..).collect();
950aaf86ef2SBo Chen } else {
951aaf86ef2SBo Chen info!(
952aaf86ef2SBo Chen "MSE bit is disabled. No BAR reprogramming parameter is returned: {:x?}",
953aaf86ef2SBo Chen self.pending_bar_reprogram
954aaf86ef2SBo Chen );
955aaf86ef2SBo Chen }
956aaf86ef2SBo Chen }
957aaf86ef2SBo Chen
958aaf86ef2SBo Chen Vec::new()
959e8308dd1SSamuel Ortiz }
960e8308dd1SSamuel Ortiz
read_config_register(&self, reg_idx: usize) -> u32961e8308dd1SSamuel Ortiz pub fn read_config_register(&self, reg_idx: usize) -> u32 {
962e8308dd1SSamuel Ortiz self.read_reg(reg_idx)
963e8308dd1SSamuel Ortiz }
964149b61b2SSebastien Boeuf
detect_bar_reprogramming( &mut self, reg_idx: usize, data: &[u8], ) -> Option<BarReprogrammingParams>965cb52cf91SBo Chen fn detect_bar_reprogramming(
966149b61b2SSebastien Boeuf &mut self,
967149b61b2SSebastien Boeuf reg_idx: usize,
968149b61b2SSebastien Boeuf data: &[u8],
969149b61b2SSebastien Boeuf ) -> Option<BarReprogrammingParams> {
970149b61b2SSebastien Boeuf if data.len() != 4 {
971149b61b2SSebastien Boeuf return None;
972149b61b2SSebastien Boeuf }
973149b61b2SSebastien Boeuf
974149b61b2SSebastien Boeuf let value = LittleEndian::read_u32(data);
975149b61b2SSebastien Boeuf
976149b61b2SSebastien Boeuf let mask = self.writable_bits[reg_idx];
9776ccd32c9SRob Bradford if (BAR0_REG..BAR0_REG + NUM_BAR_REGS).contains(®_idx) {
9787c457378SSebastien Boeuf // Ignore the case where the BAR size is being asked for.
9797c457378SSebastien Boeuf if value == 0xffff_ffff {
9807c457378SSebastien Boeuf return None;
9817c457378SSebastien Boeuf }
9827c457378SSebastien Boeuf
983149b61b2SSebastien Boeuf let bar_idx = reg_idx - 4;
984149b61b2SSebastien Boeuf // Handle special case where the address being written is
985149b61b2SSebastien Boeuf // different from the address initially provided. This is a
986149b61b2SSebastien Boeuf // BAR reprogramming case which needs to be properly caught.
987dc55e459SRob Bradford if let Some(bar_type) = self.bars[bar_idx].r#type {
9887c457378SSebastien Boeuf // In case of 64 bits memory BAR, we don't do anything until
9897c457378SSebastien Boeuf // the upper BAR is modified, otherwise we would be moving the
9907c457378SSebastien Boeuf // BAR to a wrong location in memory.
9917c457378SSebastien Boeuf if bar_type == PciBarRegionType::Memory64BitRegion {
9927c457378SSebastien Boeuf return None;
9937c457378SSebastien Boeuf }
9947c457378SSebastien Boeuf
9957c457378SSebastien Boeuf // Ignore the case where the value is unchanged.
9967c457378SSebastien Boeuf if (value & mask) == (self.bars[bar_idx].addr & mask) {
997c2ae3805SSebastien Boeuf return None;
998c2ae3805SSebastien Boeuf }
999c2ae3805SSebastien Boeuf
100064e217cfSRob Bradford info!(
100164e217cfSRob Bradford "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
100259f98a2eSBo Chen bar_idx, self.bars[bar_idx].addr, value
1003149b61b2SSebastien Boeuf );
1004dc55e459SRob Bradford let old_base = u64::from(self.bars[bar_idx].addr & mask);
1005149b61b2SSebastien Boeuf let new_base = u64::from(value & mask);
1006b8cfdab8SRob Bradford let len = u64::from(
1007dc55e459SRob Bradford decode_32_bits_bar_size(self.bars[bar_idx].size)
1008b8cfdab8SRob Bradford .ok_or(Error::Decode32BarSize)
1009b8cfdab8SRob Bradford .unwrap(),
1010b8cfdab8SRob Bradford );
1011149b61b2SSebastien Boeuf let region_type = bar_type;
1012149b61b2SSebastien Boeuf
1013dc55e459SRob Bradford self.bars[bar_idx].addr = value;
1014149b61b2SSebastien Boeuf
1015149b61b2SSebastien Boeuf return Some(BarReprogrammingParams {
1016149b61b2SSebastien Boeuf old_base,
1017149b61b2SSebastien Boeuf new_base,
1018149b61b2SSebastien Boeuf len,
1019149b61b2SSebastien Boeuf region_type,
1020149b61b2SSebastien Boeuf });
1021149b61b2SSebastien Boeuf } else if (reg_idx > BAR0_REG)
10227c457378SSebastien Boeuf && ((self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1])
1023dc55e459SRob Bradford != (self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1])
10247c457378SSebastien Boeuf || (value & mask) != (self.bars[bar_idx].addr & mask))
1025149b61b2SSebastien Boeuf {
102664e217cfSRob Bradford info!(
102764e217cfSRob Bradford "Detected BAR reprogramming: (BAR {}) 0x{:x}->0x{:x}",
102859f98a2eSBo Chen bar_idx, self.bars[bar_idx].addr, value
1029149b61b2SSebastien Boeuf );
1030b57cc3d7SRob Bradford let old_base = (u64::from(self.bars[bar_idx].addr & mask) << 32)
1031dc55e459SRob Bradford | u64::from(self.bars[bar_idx - 1].addr & self.writable_bits[reg_idx - 1]);
1032b57cc3d7SRob Bradford let new_base = (u64::from(value & mask) << 32)
1033149b61b2SSebastien Boeuf | u64::from(self.registers[reg_idx - 1] & self.writable_bits[reg_idx - 1]);
10347c457378SSebastien Boeuf let len =
10357c457378SSebastien Boeuf decode_64_bits_bar_size(self.bars[bar_idx].size, self.bars[bar_idx - 1].size)
1036b8cfdab8SRob Bradford .ok_or(Error::Decode64BarSize)
1037b8cfdab8SRob Bradford .unwrap();
1038149b61b2SSebastien Boeuf let region_type = PciBarRegionType::Memory64BitRegion;
1039149b61b2SSebastien Boeuf
1040dc55e459SRob Bradford self.bars[bar_idx].addr = value;
1041dc55e459SRob Bradford self.bars[bar_idx - 1].addr = self.registers[reg_idx - 1];
1042149b61b2SSebastien Boeuf
1043149b61b2SSebastien Boeuf return Some(BarReprogrammingParams {
1044149b61b2SSebastien Boeuf old_base,
1045149b61b2SSebastien Boeuf new_base,
1046149b61b2SSebastien Boeuf len,
1047149b61b2SSebastien Boeuf region_type,
1048149b61b2SSebastien Boeuf });
1049149b61b2SSebastien Boeuf }
1050149b61b2SSebastien Boeuf } else if reg_idx == ROM_BAR_REG && (value & mask) != (self.rom_bar_addr & mask) {
105107bad79fSSebastien Boeuf // Ignore the case where the BAR size is being asked for.
105207bad79fSSebastien Boeuf if value & ROM_BAR_ADDR_MASK == ROM_BAR_ADDR_MASK {
105307bad79fSSebastien Boeuf return None;
105407bad79fSSebastien Boeuf }
105507bad79fSSebastien Boeuf
105664e217cfSRob Bradford info!(
105759f98a2eSBo Chen "Detected ROM BAR reprogramming: (Expansion ROM BAR) 0x{:x}->0x{:x}",
105859f98a2eSBo Chen self.rom_bar_addr, value
1059149b61b2SSebastien Boeuf );
1060149b61b2SSebastien Boeuf let old_base = u64::from(self.rom_bar_addr & mask);
1061149b61b2SSebastien Boeuf let new_base = u64::from(value & mask);
1062b8cfdab8SRob Bradford let len = u64::from(
1063b8cfdab8SRob Bradford decode_32_bits_bar_size(self.rom_bar_size)
1064b8cfdab8SRob Bradford .ok_or(Error::Decode32BarSize)
1065b8cfdab8SRob Bradford .unwrap(),
1066b8cfdab8SRob Bradford );
1067149b61b2SSebastien Boeuf let region_type = PciBarRegionType::Memory32BitRegion;
1068149b61b2SSebastien Boeuf
1069149b61b2SSebastien Boeuf self.rom_bar_addr = value;
1070149b61b2SSebastien Boeuf
1071149b61b2SSebastien Boeuf return Some(BarReprogrammingParams {
1072149b61b2SSebastien Boeuf old_base,
1073149b61b2SSebastien Boeuf new_base,
1074149b61b2SSebastien Boeuf len,
1075149b61b2SSebastien Boeuf region_type,
1076149b61b2SSebastien Boeuf });
1077149b61b2SSebastien Boeuf }
1078149b61b2SSebastien Boeuf
1079149b61b2SSebastien Boeuf None
1080149b61b2SSebastien Boeuf }
10818da7c13eSBo Chen
pending_bar_reprogram(&self) -> Vec<BarReprogrammingParams>10828da7c13eSBo Chen pub(crate) fn pending_bar_reprogram(&self) -> Vec<BarReprogrammingParams> {
10838da7c13eSBo Chen self.pending_bar_reprogram.clone()
10848da7c13eSBo Chen }
10858da7c13eSBo Chen
clear_pending_bar_reprogram(&mut self)10868da7c13eSBo Chen pub(crate) fn clear_pending_bar_reprogram(&mut self) {
10878da7c13eSBo Chen self.pending_bar_reprogram = Vec::new();
10888da7c13eSBo Chen }
1089e8308dd1SSamuel Ortiz }
1090e8308dd1SSamuel Ortiz
1091e1701f11SSebastien Boeuf impl Pausable for PciConfiguration {}
1092e1701f11SSebastien Boeuf
1093e1701f11SSebastien Boeuf impl Snapshottable for PciConfiguration {
id(&self) -> String1094e1701f11SSebastien Boeuf fn id(&self) -> String {
1095eae80438SSebastien Boeuf String::from(PCI_CONFIGURATION_ID)
1096e1701f11SSebastien Boeuf }
1097e1701f11SSebastien Boeuf
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>1098871138d5SSebastien Boeuf fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
109910ab87d6SRob Bradford Snapshot::new_from_state(&self.state())
1100e1701f11SSebastien Boeuf }
1101e1701f11SSebastien Boeuf }
1102e1701f11SSebastien Boeuf
1103e8308dd1SSamuel Ortiz impl Default for PciBarConfiguration {
default() -> Self1104e8308dd1SSamuel Ortiz fn default() -> Self {
1105e8308dd1SSamuel Ortiz PciBarConfiguration {
1106da95c0d7SSebastien Boeuf idx: 0,
1107e8308dd1SSamuel Ortiz addr: 0,
1108e8308dd1SSamuel Ortiz size: 0,
1109e8308dd1SSamuel Ortiz region_type: PciBarRegionType::Memory64BitRegion,
1110e8308dd1SSamuel Ortiz prefetchable: PciBarPrefetchable::NotPrefetchable,
1111e8308dd1SSamuel Ortiz }
1112e8308dd1SSamuel Ortiz }
1113e8308dd1SSamuel Ortiz }
1114e8308dd1SSamuel Ortiz
1115e8308dd1SSamuel Ortiz impl PciBarConfiguration {
new( idx: usize, size: u64, region_type: PciBarRegionType, prefetchable: PciBarPrefetchable, ) -> Self1116e8308dd1SSamuel Ortiz pub fn new(
1117da95c0d7SSebastien Boeuf idx: usize,
1118e8308dd1SSamuel Ortiz size: u64,
1119e8308dd1SSamuel Ortiz region_type: PciBarRegionType,
1120e8308dd1SSamuel Ortiz prefetchable: PciBarPrefetchable,
1121e8308dd1SSamuel Ortiz ) -> Self {
1122e8308dd1SSamuel Ortiz PciBarConfiguration {
1123da95c0d7SSebastien Boeuf idx,
1124e8308dd1SSamuel Ortiz addr: 0,
1125e8308dd1SSamuel Ortiz size,
1126e8308dd1SSamuel Ortiz region_type,
1127e8308dd1SSamuel Ortiz prefetchable,
1128e8308dd1SSamuel Ortiz }
1129e8308dd1SSamuel Ortiz }
1130e8308dd1SSamuel Ortiz
1131221c1f1bSRob Bradford #[must_use]
set_index(mut self, idx: usize) -> Self1132da95c0d7SSebastien Boeuf pub fn set_index(mut self, idx: usize) -> Self {
1133da95c0d7SSebastien Boeuf self.idx = idx;
1134e8308dd1SSamuel Ortiz self
1135e8308dd1SSamuel Ortiz }
1136e8308dd1SSamuel Ortiz
1137221c1f1bSRob Bradford #[must_use]
set_address(mut self, addr: u64) -> Self1138e8308dd1SSamuel Ortiz pub fn set_address(mut self, addr: u64) -> Self {
1139e8308dd1SSamuel Ortiz self.addr = addr;
1140e8308dd1SSamuel Ortiz self
1141e8308dd1SSamuel Ortiz }
1142e8308dd1SSamuel Ortiz
1143221c1f1bSRob Bradford #[must_use]
set_size(mut self, size: u64) -> Self1144e8308dd1SSamuel Ortiz pub fn set_size(mut self, size: u64) -> Self {
1145e8308dd1SSamuel Ortiz self.size = size;
1146e8308dd1SSamuel Ortiz self
1147e8308dd1SSamuel Ortiz }
1148e8308dd1SSamuel Ortiz
1149221c1f1bSRob Bradford #[must_use]
set_region_type(mut self, region_type: PciBarRegionType) -> Self1150185b1082SSebastien Boeuf pub fn set_region_type(mut self, region_type: PciBarRegionType) -> Self {
1151185b1082SSebastien Boeuf self.region_type = region_type;
1152185b1082SSebastien Boeuf self
1153185b1082SSebastien Boeuf }
115489218b6dSSebastien Boeuf
1155868d1f69SSteven Dake #[must_use]
set_prefetchable(mut self, prefetchable: PciBarPrefetchable) -> Self1156868d1f69SSteven Dake pub fn set_prefetchable(mut self, prefetchable: PciBarPrefetchable) -> Self {
1157868d1f69SSteven Dake self.prefetchable = prefetchable;
1158868d1f69SSteven Dake self
1159868d1f69SSteven Dake }
1160868d1f69SSteven Dake
idx(&self) -> usize116189218b6dSSebastien Boeuf pub fn idx(&self) -> usize {
116289218b6dSSebastien Boeuf self.idx
116389218b6dSSebastien Boeuf }
116489218b6dSSebastien Boeuf
addr(&self) -> u64116589218b6dSSebastien Boeuf pub fn addr(&self) -> u64 {
116689218b6dSSebastien Boeuf self.addr
116789218b6dSSebastien Boeuf }
116889218b6dSSebastien Boeuf
size(&self) -> u64116989218b6dSSebastien Boeuf pub fn size(&self) -> u64 {
117089218b6dSSebastien Boeuf self.size
117189218b6dSSebastien Boeuf }
117289218b6dSSebastien Boeuf
region_type(&self) -> PciBarRegionType117389218b6dSSebastien Boeuf pub fn region_type(&self) -> PciBarRegionType {
117489218b6dSSebastien Boeuf self.region_type
117589218b6dSSebastien Boeuf }
117611e9f433SSebastien Boeuf
prefetchable(&self) -> PciBarPrefetchable117711e9f433SSebastien Boeuf pub fn prefetchable(&self) -> PciBarPrefetchable {
117811e9f433SSebastien Boeuf self.prefetchable
117911e9f433SSebastien Boeuf }
1180e8308dd1SSamuel Ortiz }
1181e8308dd1SSamuel Ortiz
1182e8308dd1SSamuel Ortiz #[cfg(test)]
1183e8308dd1SSamuel Ortiz mod tests {
1184e8308dd1SSamuel Ortiz use vm_memory::ByteValued;
1185e8308dd1SSamuel Ortiz
1186e8308dd1SSamuel Ortiz use super::*;
1187e8308dd1SSamuel Ortiz
11882e22b8bcSWei Liu #[repr(C, packed)]
1189e8308dd1SSamuel Ortiz #[derive(Clone, Copy, Default)]
1190e8308dd1SSamuel Ortiz #[allow(dead_code)]
1191e8308dd1SSamuel Ortiz struct TestCap {
1192e8308dd1SSamuel Ortiz len: u8,
1193e8308dd1SSamuel Ortiz foo: u8,
1194e8308dd1SSamuel Ortiz }
1195e8308dd1SSamuel Ortiz
1196d2d6eb05SWei Liu // SAFETY: All members are simple numbers and any value is valid.
1197e8308dd1SSamuel Ortiz unsafe impl ByteValued for TestCap {}
1198e8308dd1SSamuel Ortiz
1199e8308dd1SSamuel Ortiz impl PciCapability for TestCap {
bytes(&self) -> &[u8]1200e8308dd1SSamuel Ortiz fn bytes(&self) -> &[u8] {
1201e8308dd1SSamuel Ortiz self.as_slice()
1202e8308dd1SSamuel Ortiz }
1203e8308dd1SSamuel Ortiz
id(&self) -> PciCapabilityId1204827229d8SRob Bradford fn id(&self) -> PciCapabilityId {
1205827229d8SRob Bradford PciCapabilityId::VendorSpecific
1206e8308dd1SSamuel Ortiz }
1207e8308dd1SSamuel Ortiz }
1208e8308dd1SSamuel Ortiz
1209e8308dd1SSamuel Ortiz #[test]
add_capability()1210e8308dd1SSamuel Ortiz fn add_capability() {
1211e8308dd1SSamuel Ortiz let mut cfg = PciConfiguration::new(
1212e8308dd1SSamuel Ortiz 0x1234,
1213e8308dd1SSamuel Ortiz 0x5678,
12149bd5ec89SRob Bradford 0x1,
1215e8308dd1SSamuel Ortiz PciClassCode::MultimediaController,
1216e8308dd1SSamuel Ortiz &PciMultimediaSubclass::AudioController,
1217e8308dd1SSamuel Ortiz None,
1218e8308dd1SSamuel Ortiz PciHeaderType::Device,
1219e8308dd1SSamuel Ortiz 0xABCD,
1220e8308dd1SSamuel Ortiz 0x2468,
12219a178716SRob Bradford None,
1222eae80438SSebastien Boeuf None,
1223e8308dd1SSamuel Ortiz );
1224e8308dd1SSamuel Ortiz
1225e8308dd1SSamuel Ortiz // Add two capabilities with different contents.
1226846505d3SSebastien Boeuf let cap1 = TestCap { len: 4, foo: 0xAA };
1227e8308dd1SSamuel Ortiz let cap1_offset = cfg.add_capability(&cap1).unwrap();
1228e8308dd1SSamuel Ortiz assert_eq!(cap1_offset % 4, 0);
1229e8308dd1SSamuel Ortiz
1230e8308dd1SSamuel Ortiz let cap2 = TestCap {
1231e8308dd1SSamuel Ortiz len: 0x04,
1232e8308dd1SSamuel Ortiz foo: 0x55,
1233e8308dd1SSamuel Ortiz };
1234e8308dd1SSamuel Ortiz let cap2_offset = cfg.add_capability(&cap2).unwrap();
1235e8308dd1SSamuel Ortiz assert_eq!(cap2_offset % 4, 0);
1236e8308dd1SSamuel Ortiz
1237e8308dd1SSamuel Ortiz // The capability list head should be pointing to cap1.
1238e8308dd1SSamuel Ortiz let cap_ptr = cfg.read_reg(CAPABILITY_LIST_HEAD_OFFSET / 4) & 0xFF;
1239e8308dd1SSamuel Ortiz assert_eq!(cap1_offset, cap_ptr as usize);
1240e8308dd1SSamuel Ortiz
1241e8308dd1SSamuel Ortiz // Verify the contents of the capabilities.
1242e8308dd1SSamuel Ortiz let cap1_data = cfg.read_reg(cap1_offset / 4);
1243e8308dd1SSamuel Ortiz assert_eq!(cap1_data & 0xFF, 0x09); // capability ID
1244e8308dd1SSamuel Ortiz assert_eq!((cap1_data >> 8) & 0xFF, cap2_offset as u32); // next capability pointer
1245e8308dd1SSamuel Ortiz assert_eq!((cap1_data >> 16) & 0xFF, 0x04); // cap1.len
1246e8308dd1SSamuel Ortiz assert_eq!((cap1_data >> 24) & 0xFF, 0xAA); // cap1.foo
1247e8308dd1SSamuel Ortiz
1248e8308dd1SSamuel Ortiz let cap2_data = cfg.read_reg(cap2_offset / 4);
1249e8308dd1SSamuel Ortiz assert_eq!(cap2_data & 0xFF, 0x09); // capability ID
1250e8308dd1SSamuel Ortiz assert_eq!((cap2_data >> 8) & 0xFF, 0x00); // next capability pointer
1251e8308dd1SSamuel Ortiz assert_eq!((cap2_data >> 16) & 0xFF, 0x04); // cap2.len
1252e8308dd1SSamuel Ortiz assert_eq!((cap2_data >> 24) & 0xFF, 0x55); // cap2.foo
1253e8308dd1SSamuel Ortiz }
1254e8308dd1SSamuel Ortiz
1255e8308dd1SSamuel Ortiz #[derive(Copy, Clone)]
1256827229d8SRob Bradford enum TestPi {
1257e8308dd1SSamuel Ortiz Test = 0x5a,
1258e8308dd1SSamuel Ortiz }
1259e8308dd1SSamuel Ortiz
1260827229d8SRob Bradford impl PciProgrammingInterface for TestPi {
get_register_value(&self) -> u81261e8308dd1SSamuel Ortiz fn get_register_value(&self) -> u8 {
1262e8308dd1SSamuel Ortiz *self as u8
1263e8308dd1SSamuel Ortiz }
1264e8308dd1SSamuel Ortiz }
1265e8308dd1SSamuel Ortiz
1266e8308dd1SSamuel Ortiz #[test]
class_code()1267e8308dd1SSamuel Ortiz fn class_code() {
1268e8308dd1SSamuel Ortiz let cfg = PciConfiguration::new(
1269e8308dd1SSamuel Ortiz 0x1234,
1270e8308dd1SSamuel Ortiz 0x5678,
12719bd5ec89SRob Bradford 0x1,
1272e8308dd1SSamuel Ortiz PciClassCode::MultimediaController,
1273e8308dd1SSamuel Ortiz &PciMultimediaSubclass::AudioController,
1274827229d8SRob Bradford Some(&TestPi::Test),
1275e8308dd1SSamuel Ortiz PciHeaderType::Device,
1276e8308dd1SSamuel Ortiz 0xABCD,
1277e8308dd1SSamuel Ortiz 0x2468,
12789a178716SRob Bradford None,
1279eae80438SSebastien Boeuf None,
1280e8308dd1SSamuel Ortiz );
1281e8308dd1SSamuel Ortiz
1282e8308dd1SSamuel Ortiz let class_reg = cfg.read_reg(2);
1283e8308dd1SSamuel Ortiz let class_code = (class_reg >> 24) & 0xFF;
1284e8308dd1SSamuel Ortiz let subclass = (class_reg >> 16) & 0xFF;
1285e8308dd1SSamuel Ortiz let prog_if = (class_reg >> 8) & 0xFF;
1286e8308dd1SSamuel Ortiz assert_eq!(class_code, 0x04);
1287e8308dd1SSamuel Ortiz assert_eq!(subclass, 0x01);
1288e8308dd1SSamuel Ortiz assert_eq!(prog_if, 0x5a);
1289e8308dd1SSamuel Ortiz }
1290e8308dd1SSamuel Ortiz }
1291