Skip to content

Commit 1d5c3d0

Browse files
committed
refactor(pci): move PCI emulation logic in vmm mod
The implementation of the PCI emulation components is heavily Firecracker opinionated. Move those inside a module of `vmm` crate and leave in the `pci` module only type definitions which can easily be reused across VMMs. We also take advantage of this refactoring to remove in various places the usage of `std::io::Error` as error types returned by emulation logic. Signed-off-by: Babis Chalios <[email protected]>
1 parent b1e2224 commit 1d5c3d0

File tree

10 files changed

+635
-627
lines changed

10 files changed

+635
-627
lines changed

src/pci/src/lib.rs

Lines changed: 340 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,15 @@
66
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
77

88
//! Implements pci devices and busses.
9-
#[macro_use]
10-
extern crate log;
119
12-
mod bus;
13-
mod configuration;
14-
mod device;
15-
mod msix;
10+
extern crate log;
1611

1712
use std::fmt::{self, Debug, Display};
1813
use std::num::ParseIntError;
1914
use std::str::FromStr;
2015

2116
use serde::de::Visitor;
22-
23-
pub use self::bus::{PciBus, PciConfigIo, PciConfigMmio, PciRoot, PciRootError};
24-
pub use self::configuration::{
25-
PciBarPrefetchable, PciBarRegionType, PciCapability, PciCapabilityId, PciClassCode,
26-
PciConfiguration, PciConfigurationState, PciExpressCapabilityId, PciHeaderType,
27-
PciMassStorageSubclass, PciNetworkControllerSubclass, PciSerialBusSubClass, PciSubclass,
28-
PCI_CONFIGURATION_ID,
29-
};
30-
pub use self::device::{
31-
BarReprogrammingParams, DeviceRelocation, Error as PciDeviceError, PciDevice,
32-
};
33-
pub use self::msix::{Error as MsixError, MsixCap, MsixConfig, MsixConfigState, MsixTableEntry};
17+
use serde::{Deserialize, Serialize};
3418

3519
/// PCI has four interrupt pins A->D.
3620
#[derive(Copy, Clone)]
@@ -47,11 +31,6 @@ impl PciInterruptPin {
4731
}
4832
}
4933

50-
#[cfg(target_arch = "x86_64")]
51-
pub const PCI_CONFIG_IO_PORT: u64 = 0xcf8;
52-
#[cfg(target_arch = "x86_64")]
53-
pub const PCI_CONFIG_IO_PORT_SIZE: u64 = 0x8;
54-
5534
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd)]
5635
pub struct PciBdf(u32);
5736

@@ -202,6 +181,344 @@ impl FromStr for PciBdf {
202181
}
203182
}
204183

