Skip to content

Commit f84e8a5

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, the PCIe segment is always enabled. Later commit will make it optional and enable it only when a command line argument flag is passed to Firecracker binary. Signed-off-by: Babis Chalios <[email protected]>
1 parent 971a28d commit f84e8a5

File tree

9 files changed

+545
-2
lines changed

9 files changed

+545
-2
lines changed

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/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

5355
/// Types of devices that can get attached to this platform.

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
@@ -16,6 +16,7 @@ use legacy::{LegacyDeviceError, PortIODeviceManager};
1616
use linux_loader::loader::Cmdline;
1717
use log::error;
1818
use mmio::{MMIODeviceManager, MmioError};
19+
use pci_mngr::{PciDevices, PciManagerError};
1920
use persist::{ACPIDeviceManagerConstructorArgs, MMIODevManagerConstructorArgs};
2021
use resources::ResourceAllocator;
2122
use serde::{Deserialize, Serialize};
@@ -43,6 +44,8 @@ pub mod acpi;
4344
pub mod legacy;
4445
/// Memory Mapped I/O Manager.
4546
pub mod mmio;
47+
/// PCIe device manager
48+
pub mod pci_mngr;
4649
/// Device managers (de)serialization support.
4750
pub mod persist;
4851
/// Resource manager for devices.
@@ -104,6 +107,8 @@ pub struct DeviceManager {
104107
pub legacy_devices: PortIODeviceManager,
105108
/// ACPI devices
106109
pub acpi_devices: ACPIDeviceManager,
110+
/// PCIe devices
111+
pub pci_devices: PciDevices,
107112
}
108113

109114
impl DeviceManager {
@@ -165,6 +170,7 @@ impl DeviceManager {
165170
#[cfg(target_arch = "x86_64")]
166171
legacy_devices,
167172
acpi_devices: ACPIDeviceManager::new(),
173+
pci_devices: PciDevices::new(),
168174
})
169175
}
170176

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

249261
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
@@ -367,6 +379,7 @@ pub(crate) mod tests {
367379
pub(crate) fn default_device_manager() -> DeviceManager {
368380
let mmio_devices = MMIODeviceManager::new();
369381
let acpi_devices = ACPIDeviceManager::new();
382+
let pci_devices = PciDevices::new();
370383
let resource_allocator = Arc::new(ResourceAllocator::new().unwrap());
371384

372385
#[cfg(target_arch = "x86_64")]
@@ -386,6 +399,7 @@ pub(crate) mod tests {
386399
#[cfg(target_arch = "x86_64")]
387400
legacy_devices,
388401
acpi_devices,
402+
pci_devices,
389403
}
390404
}
391405

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
// Currently we don't assign any IRQs to PCI devices. We will be using MSI-X interrupts
39+
// only.
40+
let pci_segment = PciSegment::new(0, resource_allocator, &[0u8; 32])?;
41+
self.pci_segment = Some(pci_segment);
42+
43+
Ok(())
44+
}
45+
}

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

src/vmm/src/devices/pci/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
pub mod pci_segment;
5+
6+
pub use pci_segment::*;

0 commit comments

Comments
 (0)