Skip to content

Commit f9a2e64

Browse files
authored
Merge pull request #184 from junyu0312/dev
feat: Introduce InterruptManager
2 parents 9baeabe + 2130655 commit f9a2e64

24 files changed

Lines changed: 207 additions & 79 deletions

File tree

crates/vm-core/src/arch/aarch64/layout.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const KERNEL_MAX: usize = 0x0400_0000;
2121

2222
// We use SPI index to facilitate device-tree generating, triggering irq should add 32.
2323
pub const IRQ_ALLOCATION_START: u32 = 0;
24-
pub const IRQ_ALLOCATION_END: u32 = 256 - 32;
24+
pub const IRQ_ALLOCATION_LEN: usize = 256 - 32;
2525

2626
const_assert!(ECAM_BASE >= MMIO_START + MMIO_LEN);
2727
const_assert!(PCI_BAR_MMIO_WINDOW_START >= ECAM_BASE + ECAM_LENGTH);

crates/vm-core/src/arch/x86_64/layout.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ pub const PCI_IO_PORT_WINDOW_START: u16 = 0x2000;
3131
pub const PCI_IO_PORT_WINDOW_LENGTH: u16 = 0x2000;
3232

3333
pub const IRQ_ALLOCATION_START: u32 = 5;
34-
pub const IRQ_ALLOCATION_END: u32 = 23;
34+
pub const IRQ_ALLOCATION_LEN: usize = 16 - IRQ_ALLOCATION_START as usize;
35+
36+
pub const GSI_ALLOCATION_START: u32 = 32;
37+
pub const GSI_ALLOCATION_LEN: usize = 256 - GSI_ALLOCATION_START as usize;
3538

3639
const_assert!(KERNEL_START >= ACPI_RSDP_START + ACPI_MAX_LEN);
3740
const_assert!(PCI_BAR_MMIO_WINDOW_START >= MMIO_START + MMIO_LEN);
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use std::sync::Mutex;
2+
3+
use thiserror::Error;
4+
use vm_utils::range_allocator::RangeAllocator;
5+
6+
#[derive(Error, Debug)]
7+
pub enum InterruptManagerError {
8+
#[error("Invalid argument")]
9+
InvalidArgument,
10+
11+
#[error("Failed to reserve irq {0}")]
12+
ReserveIrq(u32),
13+
14+
#[error("Failed to allocate irq")]
15+
AllocateIrq,
16+
17+
#[error("Failed to allocate gsi")]
18+
AllocateGsi,
19+
}
20+
21+
struct Allocator(Mutex<RangeAllocator<u32>>);
22+
23+
impl Allocator {
24+
fn new(start: u32, len: usize) -> Result<Self, InterruptManagerError> {
25+
let mut irq_allocator = RangeAllocator::<u32>::default();
26+
irq_allocator
27+
.insert(start, len)
28+
.map_err(|_| InterruptManagerError::InvalidArgument)?;
29+
Ok(Allocator(Mutex::new(irq_allocator)))
30+
}
31+
}
32+
33+
pub struct InterruptManager {
34+
// We can use bitmap for better performance.
35+
irq_allocator: Allocator,
36+
#[cfg(target_arch = "x86_64")]
37+
gsi_allocator: Allocator,
38+
}
39+
40+
impl InterruptManager {
41+
pub fn new(
42+
irq_start: u32,
43+
irq_len: usize,
44+
#[cfg(target_arch = "x86_64")] gsi_start: u32,
45+
#[cfg(target_arch = "x86_64")] gsi_len: usize,
46+
) -> Result<Self, InterruptManagerError> {
47+
let irq_allocator = Allocator::new(irq_start, irq_len)?;
48+
49+
#[cfg(target_arch = "x86_64")]
50+
let gsi_allocator = Allocator::new(gsi_start, gsi_len)?;
51+
52+
Ok(InterruptManager {
53+
irq_allocator,
54+
#[cfg(target_arch = "x86_64")]
55+
gsi_allocator,
56+
})
57+
}
58+
59+
pub fn reserve_irq(&self, irq: u32) -> Result<(), InterruptManagerError> {
60+
let mut irq_allocator = self.irq_allocator.0.lock().unwrap();
61+
let _ = irq_allocator
62+
.reserve(irq, 1)
63+
.map_err(|_| InterruptManagerError::ReserveIrq(irq))?;
64+
65+
Ok(())
66+
}
67+
68+
pub fn allocate_irq(&self) -> Result<u32, InterruptManagerError> {
69+
let mut irq_allocator = self.irq_allocator.0.lock().unwrap();
70+
let range = irq_allocator
71+
.alloc(1)
72+
.map_err(|_| InterruptManagerError::AllocateIrq)?;
73+
74+
Ok(range.start)
75+
}
76+
77+
#[cfg(target_arch = "x86_64")]
78+
pub fn allocate_gsi(&self) -> Result<u32, InterruptManagerError> {
79+
let mut gsi_allocator = self.gsi_allocator.0.lock().unwrap();
80+
let range = gsi_allocator
81+
.alloc(1)
82+
.map_err(|_| InterruptManagerError::AllocateGsi)?;
83+
84+
Ok(range.start)
85+
}
86+
87+
#[cfg(target_arch = "aarch64")]
88+
pub fn allocate_gsi(&self) -> Result<u32, InterruptManagerError> {
89+
self.allocate_irq()
90+
.map_err(|_| InterruptManagerError::AllocateGsi)
91+
}
92+
}

