Skip to content

Commit 2813996

Browse files
Swchexitroypat
authored andcommitted
fix: Correct GSI numbering for aarch64 to resolve device limit issues
On aarch64, Linux expects device tree interrupts (GSIs) to start at 0, as it internally adds an offset of 32 for SPIs. Firecracker previously defined IRQ_BASE as 32, unintentionally causing a double offset and limiting the maximum number of attachable devices to 64. This commit introduces new constants, GSI_BASE and GSI_MAX, properly adjusted for aarch64, with GSIs starting at 1 (since GSI 0 is disallowed by device_manager/mmio.rs). These changes ensure interrupts are numbered correctly, resolving the issue and allowing an aarch64 VM to handle up to 95 devices. Additional adjustments are made to tests to reflect this correction. Signed-off-by: Sheng-Wei (Way) Chen <[email protected]>
1 parent 5ce383e commit 2813996

File tree

5 files changed

+28
-11
lines changed

5 files changed

+28
-11
lines changed

src/vmm/src/arch/aarch64/layout.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,15 @@ pub const IRQ_MAX: u32 = 128;
8080
/// First usable interrupt on aarch64.
8181
pub const IRQ_BASE: u32 = 32;
8282

83+
// The Linux kernel automatically shifts the GSI by 32 if it is an SPI,
84+
// allowing us to start numbering from 0 instead of 32.
85+
// But device_manager/mmio.rs states that 0 is not allowed for GSIs
86+
// So we start with 1 instead.
87+
/// The first usable GSI on aarch64.
88+
pub const GSI_BASE: u32 = 1;
89+
90+
/// The maximum usable GSI on aarch64.
91+
pub const GSI_MAX: u32 = IRQ_MAX - IRQ_BASE - 1;
92+
8393
/// Below this address will reside the GIC, above this address will reside the MMIO devices.
8494
pub const MAPPED_IO_START: u64 = 1 << 30; // 1 GB

src/vmm/src/arch/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ pub use aarch64::vm::{ArchVm, ArchVmError, VmState};
2222
pub use aarch64::{
2323
ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START, arch_memory_regions,
2424
configure_system_for_boot, get_kernel_start, initrd_load_addr, layout::CMDLINE_MAX_SIZE,
25-
layout::IRQ_BASE, layout::IRQ_MAX, layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START,
26-
load_kernel,
25+
layout::GSI_BASE, layout::GSI_MAX, layout::IRQ_BASE, layout::IRQ_MAX, layout::SYSTEM_MEM_SIZE,
26+
layout::SYSTEM_MEM_START, load_kernel,
2727
};
2828

2929
/// Module for x86_64 related functionality.
@@ -41,8 +41,9 @@ pub use x86_64::vm::{ArchVm, ArchVmError, VmState};
4141
pub use crate::arch::x86_64::{
4242
ConfigurationError, MMIO_MEM_SIZE, MMIO_MEM_START, arch_memory_regions,
4343
configure_system_for_boot, get_kernel_start, initrd_load_addr, layout::APIC_ADDR,
44-
layout::CMDLINE_MAX_SIZE, layout::IOAPIC_ADDR, layout::IRQ_BASE, layout::IRQ_MAX,
45-
layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START, load_kernel,
44+
layout::CMDLINE_MAX_SIZE, layout::GSI_BASE, layout::GSI_MAX, layout::IOAPIC_ADDR,
45+
layout::IRQ_BASE, layout::IRQ_MAX, layout::SYSTEM_MEM_SIZE, layout::SYSTEM_MEM_START,
46+
load_kernel,
4647
};
4748

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

src/vmm/src/arch/x86_64/layout.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ pub const IRQ_BASE: u32 = 5;
2424
/// Last usable IRQ ID for virtio device interrupts on x86_64.
2525
pub const IRQ_MAX: u32 = 23;
2626

27+
/// The first usable GSI on x86_64 is the same as the first usable IRQ ID.
28+
pub const GSI_BASE: u32 = IRQ_BASE;
29+
30+
/// The maximum usable GSI on x86_64 is the same as the last usable IRQ ID.
31+
pub const GSI_MAX: u32 = IRQ_MAX;
32+
2733
/// Address for the TSS setup.
2834
pub const KVM_TSS_ADDRESS: u64 = 0xfffb_d000;
2935

src/vmm/src/device_manager/mmio.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -834,7 +834,7 @@ mod tests {
834834
let device_info = device_manager
835835
.allocate_mmio_resources(&mut resource_allocator, 1)
836836
.unwrap();
837-
assert_eq!(device_info.irq.unwrap().get(), crate::arch::IRQ_BASE);
837+
assert_eq!(device_info.irq.unwrap().get(), crate::arch::GSI_BASE);
838838
}
839839

840840
#[test]

src/vmm/src/device_manager/resources.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ impl ResourceAllocator {
2727
/// Create a new resource allocator for Firecracker devices
2828
pub fn new() -> Result<Self, vm_allocator::Error> {
2929
Ok(Self {
30-
gsi_allocator: IdAllocator::new(arch::IRQ_BASE, arch::IRQ_MAX)?,
30+
gsi_allocator: IdAllocator::new(arch::GSI_BASE, arch::GSI_MAX)?,
3131
mmio_memory: AddressAllocator::new(arch::MMIO_MEM_START, arch::MMIO_MEM_SIZE)?,
3232
system_memory: AddressAllocator::new(arch::SYSTEM_MEM_START, arch::SYSTEM_MEM_SIZE)?,
3333
})
@@ -102,7 +102,7 @@ mod tests {
102102
use super::ResourceAllocator;
103103
use crate::arch;
104104

105-
const MAX_IRQS: u32 = arch::IRQ_MAX - arch::IRQ_BASE + 1;
105+
const MAX_IRQS: u32 = arch::GSI_MAX - arch::GSI_BASE + 1;
106106

107107
#[test]
108108
fn test_allocate_gsi() {
@@ -117,7 +117,7 @@ mod tests {
117117
// But allocating all of them at once should work
118118
assert_eq!(
119119
allocator.allocate_gsi(MAX_IRQS),
120-
Ok((arch::IRQ_BASE..=arch::IRQ_MAX).collect::<Vec<_>>())
120+
Ok((arch::GSI_BASE..=arch::GSI_MAX).collect::<Vec<_>>())
121121
);
122122
// And now we ran out of GSIs
123123
assert_eq!(
@@ -129,16 +129,16 @@ mod tests {
129129

130130
let mut allocator = ResourceAllocator::new().unwrap();
131131
// We should be able to allocate 1 GSI
132-
assert_eq!(allocator.allocate_gsi(1), Ok(vec![arch::IRQ_BASE]));
132+
assert_eq!(allocator.allocate_gsi(1), Ok(vec![arch::GSI_BASE]));
133133
// We can't allocate MAX_IRQS any more
134134
assert_eq!(
135135
allocator.allocate_gsi(MAX_IRQS),
136136
Err(vm_allocator::Error::ResourceNotAvailable)
137137
);
138138
// We can allocate another one and it should be the second available
139-
assert_eq!(allocator.allocate_gsi(1), Ok(vec![arch::IRQ_BASE + 1]));
139+
assert_eq!(allocator.allocate_gsi(1), Ok(vec![arch::GSI_BASE + 1]));
140140
// Let's allocate the rest in a loop
141-
for i in arch::IRQ_BASE + 2..=arch::IRQ_MAX {
141+
for i in arch::GSI_BASE + 2..=arch::GSI_MAX {
142142
assert_eq!(allocator.allocate_gsi(1), Ok(vec![i]));
143143
}
144144
}

0 commit comments

Comments
 (0)