184+
/// Represents the types of PCI headers allowed in the configuration registers.
185+
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
186+
pub enum PciHeaderType {
187+
Device,
188+
Bridge,
189+
}
190+
191+
/// Classes of PCI nodes.
192+
#[allow(dead_code)]
193+
#[derive(Copy, Clone)]
194+
pub enum PciClassCode {
195+
TooOld,
196+
MassStorage,
197+
NetworkController,
198+
DisplayController,
199+
MultimediaController,
200+
MemoryController,
201+
BridgeDevice,
202+
SimpleCommunicationController,
203+
BaseSystemPeripheral,
204+
InputDevice,
205+
DockingStation,
206+
Processor,
207+
SerialBusController,
208+
WirelessController,
209+
IntelligentIoController,
210+
EncryptionController,
211+
DataAcquisitionSignalProcessing,
212+
Other = 0xff,
213+
}
214+
215+
impl PciClassCode {
216+
pub fn get_register_value(self) -> u8 {
217+
self as u8
218+
}
219+
}
220+
221+
/// A PCI subclass. Each class in `PciClassCode` can specify a unique set of subclasses. This trait
222+
/// is implemented by each subclass. It allows use of a trait object to generate configurations.
223+
pub trait PciSubclass {
224+
/// Convert this subclass to the value used in the PCI specification.
225+
fn get_register_value(&self) -> u8;
226+
}
227+
228+
/// Subclasses of the MultimediaController class.
229+
#[allow(dead_code)]
230+
#[derive(Copy, Clone)]
231+
pub enum PciMultimediaSubclass {
232+
VideoController = 0x00,
233+
AudioController = 0x01,
234+
TelephonyDevice = 0x02,
235+
AudioDevice = 0x03,
236+
Other = 0x80,
237+
}
238+
239+
impl PciSubclass for PciMultimediaSubclass {
240+
fn get_register_value(&self) -> u8 {
241+
*self as u8
242+
}
243+
}
244+
245+
/// Subclasses of the BridgeDevice
246+
#[allow(dead_code)]
247+
#[derive(Copy, Clone)]
248+
pub enum PciBridgeSubclass {
249+
HostBridge = 0x00,
250+
IsaBridge = 0x01,
251+
EisaBridge = 0x02,
252+
McaBridge = 0x03,
253+
PciToPciBridge = 0x04,
254+
PcmciaBridge = 0x05,
255+
NuBusBridge = 0x06,
256+
CardBusBridge = 0x07,
257+
RacEwayBridge = 0x08,
258+
PciToPciSemiTransparentBridge = 0x09,
259+
InfiniBrandToPciHostBridge = 0x0a,
260+
OtherBridgeDevice = 0x80,
261+
}
262+
263+
impl PciSubclass for PciBridgeSubclass {
264+
fn get_register_value(&self) -> u8 {
265+
*self as u8
266+
}
267+
}
268+
269+
/// Subclass of the SerialBus
270+
#[allow(dead_code)]
271+
#[derive(Copy, Clone)]
272+
pub enum PciSerialBusSubClass {
273+
Firewire = 0x00,
274+
Accessbus = 0x01,
275+
Ssa = 0x02,
276+
Usb = 0x03,
277+
}
278+
279+
impl PciSubclass for PciSerialBusSubClass {
280+
fn get_register_value(&self) -> u8 {
281+
*self as u8
282+
}
283+
}
284+
285+
/// Mass Storage Sub Classes
286+
#[allow(dead_code)]
287+
#[derive(Copy, Clone)]
288+
pub enum PciMassStorageSubclass {
289+
ScsiStorage = 0x00,
290+
IdeInterface = 0x01,
291+
FloppyController = 0x02,
292+
IpiController = 0x03,
293+
RaidController = 0x04,
294+
AtaController = 0x05,
295+
SataController = 0x06,
296+
SerialScsiController = 0x07,
297+
NvmController = 0x08,
298+
MassStorage = 0x80,
299+
}
300+
301+
impl PciSubclass for PciMassStorageSubclass {
302+
fn get_register_value(&self) -> u8 {
303+
*self as u8
304+
}
305+
}
306+
307+
/// Network Controller Sub Classes
308+
#[allow(dead_code)]
309+
#[derive(Copy, Clone)]
310+
pub enum PciNetworkControllerSubclass {
311+
EthernetController = 0x00,
312+
TokenRingController = 0x01,
313+
FddiController = 0x02,
314+
AtmController = 0x03,
315+
IsdnController = 0x04,
316+
WorldFipController = 0x05,
317+
PicmgController = 0x06,
318+
InfinibandController = 0x07,
319+
FabricController = 0x08,
320+
NetworkController = 0x80,
321+
}
322+
323+
impl PciSubclass for PciNetworkControllerSubclass {
324+
fn get_register_value(&self) -> u8 {
325+
*self as u8
326+
}
327+
}
328+
329+
/// Types of PCI capabilities.
330+
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
331+
#[allow(dead_code)]
332+
#[allow(non_camel_case_types)]
333+
#[repr(u8)]
334+
pub enum PciCapabilityId {
335+
ListId = 0,
336+
PowerManagement = 0x01,
337+
AcceleratedGraphicsPort = 0x02,
338+
VitalProductData = 0x03,
339+
SlotIdentification = 0x04,
340+
MessageSignalledInterrupts = 0x05,
341+
CompactPciHotSwap = 0x06,
342+
PciX = 0x07,
343+
HyperTransport = 0x08,
344+
VendorSpecific = 0x09,
345+
Debugport = 0x0A,
346+
CompactPciCentralResourceControl = 0x0B,
347+
PciStandardHotPlugController = 0x0C,
348+
BridgeSubsystemVendorDeviceId = 0x0D,
349+
AgpTargetPciPcibridge = 0x0E,
350+
SecureDevice = 0x0F,
351+
PciExpress = 0x10,
352+
MsiX = 0x11,
353+
SataDataIndexConf = 0x12,
354+
PciAdvancedFeatures = 0x13,
355+
PciEnhancedAllocation = 0x14,
356+
}
357+
358+
impl From<u8> for PciCapabilityId {
359+
fn from(c: u8) -> Self {
360+
match c {
361+
0 => PciCapabilityId::ListId,
362+
0x01 => PciCapabilityId::PowerManagement,
363+
0x02 => PciCapabilityId::AcceleratedGraphicsPort,
364+
0x03 => PciCapabilityId::VitalProductData,
365+
0x04 => PciCapabilityId::SlotIdentification,
366+
0x05 => PciCapabilityId::MessageSignalledInterrupts,
367+
0x06 => PciCapabilityId::CompactPciHotSwap,
368+
0x07 => PciCapabilityId::PciX,
369+
0x08 => PciCapabilityId::HyperTransport,
370+
0x09 => PciCapabilityId::VendorSpecific,
371+
0x0A => PciCapabilityId::Debugport,
372+
0x0B => PciCapabilityId::CompactPciCentralResourceControl,
373+
0x0C => PciCapabilityId::PciStandardHotPlugController,
374+
0x0D => PciCapabilityId::BridgeSubsystemVendorDeviceId,
375+
0x0E => PciCapabilityId::AgpTargetPciPcibridge,
376+
0x0F => PciCapabilityId::SecureDevice,
377+
0x10 => PciCapabilityId::PciExpress,
378+
0x11 => PciCapabilityId::MsiX,
379+
0x12 => PciCapabilityId::SataDataIndexConf,
380+
0x13 => PciCapabilityId::PciAdvancedFeatures,
381+
0x14 => PciCapabilityId::PciEnhancedAllocation,
382+
_ => PciCapabilityId::ListId,
383+
}
384+
}
385+
}
386+
387+
/// Types of PCI Express capabilities.
388+
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
389+
#[allow(dead_code)]
390+
#[repr(u16)]
391+
pub enum PciExpressCapabilityId {
392+
NullCapability = 0x0000,
393+
AdvancedErrorReporting = 0x0001,
394+
VirtualChannelMultiFunctionVirtualChannelNotPresent = 0x0002,
395+
DeviceSerialNumber = 0x0003,
396+
PowerBudgeting = 0x0004,
397+
RootComplexLinkDeclaration = 0x0005,
398+
RootComplexInternalLinkControl = 0x0006,
399+
RootComplexEventCollectorEndpointAssociation = 0x0007,
400+
MultiFunctionVirtualChannel = 0x0008,
401+
VirtualChannelMultiFunctionVirtualChannelPresent = 0x0009,
402+
RootComplexRegisterBlock = 0x000a,
403+
VendorSpecificExtendedCapability = 0x000b,
404+
ConfigurationAccessCorrelation = 0x000c,
405+
AccessControlServices = 0x000d,
406+
AlternativeRoutingIdentificationInterpretation = 0x000e,
407+
AddressTranslationServices = 0x000f,
408+
SingleRootIoVirtualization = 0x0010,
409+
DeprecatedMultiRootIoVirtualization = 0x0011,
410+
Multicast = 0x0012,
411+
PageRequestInterface = 0x0013,
412+
ReservedForAmd = 0x0014,
413+
ResizeableBar = 0x0015,
414+
DynamicPowerAllocation = 0x0016,
415+
ThpRequester = 0x0017,
416+
LatencyToleranceReporting = 0x0018,
417+
SecondaryPciExpress = 0x0019,
418+
ProtocolMultiplexing = 0x001a,
419+
ProcessAddressSpaceId = 0x001b,
420+
LnRequester = 0x001c,
421+
DownstreamPortContainment = 0x001d,
422+
L1PmSubstates = 0x001e,
423+
PrecisionTimeMeasurement = 0x001f,
424+
PciExpressOverMphy = 0x0020,
425+
FRSQueueing = 0x0021,
426+
ReadinessTimeReporting = 0x0022,
427+
DesignatedVendorSpecificExtendedCapability = 0x0023,
428+
VfResizeableBar = 0x0024,
429+
DataLinkFeature = 0x0025,
430+
PhysicalLayerSixteenGts = 0x0026,
431+
LaneMarginingAtTheReceiver = 0x0027,
432+
HierarchyId = 0x0028,
433+
NativePcieEnclosureManagement = 0x0029,
434+
PhysicalLayerThirtyTwoGts = 0x002a,
435+
AlternateProtocol = 0x002b,
436+
SystemFirmwareIntermediary = 0x002c,
437+
ShadowFunctions = 0x002d,
438+
DataObjectExchange = 0x002e,
439+
Reserved = 0x002f,
440+
ExtendedCapabilitiesAbsence = 0xffff,
441+
}
442+
443+
impl From<u16> for PciExpressCapabilityId {
444+
fn from(c: u16) -> Self {
445+
match c {
446+
0x0000 => PciExpressCapabilityId::NullCapability,
447+
0x0001 => PciExpressCapabilityId::AdvancedErrorReporting,
448+
0x0002 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelNotPresent,
449+
0x0003 => PciExpressCapabilityId::DeviceSerialNumber,
450+
0x0004 => PciExpressCapabilityId::PowerBudgeting,
451+
0x0005 => PciExpressCapabilityId::RootComplexLinkDeclaration,
452+
0x0006 => PciExpressCapabilityId::RootComplexInternalLinkControl,
453+
0x0007 => PciExpressCapabilityId::RootComplexEventCollectorEndpointAssociation,
454+
0x0008 => PciExpressCapabilityId::MultiFunctionVirtualChannel,
455+
0x0009 => PciExpressCapabilityId::VirtualChannelMultiFunctionVirtualChannelPresent,
456+
0x000a => PciExpressCapabilityId::RootComplexRegisterBlock,
457+
0x000b => PciExpressCapabilityId::VendorSpecificExtendedCapability,
458+
0x000c => PciExpressCapabilityId::ConfigurationAccessCorrelation,
459+
0x000d => PciExpressCapabilityId::AccessControlServices,
460+
0x000e => PciExpressCapabilityId::AlternativeRoutingIdentificationInterpretation,
461+
0x000f => PciExpressCapabilityId::AddressTranslationServices,
462+
0x0010 => PciExpressCapabilityId::SingleRootIoVirtualization,
463+
0x0011 => PciExpressCapabilityId::DeprecatedMultiRootIoVirtualization,
464+
0x0012 => PciExpressCapabilityId::Multicast,
465+
0x0013 => PciExpressCapabilityId::PageRequestInterface,
466+
0x0014 => PciExpressCapabilityId::ReservedForAmd,
467+
0x0015 => PciExpressCapabilityId::ResizeableBar,
468+
0x0016 => PciExpressCapabilityId::DynamicPowerAllocation,
469+
0x0017 => PciExpressCapabilityId::ThpRequester,
470+
0x0018 => PciExpressCapabilityId::LatencyToleranceReporting,
471+
0x0019 => PciExpressCapabilityId::SecondaryPciExpress,
472+
0x001a => PciExpressCapabilityId::ProtocolMultiplexing,
473+
0x001b => PciExpressCapabilityId::ProcessAddressSpaceId,
474+
0x001c => PciExpressCapabilityId::LnRequester,
475+
0x001d => PciExpressCapabilityId::DownstreamPortContainment,
476+
0x001e => PciExpressCapabilityId::L1PmSubstates,
477+
0x001f => PciExpressCapabilityId::PrecisionTimeMeasurement,
478+
0x0020 => PciExpressCapabilityId::PciExpressOverMphy,
479+
0x0021 => PciExpressCapabilityId::FRSQueueing,
480+
0x0022 => PciExpressCapabilityId::ReadinessTimeReporting,
481+
0x0023 => PciExpressCapabilityId::DesignatedVendorSpecificExtendedCapability,
482+
0x0024 => PciExpressCapabilityId::VfResizeableBar,
483+
0x0025 => PciExpressCapabilityId::DataLinkFeature,
484+
0x0026 => PciExpressCapabilityId::PhysicalLayerSixteenGts,
485+
0x0027 => PciExpressCapabilityId::LaneMarginingAtTheReceiver,
486+
0x0028 => PciExpressCapabilityId::HierarchyId,
487+
0x0029 => PciExpressCapabilityId::NativePcieEnclosureManagement,
488+
0x002a => PciExpressCapabilityId::PhysicalLayerThirtyTwoGts,
489+
0x002b => PciExpressCapabilityId::AlternateProtocol,
490+
0x002c => PciExpressCapabilityId::SystemFirmwareIntermediary,
491+
0x002d => PciExpressCapabilityId::ShadowFunctions,
492+
0x002e => PciExpressCapabilityId::DataObjectExchange,
493+
0xffff => PciExpressCapabilityId::ExtendedCapabilitiesAbsence,
494+
_ => PciExpressCapabilityId::Reserved,
495+
}
496+
}
497+
}
498+
499+
/// See pci_regs.h in kernel
500+
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
501+
pub enum PciBarRegionType {
502+
Memory32BitRegion = 0,
503+
IoRegion = 0x01,
504+
Memory64BitRegion = 0x04,
505+
}
506+
507+
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
508+
pub enum PciBarPrefetchable {
509+
NotPrefetchable = 0,
510+
Prefetchable = 0x08,
511+
}
512+
513+
impl From<PciBarPrefetchable> for bool {
514+
fn from(val: PciBarPrefetchable) -> Self {
515+
match val {
516+
PciBarPrefetchable::NotPrefetchable => false,
517+
PciBarPrefetchable::Prefetchable => true,
518+
}
519+
}
520+
}
521+
205522
#[cfg(test)]
206523
mod tests {
207524
use super::*;

0 commit comments

Comments
 (0)