crates/vm-core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pub mod arch;
44
pub mod cpu;
55
pub mod device;
6+
pub mod interrupt_manager;
67
pub mod monitor;
78
pub mod utils;
89
pub mod virtualization;

crates/vm-core/src/virtualization.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,5 @@ pub mod hvp;
55
pub mod kvm;
66

77
pub mod hypervisor;
8-
pub mod irq_allocator;
98
pub mod vcpu;
109
pub mod vm;

crates/vm-core/src/virtualization/hvp/vm.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@ use crate::arch::aarch64::irq::GIC_SPI_START;
1818
use crate::arch::aarch64::layout::GIC_DISTRIBUTOR;
1919
use crate::arch::aarch64::layout::GIC_MSI;
2020
use crate::arch::aarch64::layout::GIC_REDISTRIBUTOR;
21-
use crate::arch::aarch64::layout::IRQ_ALLOCATION_END;
21+
use crate::arch::aarch64::layout::IRQ_ALLOCATION_LEN;
2222
use crate::arch::aarch64::layout::IRQ_ALLOCATION_START;
2323
use crate::arch::aarch64::layout::RAM_BASE;
2424
use crate::arch::irq::InterruptController;
2525
use crate::cpu::vm_exit::VmExit;
26+
use crate::interrupt_manager::InterruptManager;
2627
use crate::virtualization::hvp::hv_unsafe_call;
2728
use crate::virtualization::hvp::irq_chip::HvpGicV3;
2829
use crate::virtualization::hvp::vcpu::HvpVcpu;
29-
use crate::virtualization::irq_allocator::IrqAllocator;
3030
use crate::virtualization::vcpu::HypervisorVcpu;
3131
use crate::virtualization::vm::HypervisorVm;
3232
use crate::virtualization::vm::SetUserMemoryRegionFlags;
@@ -135,7 +135,7 @@ impl HypervisorVm for AppleHypervisorVm {
135135
)))
136136
}
137137

