Scarlet implements PCI/PCIe bus support using ECAM (Enhanced Configuration Access Mechanism), the standard configuration-space access method for PCI Express on RISC-V and ARM platforms.
kernel/src/device/pci/
├── mod.rs – PciAddress, PciBus (core types)
├── config.rs – PciConfig (ECAM-based config-space access)
├── device.rs – PciDeviceInfo (device properties, DeviceInfo impl)
├── driver.rs – PciDeviceDriver, PciDeviceId (driver matching)
└── scan.rs – Bus enumeration and device scanning
FDT / ACPI
│ ecam_base, ecam_size
▼
PciBus ──────────────────────────────────────────
│ │
│ scan() │
▼ │
PciConfig ── ECAM MMIO read/write ──► Config Space │
│ │
▼ │
PciDeviceInfo ──► DeviceManager ──► PciDeviceDriver │
(vendor/device ID, class, BARs) (probe/remove) │
────────────────────────────────────────────────────┘
Represents a PCI device location: { segment, bus, device, function }.
ECAM offset: (bus << 20) | (device << 15) | (function << 12) — each function receives 4 KB of config space.
Central manager initialized with the ECAM base physical address and size from the device tree:
let pci_bus = PciBus::new(ecam_base, ecam_size);
pci_bus.scan_and_register(); // enumerate → register with DeviceManagerECAM is lazily mapped via vm::ioremap on first access.
Provides 8/16/32-bit read/write to configuration-space registers through the mapped ECAM region.
Holds device properties discovered during enumeration:
- Vendor ID, Device ID
- Class code (base class, subclass, interface)
- Subsystem IDs
- BAR addresses
- Interrupt pin/line
Implements the DeviceInfo trait so that DeviceManager can match devices to drivers generically.
Wraps an ID table (PciDeviceId) and probe/remove callbacks. Supports:
- Exact match: vendor + device ID
- Class match: class code with mask (e.g., match all network controllers)
let driver = PciDeviceDriver::new(
"my-driver",
vec![PciDeviceId::new(0x8086, 0x1234)],
|device| { /* probe */ Ok(()) },
|device| { /* remove */ Ok(()) },
);
DeviceManager::get_mut_manager()
.register_driver(Box::new(driver), DriverPriority::Standard);- Platform init reads ECAM base/size from FDT.
PciBus::scan_and_register()walks bus/dev/func.- Each valid device becomes a
PciDeviceInfo, registered withDeviceManager. - Registered
PciDeviceDrivers are matched and probed automatically.
- VirtIO over PCI (network, block, GPU, input, RNG, etc.)
- xHCI USB host controllers
- Any PCI device with a registered driver