Skip to content

Commit 0ecb17b

Browse files
committed
pci: add support for PCIe segment
Add a PCIe segment which includes a single PCIe root port and a bus. At the moment, we always enabled it. things left to do: * enable it only if `--pci` is passed as a command line argument * add a test that checks the presence of the root port in the guest (lspci) * ensure it works for Aarch64. Signed-off-by: Babis Chalios <[email protected]>
1 parent 95add78 commit 0ecb17b

File tree

12 files changed

+570
-16
lines changed

12 files changed

+570
-16
lines changed

Cargo.lock

Lines changed: 3 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/firecracker/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ fn main_exec() -> Result<(), MainError> {
449449
/// the default the jailer would set).
450450
///
451451
/// We do this resizing because the kernel default is 64, with a reallocation happening whenever
452-
/// the tabel fills up. This was happening for some larger microVMs, and reallocating the
452+
/// the table fills up. This was happening for some larger microVMs, and reallocating the
453453
/// fdtable while a lot of file descriptors are active (due to being eventfds/timerfds registered
454454
/// to epoll) incurs a penalty of 30ms-70ms on the snapshot restore path.
455455
fn resize_fdtable() -> Result<(), ResizeFdTableError> {

src/pci/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ libc = "0.2.172"
1414
log = "0.4.27"
1515
serde = { version = "1.0.219", features = ["derive"] }
1616
thiserror = "2.0.12"
17-
vm-allocator = "0.1.1"
17+
vm-allocator = { git = "https://github.com/rust-vmm/vm-allocator" }
1818
vm-device = { path = "../vm-device" }
1919
vm-memory = { version = "0.16.1", features = [
2020
"backend-mmap",

src/vmm/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ userfaultfd = "0.8.1"
4444
utils = { path = "../utils" }
4545
uuid = "1.16.0"
4646
vhost = { version = "0.13.0", features = ["vhost-user-frontend"] }
47-
vm-allocator = { path = "../../../rust-vmm/vm-allocator" }
47+
vm-allocator = { git = "https://github.com/rust-vmm/vm-allocator" }
4848
vm-device = { path = "../vm-device" }
4949
vm-memory = { version = "0.16.1", features = [
5050
"backend-mmap",

src/vmm/src/acpi/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ impl AcpiTableWriter<'_> {
9090
.acpi_devices
9191
.append_aml_bytes(&mut dsdt_data)?;
9292

93+
if let Some(pci_segment) = &device_manager.pci_devices.pci_segment {
94+
pci_segment.append_aml_bytes(&mut dsdt_data)?;
95+
}
96+
9397
// Architecture specific DSDT data
9498
setup_arch_dsdt(&mut dsdt_data)?;
9599

src/vmm/src/arch/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ pub use crate::arch::x86_64::{
4747
layout::IOAPIC_ADDR, layout::IRQ_BASE, layout::IRQ_MAX, layout::MEM_32BIT_DEVICES_SIZE,
4848
layout::MEM_32BIT_DEVICES_START, layout::MEM_64BIT_DEVICES_SIZE,
4949
layout::MEM_64BIT_DEVICES_START, layout::MMIO32_MEM_SIZE, layout::MMIO32_MEM_START,
50-
layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START, load_kernel,
50+
layout::PCI_MMCONFIG_SIZE, layout::PCI_MMCONFIG_START,
51+
layout::PCI_MMIO_CONFIG_SIZE_PER_SEGMENT, layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START,
52+
load_kernel,
5153
};
5254
use crate::utils::u64_to_usize;
5355

src/vmm/src/builder.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use crate::cpu_config::templates::{
2424
};
2525
#[cfg(target_arch = "aarch64")]
2626
use crate::device_manager::AttachLegacyMmioDeviceError;
27+
use crate::device_manager::pci_mngr::PciManagerError;
2728
use crate::device_manager::{
2829
AttachMmioDeviceError, AttachVmgenidError, DeviceManager, DevicePersistError, DeviceRestoreArgs,
2930
};
@@ -71,6 +72,8 @@ pub enum StartMicrovmError {
7172
CreateLegacyDevice(device_manager::legacy::LegacyDeviceError),
7273
/// Error creating VMGenID device: {0}
7374
CreateVMGenID(VmGenIdError),
75+
/// Error enabling PCIe support: {0}
76+
EnablePciDevices(#[from] PciManagerError),
7477
/// Error enabling pvtime on vcpu: {0}
7578
#[cfg(target_arch = "aarch64")]
7679
EnablePVTime(crate::arch::VcpuArchError),
@@ -214,6 +217,8 @@ pub fn build_microvm_for_boot(
214217
.map(|vcpu| vcpu.copy_kvm_vcpu_fd(vmm.vm()))
215218
.collect::<Result<Vec<_>, _>>()?;
216219

220+
vmm.device_manager.enable_pci()?;
221+
217222
// The boot timer device needs to be the first device attached in order
218223
// to maintain the same MMIO address referenced in the documentation
219224
// and tests.

src/vmm/src/device_manager/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use linux_loader::loader::Cmdline;
1717
use log::error;
1818
use mmio::{MMIODeviceManager, MmioError};
1919
use pci::DeviceRelocation;
20+
use pci_mngr::{PciDevices, PciManagerError};
2021
use persist::{ACPIDeviceManagerConstructorArgs, MMIODevManagerConstructorArgs};
2122
use resources::ResourceAllocator;
2223
use serde::{Deserialize, Serialize};
@@ -44,6 +45,8 @@ pub mod acpi;
4445
pub mod legacy;
4546
/// Memory Mapped I/O Manager.
4647
pub mod mmio;
48+
/// PCIe device manager
49+
pub mod pci_mngr;
4750
/// Device managers (de)serialization support.
4851
pub mod persist;
4952
/// Resource manager for devices.
@@ -105,6 +108,8 @@ pub struct DeviceManager {
105108
pub legacy_devices: PortIODeviceManager,
106109
/// ACPI devices
107110
pub acpi_devices: ACPIDeviceManager,
111+
/// PCIe devices
112+
pub pci_devices: PciDevices,
108113
}
109114

110115
impl DeviceManager {
@@ -166,6 +171,7 @@ impl DeviceManager {
166171
#[cfg(target_arch = "x86_64")]
167172
legacy_devices,
168173
acpi_devices: ACPIDeviceManager::new(),
174+
pci_devices: PciDevices::new(),
169175
})
170176
}
171177

@@ -245,6 +251,12 @@ impl DeviceManager {
245251
.register_mmio_rtc(&self.resource_allocator, rtc, None)?;
246252
Ok(())
247253
}
254+
255+
/// Enables PCIe support for Firecracker devices
256+
pub fn enable_pci(&mut self) -> Result<(), PciManagerError> {
257+
self.pci_devices
258+
.attach_pci_segment(&self.resource_allocator)
259+
}
248260
}
249261

250262
impl DeviceRelocation for DeviceManager {
@@ -381,6 +393,7 @@ pub(crate) mod tests {
381393
pub(crate) fn default_device_manager() -> DeviceManager {
382394
let mmio_devices = MMIODeviceManager::new();
383395
let acpi_devices = ACPIDeviceManager::new();
396+
let pci_devices = PciDevices::new();
384397
let resource_allocator = Arc::new(ResourceAllocator::new().unwrap());
385398

386399
#[cfg(target_arch = "x86_64")]
@@ -400,6 +413,7 @@ pub(crate) mod tests {
400413
#[cfg(target_arch = "x86_64")]
401414
legacy_devices,
402415
acpi_devices,
416+
pci_devices,
403417
}
404418
}
405419

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use std::sync::Arc;
5+
6+
use vm_device::BusError;
7+
8+
use super::resources::ResourceAllocator;
9+
use crate::devices::pci::PciSegment;
10+
11+
#[derive(Debug, Default)]
12+
pub struct PciDevices {
13+
/// PCIe segment of the VMM, if PCI is enabled. We currently support a single PCIe segment.
14+
pub pci_segment: Option<PciSegment>,
15+
}
16+
17+
#[derive(Debug, thiserror::Error, displaydoc::Display)]
18+
pub enum PciManagerError {
19+
/// Resource allocation error: {0}
20+
ResourceAllocation(#[from] vm_allocator::Error),
21+
/// Bus error: {0}
22+
Bus(#[from] BusError),
23+
}
24+
25+
impl PciDevices {
26+
pub fn new() -> Self {
27+
Default::default()
28+
}
29+
30+
pub fn attach_pci_segment(
31+
&mut self,
32+
resource_allocator: &Arc<ResourceAllocator>,
33+
) -> Result<(), PciManagerError> {
34+
// We only support a single PCIe segment. Calling this function twice is a Firecracker
35+
// internal error.
36+
assert!(self.pci_segment.is_none());
37+
38+
let irqs = resource_allocator.allocate_gsi(8)?;
39+
let mut pci_irq_slots = [0u8; 32];
40+
for i in 0..32 {
41+
pci_irq_slots[i] = irqs[i % 8].try_into().unwrap();
42+
}
43+
44+
let pci_segment = PciSegment::new(0, resource_allocator, &pci_irq_slots)?;
45+
self.pci_segment = Some(pci_segment);
46+
47+
Ok(())
48+
}
49+
}

src/vmm/src/devices/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77

88
//! Emulates virtual and hardware devices.
99
10+
#![allow(unused)]
11+
1012
use std::io;
1113

1214
pub mod acpi;
1315
pub mod legacy;
16+
pub mod pci;
1417
pub mod pseudo;
1518
pub mod virtio;
1619

0 commit comments

Comments
 (0)