138-
fn create_irq_allocator(&self) -> Result<IrqAllocator, VmError> {
138+
fn create_irq_manager(&self) -> Result<InterruptManager, VmError> {
139139
let mut spi_intid_base = 0;
140140
let mut spi_intid_count = 0;
141141
hv_unsafe_call!(hv_gic_get_spi_interrupt_range(
@@ -144,9 +144,12 @@ impl HypervisorVm for AppleHypervisorVm {
144144
))?;
145145

146146
assert!(IRQ_ALLOCATION_START + GIC_SPI_START >= spi_intid_base);
147-
assert!(IRQ_ALLOCATION_END + GIC_SPI_START <= spi_intid_base + spi_intid_count);
147+
assert!(
148+
IRQ_ALLOCATION_START + IRQ_ALLOCATION_LEN as u32 + GIC_SPI_START
149+
<= spi_intid_base + spi_intid_count
150+
);
148151

149-
let allocator = IrqAllocator::new(IRQ_ALLOCATION_START, IRQ_ALLOCATION_END);
152+
let allocator = InterruptManager::new(IRQ_ALLOCATION_START, IRQ_ALLOCATION_LEN)?;
150153

151154
Ok(allocator)
152155
}

crates/vm-core/src/virtualization/irq_allocator.rs

Lines changed: 0 additions & 23 deletions
This file was deleted.

crates/vm-core/src/virtualization/kvm/vm.rs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@ use vm_mm::manager::MemoryAddressSpace;
88
use vmm_sys_util::eventfd::EventFd;
99

1010
#[cfg(target_arch = "aarch64")]
11-
use crate::arch::aarch64::layout::IRQ_ALLOCATION_END;
11+
use crate::arch::aarch64::layout::IRQ_ALLOCATION_LEN;
1212
#[cfg(target_arch = "aarch64")]
1313
use crate::arch::aarch64::layout::IRQ_ALLOCATION_START;
1414
use crate::arch::irq::InterruptController;
1515
#[cfg(target_arch = "x86_64")]
16-
use crate::arch::x86_64::layout::IRQ_ALLOCATION_END;
16+
use crate::arch::x86_64::layout::GSI_ALLOCATION_LEN;
17+
#[cfg(target_arch = "x86_64")]
18+
use crate::arch::x86_64::layout::GSI_ALLOCATION_START;
19+
#[cfg(target_arch = "x86_64")]
20+
use crate::arch::x86_64::layout::IRQ_ALLOCATION_LEN;
1721
#[cfg(target_arch = "x86_64")]
1822
use crate::arch::x86_64::layout::IRQ_ALLOCATION_START;
1923
use crate::cpu::vm_exit::VmExit;
20-
use crate::virtualization::irq_allocator::IrqAllocator;
24+
use crate::interrupt_manager::InterruptManager;
2125
use crate::virtualization::kvm::gsi_routing::KvmGsiRouting;
2226
use crate::virtualization::kvm::gsi_routing::get_kvm_gsi_routing_instance;
2327
use crate::virtualization::kvm::irq_chip::KvmIrqChip;
@@ -73,8 +77,17 @@ impl HypervisorVm for KvmVm {
7377
Ok(Box::new(irq_chip))
7478
}
7579

76-
fn create_irq_allocator(&self) -> Result<IrqAllocator, VmError> {
77-
Ok(IrqAllocator::new(IRQ_ALLOCATION_START, IRQ_ALLOCATION_END))
80+
fn create_irq_manager(&self) -> Result<InterruptManager, VmError> {
81+
let interrupt_manager = InterruptManager::new(
82+
IRQ_ALLOCATION_START,
83+
IRQ_ALLOCATION_LEN,
84+
#[cfg(target_arch = "x86_64")]
85+
GSI_ALLOCATION_START,
86+
#[cfg(target_arch = "x86_64")]
87+
GSI_ALLOCATION_LEN,
88+
)?;
89+
90+
Ok(interrupt_manager)
7891
}
7992

8093
fn set_user_memory_region(

crates/vm-core/src/virtualization/vm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use vmm_sys_util::eventfd::EventFd;
66

77
use crate::arch::irq::InterruptController;
88
use crate::cpu::vm_exit::VmExit;
9-
use crate::virtualization::irq_allocator::IrqAllocator;
9+
use crate::interrupt_manager::InterruptManager;
1010
use crate::virtualization::vcpu::HypervisorVcpu;
1111
use crate::virtualization::vm::error::VmError;
1212

@@ -27,7 +27,7 @@ pub trait HypervisorVm: Send + Sync {
2727

2828
fn create_irq_chip(&self) -> Result<Box<dyn InterruptController>, VmError>;
2929

30-
fn create_irq_allocator(&self) -> Result<IrqAllocator, VmError>;
30+
fn create_irq_manager(&self) -> Result<InterruptManager, VmError>;
3131

3232
fn set_user_memory_region(
3333
&self,

crates/vm-core/src/virtualization/vm/error.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use thiserror::Error;
22

33
use crate::cpu::error::CpuError;
4+
use crate::interrupt_manager::InterruptManagerError;
45
use crate::virtualization::vm::state::VmState;
56

67
#[derive(Error, Debug)]
@@ -34,8 +35,8 @@ pub enum VmError {
3435
#[error("Cpu error: {0}")]
3536
CpuError(#[from] CpuError),
3637

37-
#[error("No space to alloc irq")]
38-
AllocIrq,
38+
#[error("Interrupt manager error: {0}")]
39+
InterruptManagerError(#[from] InterruptManagerError),
3940

4041
#[error("vm state is not satisfied, current: {current:?}")]
4142
VmState { current: VmState },

0 commit comments

Comments
 (0)