From 2130655daf39ba8410502440ceeb21561edeb94a Mon Sep 17 00:00:00 2001 From: Zhang Junyu Date: Tue, 30 Jun 2026 17:46:22 +0000 Subject: [PATCH] feat: Introduce InterruptManager --- crates/vm-core/src/arch/aarch64/layout.rs | 2 +- crates/vm-core/src/arch/x86_64/layout.rs | 5 +- crates/vm-core/src/interrupt_manager.rs | 92 +++++++++++++++++++ crates/vm-core/src/lib.rs | 1 + crates/vm-core/src/virtualization.rs | 1 - crates/vm-core/src/virtualization/hvp/vm.rs | 13 ++- .../src/virtualization/irq_allocator.rs | 23 ----- crates/vm-core/src/virtualization/kvm/vm.rs | 23 ++++- crates/vm-core/src/virtualization/vm.rs | 4 +- crates/vm-core/src/virtualization/vm/error.rs | 5 +- crates/vm-vfio/src/vfio_pci/device.rs | 19 ++-- crates/vm-vfio/src/vfio_pci/function.rs | 23 ++++- crates/vm-vfio/src/vfio_pci/interrupt/msi.rs | 1 + crates/vm-vfio/src/vfio_pci/interrupt/msix.rs | 1 + crates/vm-virtio/src/device.rs | 8 +- crates/vm-virtio/src/result.rs | 6 +- crates/vm-virtio/src/transport/pci.rs | 20 ++-- crates/vm-vmm/src/device/error.rs | 4 + crates/vm-vmm/src/vm/config.rs | 2 +- crates/vm-vmm/src/vm/device_builder.rs | 21 +++-- .../src/vm/device_builder/arch/aarch64.rs | 4 +- crates/vm-vmm/src/vm/device_builder/vfio.rs | 2 +- crates/vm-vmm/src/vm/snapshot.rs | 2 +- crates/vm-vmm/src/vmm/error.rs | 4 + 24 files changed, 207 insertions(+), 79 deletions(-) create mode 100644 crates/vm-core/src/interrupt_manager.rs delete mode 100644 crates/vm-core/src/virtualization/irq_allocator.rs diff --git a/crates/vm-core/src/arch/aarch64/layout.rs b/crates/vm-core/src/arch/aarch64/layout.rs index 7728e585..6b01ebfe 100644 --- a/crates/vm-core/src/arch/aarch64/layout.rs +++ b/crates/vm-core/src/arch/aarch64/layout.rs @@ -21,7 +21,7 @@ const KERNEL_MAX: usize = 0x0400_0000; // We use SPI index to facilitate device-tree generating, triggering irq should add 32. pub const IRQ_ALLOCATION_START: u32 = 0; -pub const IRQ_ALLOCATION_END: u32 = 256 - 32; +pub const IRQ_ALLOCATION_LEN: usize = 256 - 32; const_assert!(ECAM_BASE >= MMIO_START + MMIO_LEN); const_assert!(PCI_BAR_MMIO_WINDOW_START >= ECAM_BASE + ECAM_LENGTH); diff --git a/crates/vm-core/src/arch/x86_64/layout.rs b/crates/vm-core/src/arch/x86_64/layout.rs index ed4749a0..2a4f1636 100644 --- a/crates/vm-core/src/arch/x86_64/layout.rs +++ b/crates/vm-core/src/arch/x86_64/layout.rs @@ -31,7 +31,10 @@ pub const PCI_IO_PORT_WINDOW_START: u16 = 0x2000; pub const PCI_IO_PORT_WINDOW_LENGTH: u16 = 0x2000; pub const IRQ_ALLOCATION_START: u32 = 5; -pub const IRQ_ALLOCATION_END: u32 = 23; +pub const IRQ_ALLOCATION_LEN: usize = 16 - IRQ_ALLOCATION_START as usize; + +pub const GSI_ALLOCATION_START: u32 = 32; +pub const GSI_ALLOCATION_LEN: usize = 256 - GSI_ALLOCATION_START as usize; const_assert!(KERNEL_START >= ACPI_RSDP_START + ACPI_MAX_LEN); const_assert!(PCI_BAR_MMIO_WINDOW_START >= MMIO_START + MMIO_LEN); diff --git a/crates/vm-core/src/interrupt_manager.rs b/crates/vm-core/src/interrupt_manager.rs new file mode 100644 index 00000000..6a0199d2 --- /dev/null +++ b/crates/vm-core/src/interrupt_manager.rs @@ -0,0 +1,92 @@ +use std::sync::Mutex; + +use thiserror::Error; +use vm_utils::range_allocator::RangeAllocator; + +#[derive(Error, Debug)] +pub enum InterruptManagerError { + #[error("Invalid argument")] + InvalidArgument, + + #[error("Failed to reserve irq {0}")] + ReserveIrq(u32), + + #[error("Failed to allocate irq")] + AllocateIrq, + + #[error("Failed to allocate gsi")] + AllocateGsi, +} + +struct Allocator(Mutex>); + +impl Allocator { + fn new(start: u32, len: usize) -> Result { + let mut irq_allocator = RangeAllocator::::default(); + irq_allocator + .insert(start, len) + .map_err(|_| InterruptManagerError::InvalidArgument)?; + Ok(Allocator(Mutex::new(irq_allocator))) + } +} + +pub struct InterruptManager { + // We can use bitmap for better performance. + irq_allocator: Allocator, + #[cfg(target_arch = "x86_64")] + gsi_allocator: Allocator, +} + +impl InterruptManager { + pub fn new( + irq_start: u32, + irq_len: usize, + #[cfg(target_arch = "x86_64")] gsi_start: u32, + #[cfg(target_arch = "x86_64")] gsi_len: usize, + ) -> Result { + let irq_allocator = Allocator::new(irq_start, irq_len)?; + + #[cfg(target_arch = "x86_64")] + let gsi_allocator = Allocator::new(gsi_start, gsi_len)?; + + Ok(InterruptManager { + irq_allocator, + #[cfg(target_arch = "x86_64")] + gsi_allocator, + }) + } + + pub fn reserve_irq(&self, irq: u32) -> Result<(), InterruptManagerError> { + let mut irq_allocator = self.irq_allocator.0.lock().unwrap(); + let _ = irq_allocator + .reserve(irq, 1) + .map_err(|_| InterruptManagerError::ReserveIrq(irq))?; + + Ok(()) + } + + pub fn allocate_irq(&self) -> Result { + let mut irq_allocator = self.irq_allocator.0.lock().unwrap(); + let range = irq_allocator + .alloc(1) + .map_err(|_| InterruptManagerError::AllocateIrq)?; + + Ok(range.start) + } + + #[cfg(target_arch = "x86_64")] + pub fn allocate_gsi(&self) -> Result { + let mut gsi_allocator = self.gsi_allocator.0.lock().unwrap(); + let range = gsi_allocator + .alloc(1) + .map_err(|_| InterruptManagerError::AllocateGsi)?; + + Ok(range.start) + } + + #[cfg(target_arch = "aarch64")] + pub fn allocate_gsi(&self) -> Result { + self.allocate_irq() + .map_err(|_| InterruptManagerError::AllocateGsi) + } +} diff --git a/crates/vm-core/src/lib.rs b/crates/vm-core/src/lib.rs index f7affaef..105d7b57 100644 --- a/crates/vm-core/src/lib.rs +++ b/crates/vm-core/src/lib.rs @@ -3,6 +3,7 @@ pub mod arch; pub mod cpu; pub mod device; +pub mod interrupt_manager; pub mod monitor; pub mod utils; pub mod virtualization; diff --git a/crates/vm-core/src/virtualization.rs b/crates/vm-core/src/virtualization.rs index 4ebb6923..60aa0479 100644 --- a/crates/vm-core/src/virtualization.rs +++ b/crates/vm-core/src/virtualization.rs @@ -5,6 +5,5 @@ pub mod hvp; pub mod kvm; pub mod hypervisor; -pub mod irq_allocator; pub mod vcpu; pub mod vm; diff --git a/crates/vm-core/src/virtualization/hvp/vm.rs b/crates/vm-core/src/virtualization/hvp/vm.rs index 201a11ef..08d894e4 100644 --- a/crates/vm-core/src/virtualization/hvp/vm.rs +++ b/crates/vm-core/src/virtualization/hvp/vm.rs @@ -18,15 +18,15 @@ use crate::arch::aarch64::irq::GIC_SPI_START; use crate::arch::aarch64::layout::GIC_DISTRIBUTOR; use crate::arch::aarch64::layout::GIC_MSI; use crate::arch::aarch64::layout::GIC_REDISTRIBUTOR; -use crate::arch::aarch64::layout::IRQ_ALLOCATION_END; +use crate::arch::aarch64::layout::IRQ_ALLOCATION_LEN; use crate::arch::aarch64::layout::IRQ_ALLOCATION_START; use crate::arch::aarch64::layout::RAM_BASE; use crate::arch::irq::InterruptController; use crate::cpu::vm_exit::VmExit; +use crate::interrupt_manager::InterruptManager; use crate::virtualization::hvp::hv_unsafe_call; use crate::virtualization::hvp::irq_chip::HvpGicV3; use crate::virtualization::hvp::vcpu::HvpVcpu; -use crate::virtualization::irq_allocator::IrqAllocator; use crate::virtualization::vcpu::HypervisorVcpu; use crate::virtualization::vm::HypervisorVm; use crate::virtualization::vm::SetUserMemoryRegionFlags; @@ -135,7 +135,7 @@ impl HypervisorVm for AppleHypervisorVm { ))) } - fn create_irq_allocator(&self) -> Result { + fn create_irq_manager(&self) -> Result { let mut spi_intid_base = 0; let mut spi_intid_count = 0; hv_unsafe_call!(hv_gic_get_spi_interrupt_range( @@ -144,9 +144,12 @@ impl HypervisorVm for AppleHypervisorVm { ))?; assert!(IRQ_ALLOCATION_START + GIC_SPI_START >= spi_intid_base); - assert!(IRQ_ALLOCATION_END + GIC_SPI_START <= spi_intid_base + spi_intid_count); + assert!( + IRQ_ALLOCATION_START + IRQ_ALLOCATION_LEN as u32 + GIC_SPI_START + <= spi_intid_base + spi_intid_count + ); - let allocator = IrqAllocator::new(IRQ_ALLOCATION_START, IRQ_ALLOCATION_END); + let allocator = InterruptManager::new(IRQ_ALLOCATION_START, IRQ_ALLOCATION_LEN)?; Ok(allocator) } diff --git a/crates/vm-core/src/virtualization/irq_allocator.rs b/crates/vm-core/src/virtualization/irq_allocator.rs deleted file mode 100644 index 9d41eb94..00000000 --- a/crates/vm-core/src/virtualization/irq_allocator.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::virtualization::vm::error::VmError; - -pub struct IrqAllocator { - max: u32, - current: u32, -} - -impl IrqAllocator { - pub fn new(min: u32, max: u32) -> Self { - IrqAllocator { max, current: min } - } - - pub fn alloc(&mut self) -> Result { - if self.current > self.max { - return Err(VmError::AllocIrq); - } - - let alloc = self.current; - self.current = self.current.checked_add(1).ok_or(VmError::AllocIrq)?; - - Ok(alloc) - } -} diff --git a/crates/vm-core/src/virtualization/kvm/vm.rs b/crates/vm-core/src/virtualization/kvm/vm.rs index d29cb60c..a89276da 100644 --- a/crates/vm-core/src/virtualization/kvm/vm.rs +++ b/crates/vm-core/src/virtualization/kvm/vm.rs @@ -8,16 +8,20 @@ use vm_mm::manager::MemoryAddressSpace; use vmm_sys_util::eventfd::EventFd; #[cfg(target_arch = "aarch64")] -use crate::arch::aarch64::layout::IRQ_ALLOCATION_END; +use crate::arch::aarch64::layout::IRQ_ALLOCATION_LEN; #[cfg(target_arch = "aarch64")] use crate::arch::aarch64::layout::IRQ_ALLOCATION_START; use crate::arch::irq::InterruptController; #[cfg(target_arch = "x86_64")] -use crate::arch::x86_64::layout::IRQ_ALLOCATION_END; +use crate::arch::x86_64::layout::GSI_ALLOCATION_LEN; +#[cfg(target_arch = "x86_64")] +use crate::arch::x86_64::layout::GSI_ALLOCATION_START; +#[cfg(target_arch = "x86_64")] +use crate::arch::x86_64::layout::IRQ_ALLOCATION_LEN; #[cfg(target_arch = "x86_64")] use crate::arch::x86_64::layout::IRQ_ALLOCATION_START; use crate::cpu::vm_exit::VmExit; -use crate::virtualization::irq_allocator::IrqAllocator; +use crate::interrupt_manager::InterruptManager; use crate::virtualization::kvm::gsi_routing::KvmGsiRouting; use crate::virtualization::kvm::gsi_routing::get_kvm_gsi_routing_instance; use crate::virtualization::kvm::irq_chip::KvmIrqChip; @@ -73,8 +77,17 @@ impl HypervisorVm for KvmVm { Ok(Box::new(irq_chip)) } - fn create_irq_allocator(&self) -> Result { - Ok(IrqAllocator::new(IRQ_ALLOCATION_START, IRQ_ALLOCATION_END)) + fn create_irq_manager(&self) -> Result { + let interrupt_manager = InterruptManager::new( + IRQ_ALLOCATION_START, + IRQ_ALLOCATION_LEN, + #[cfg(target_arch = "x86_64")] + GSI_ALLOCATION_START, + #[cfg(target_arch = "x86_64")] + GSI_ALLOCATION_LEN, + )?; + + Ok(interrupt_manager) } fn set_user_memory_region( diff --git a/crates/vm-core/src/virtualization/vm.rs b/crates/vm-core/src/virtualization/vm.rs index b2b004e8..cff45772 100644 --- a/crates/vm-core/src/virtualization/vm.rs +++ b/crates/vm-core/src/virtualization/vm.rs @@ -6,7 +6,7 @@ use vmm_sys_util::eventfd::EventFd; use crate::arch::irq::InterruptController; use crate::cpu::vm_exit::VmExit; -use crate::virtualization::irq_allocator::IrqAllocator; +use crate::interrupt_manager::InterruptManager; use crate::virtualization::vcpu::HypervisorVcpu; use crate::virtualization::vm::error::VmError; @@ -27,7 +27,7 @@ pub trait HypervisorVm: Send + Sync { fn create_irq_chip(&self) -> Result, VmError>; - fn create_irq_allocator(&self) -> Result; + fn create_irq_manager(&self) -> Result; fn set_user_memory_region( &self, diff --git a/crates/vm-core/src/virtualization/vm/error.rs b/crates/vm-core/src/virtualization/vm/error.rs index 1868d623..19f6ab6c 100644 --- a/crates/vm-core/src/virtualization/vm/error.rs +++ b/crates/vm-core/src/virtualization/vm/error.rs @@ -1,6 +1,7 @@ use thiserror::Error; use crate::cpu::error::CpuError; +use crate::interrupt_manager::InterruptManagerError; use crate::virtualization::vm::state::VmState; #[derive(Error, Debug)] @@ -34,8 +35,8 @@ pub enum VmError { #[error("Cpu error: {0}")] CpuError(#[from] CpuError), - #[error("No space to alloc irq")] - AllocIrq, + #[error("Interrupt manager error: {0}")] + InterruptManagerError(#[from] InterruptManagerError), #[error("vm state is not satisfied, current: {current:?}")] VmState { current: VmState }, diff --git a/crates/vm-vfio/src/vfio_pci/device.rs b/crates/vm-vfio/src/vfio_pci/device.rs index 46dab964..c8b4dc40 100644 --- a/crates/vm-vfio/src/vfio_pci/device.rs +++ b/crates/vm-vfio/src/vfio_pci/device.rs @@ -8,7 +8,7 @@ use vfio_bindings::bindings::vfio::VFIO_PCI_CONFIG_REGION_INDEX; use vfio_bindings::bindings::vfio::VFIO_REGION_INFO_FLAG_READ; use vfio_bindings::bindings::vfio::VFIO_REGION_INFO_FLAG_WRITE; use vm_core::device::Device; -use vm_core::virtualization::irq_allocator::IrqAllocator; +use vm_core::interrupt_manager::InterruptManager; use vm_core::virtualization::vm::HypervisorVm; use vm_pci::device::capability::PciCapId; use vm_pci::device::capability::msi::PCI_MSI_FLAGS_64BIT; @@ -71,7 +71,7 @@ const DEBUG_ENABLE_INTX: bool = true; fn setup_interrupt_capability( vm: &dyn HypervisorVm, vfio_device: Arc, - irq_allocator: &mut IrqAllocator, + interrupt_manager: &InterruptManager, raw: &PciConfigurationSpace, cfg: &mut ConfigurationSpace, ) -> Result<(VfioInterruptInfo, VfioInterruptManager)> { @@ -116,6 +116,7 @@ fn setup_interrupt_capability( let pba_offset = cap.pba_offset & PCI_MSIX_PBA_OFFSET; let pba_len = pba.as_bytes().len(); + let gsi = vec![None; vectors as usize]; let event_fds = (0..vectors) .map(|_| EventFd::new(0)) .collect::, _>>()?; @@ -141,6 +142,7 @@ fn setup_interrupt_capability( cap_offset_range: cap_offset as u16..cap_offset as u16 + cap_len as u16, }); msix = Some(VfioMsix { + gsi, table, pba, enabled: false, @@ -203,6 +205,7 @@ fn setup_interrupt_capability( } } + let gsi = vec![None; mmc.vectors() as usize]; let irqrd = vec![false; mmc.vectors() as usize]; let event_fds = (0..mmc.vectors()) .map(|_| EventFd::new(0)) @@ -215,6 +218,7 @@ fn setup_interrupt_capability( cap_offset_range: cap_offset as u16..cap_offset as u16 + cap_len as u16, }); msi = Some(VfioMsi { + gsi, irqrd, enabled: false, }); @@ -236,11 +240,11 @@ fn setup_interrupt_capability( InterruptPin::from_repr(raw_header.interrupt_pin).ok_or(Error::ParseIntx)?; header.interrupt_pin = interrupt_pin as u8; - let gsi = irq_allocator - .alloc() + let gsi = interrupt_manager + .allocate_irq() .map_err(|_| Error::AllocIrq)? .try_into() - .unwrap(); + .map_err(|_| Error::AllocIrq)?; header.interrupt_line = gsi; if irq_info.flags & VFIO_IRQ_INFO_EVENTFD == 0 { @@ -288,7 +292,7 @@ impl VfioPciDevice { vm: Arc, #[cfg(target_arch = "x86_64")] pci_io_window_allocator: &mut RangeAllocator, pci_mmio_window_allocator: &mut RangeAllocator, - irq_allocator: &mut IrqAllocator, + irq_manager: Arc, vfio_device: VfioDevice, ) -> Result { let vfio_device = Arc::new(vfio_device); @@ -348,7 +352,7 @@ impl VfioPciDevice { let (interrupt_info, interrupt_manager) = setup_interrupt_capability( vm.as_ref(), vfio_device.clone(), - irq_allocator, + irq_manager.as_ref(), &raw_configuration_space, &mut configuration_space, )?; @@ -414,6 +418,7 @@ impl VfioPciDevice { let function = VfioPciFunction::new( vm, + irq_manager, raw_configuration_space, configuration_space, bar_info, diff --git a/crates/vm-vfio/src/vfio_pci/function.rs b/crates/vm-vfio/src/vfio_pci/function.rs index 9c0d87e3..0ef14337 100644 --- a/crates/vm-vfio/src/vfio_pci/function.rs +++ b/crates/vm-vfio/src/vfio_pci/function.rs @@ -4,6 +4,7 @@ use std::sync::Mutex; use tracing::warn; use vfio_bindings::bindings::vfio::VFIO_PCI_BAR0_REGION_INDEX; use vfio_bindings::bindings::vfio::VFIO_PCI_CONFIG_REGION_INDEX; +use vm_core::interrupt_manager::InterruptManager; use vm_core::virtualization::kvm::gsi_routing::get_kvm_gsi_routing_instance; use vm_core::virtualization::vm::HypervisorVm; use vm_pci::device::capability::msi::PciMsiCap; @@ -40,6 +41,7 @@ use crate::vfio_pci::interrupt::msix::VfioMsixInfo; pub struct VfioPciFunction { vm: Arc, + irq_manager: Arc, raw_configuration_space: PciConfigurationSpace, configuration_space: Mutex, bars: [Option; 6], @@ -49,8 +51,10 @@ pub struct VfioPciFunction { } impl VfioPciFunction { + #[allow(clippy::too_many_arguments)] pub(crate) fn new( vm: Arc, + irq_manager: Arc, raw_configuration_space: PciConfigurationSpace, configuration_space: ConfigurationSpace, bars: [Option; 6], @@ -60,6 +64,7 @@ impl VfioPciFunction { ) -> Self { VfioPciFunction { vm, + irq_manager, raw_configuration_space, configuration_space: configuration_space.into(), bars, @@ -140,8 +145,13 @@ impl VfioPciFunction { enable: bool, vector: usize, ) { - // TODO: introduce gsi allocator - let gsi = (32 + vector) as u32; + let gsi = if let Some(gsi) = msi.gsi[vector] { + gsi + } else { + let gsi = self.irq_manager.allocate_gsi().unwrap(); + msi.gsi[vector] = Some(gsi); + gsi + }; self.insert_or_update_msi_gsi_entry( msi_cap.address_lo(), @@ -348,8 +358,13 @@ impl VfioPciFunction { msi_entry_new.as_mut_bytes()[offset_within_entry..offset_within_entry + buf.len()] .copy_from_slice(buf); - // TODO: introduce gsi allocator - let gsi = (32 + vector) as u32; + let gsi = if let Some(gsi) = msix.gsi[vector] { + gsi + } else { + let gsi = self.irq_manager.allocate_gsi().unwrap(); + msix.gsi[vector] = Some(gsi); + gsi + }; self.insert_or_update_msi_gsi_entry( msi_entry_new.addr_lo, msi_entry_new.addr_hi, diff --git a/crates/vm-vfio/src/vfio_pci/interrupt/msi.rs b/crates/vm-vfio/src/vfio_pci/interrupt/msi.rs index 6150d7ca..5038640f 100644 --- a/crates/vm-vfio/src/vfio_pci/interrupt/msi.rs +++ b/crates/vm-vfio/src/vfio_pci/interrupt/msi.rs @@ -10,6 +10,7 @@ pub struct VfioMsiInfo { } pub struct VfioMsi { + pub gsi: Vec>, pub irqrd: Vec, pub enabled: bool, } diff --git a/crates/vm-vfio/src/vfio_pci/interrupt/msix.rs b/crates/vm-vfio/src/vfio_pci/interrupt/msix.rs index 9bb2aa6b..5d101c6d 100644 --- a/crates/vm-vfio/src/vfio_pci/interrupt/msix.rs +++ b/crates/vm-vfio/src/vfio_pci/interrupt/msix.rs @@ -15,6 +15,7 @@ pub struct VfioMsixInfo { } pub struct VfioMsix { + pub gsi: Vec>, pub table: Vec, pub pba: Vec, pub enabled: bool, diff --git a/crates/vm-virtio/src/device.rs b/crates/vm-virtio/src/device.rs index e230765d..4e6611fb 100644 --- a/crates/vm-virtio/src/device.rs +++ b/crates/vm-virtio/src/device.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use tokio::runtime::Handle; use vm_core::arch::irq::InterruptController; use vm_core::device::error::DeviceSnapshotError; -use vm_core::virtualization::irq_allocator::IrqAllocator; +use vm_core::interrupt_manager::InterruptManager; use vm_mm::manager::MemoryAddressSpace; use vm_utils::range_allocator::RangeAllocator; @@ -70,7 +70,7 @@ pub trait VirtioDevice: Sized + Send + Sync + 'static { fn into_mmio_device( self, mmio_allocator: &mut RangeAllocator, - irq_allocator: &mut IrqAllocator, + interrupt_manager: &InterruptManager, virtio_aml_path_allocator: &mut RangeAllocator, tokio_runtime: Handle, memory: Arc, @@ -82,7 +82,7 @@ pub trait VirtioDevice: Sized + Send + Sync + 'static { let id = virtio_aml_path_allocator .alloc(1) - .map_err(VirtioError::AllocIrq)?; + .map_err(VirtioError::AllocId)?; let dev = VirtioMmioTransport::new( tokio_runtime, @@ -90,7 +90,7 @@ pub trait VirtioDevice: Sized + Send + Sync + 'static { irq_chip, id.start, mmio_range, - irq_allocator.alloc().unwrap().try_into().unwrap(), + interrupt_manager.allocate_irq()?.try_into().unwrap(), VirtioTransportCommon::new(self)?, ); diff --git a/crates/vm-virtio/src/result.rs b/crates/vm-virtio/src/result.rs index 0ca79bd8..d334dacb 100644 --- a/crates/vm-virtio/src/result.rs +++ b/crates/vm-virtio/src/result.rs @@ -1,4 +1,5 @@ use thiserror::Error; +use vm_core::interrupt_manager::InterruptManagerError; use vm_utils::range_allocator::RangeAllocatorError; #[derive(Error, Debug)] @@ -7,7 +8,10 @@ pub enum VirtioError { AllocMmioRange(RangeAllocatorError), #[error("Failed to alloc irq")] - AllocIrq(RangeAllocatorError), + AllocIrq(#[from] InterruptManagerError), + + #[error("Failed to alloc virtio-mmio id")] + AllocId(RangeAllocatorError), #[error("queue id exceeds u16")] QueueExceedsU16 { device: &'static str }, diff --git a/crates/vm-virtio/src/transport/pci.rs b/crates/vm-virtio/src/transport/pci.rs index 5120a5bc..f1926e3e 100644 --- a/crates/vm-virtio/src/transport/pci.rs +++ b/crates/vm-virtio/src/transport/pci.rs @@ -10,7 +10,7 @@ use tokio::runtime::Handle; use vm_core::arch::irq::InterruptController; use vm_core::device::Device; use vm_core::device::error::DeviceSnapshotError; -use vm_core::virtualization::irq_allocator::IrqAllocator; +use vm_core::interrupt_manager::InterruptManager; use vm_mm::manager::MemoryAddressSpace; use vm_pci::device::capability::msix::PciMsixCap; use vm_pci::device::function::PciTypeFunctionCommon; @@ -92,7 +92,7 @@ where } fn new( - irq_allocator: &mut IrqAllocator, + interrupt_manager: &InterruptManager, tokio_runtime: Handle, memory: Arc, irq_chip: Arc, @@ -115,7 +115,13 @@ where legacy_int = None; msix = Some(Arc::new(RwLock::new(VirtioPciMsixInfo::new(num_queues)))); } else { - legacy_int = Some(irq_allocator.alloc().unwrap().try_into().unwrap()); + legacy_int = Some( + interrupt_manager + .allocate_irq() + .unwrap() + .try_into() + .unwrap(), + ); msix = None }; @@ -412,13 +418,13 @@ pub trait VirtioPciDevice: VirtioDevice { fn into_virtio_pci_device( self, - irq_allocator: &mut IrqAllocator, + interrupt_manager: &InterruptManager, tokio_runtime: Handle, memory: Arc, irq_chip: Arc, ) -> Result> { let dev = VirtioPciTransport::new( - irq_allocator, + interrupt_manager, tokio_runtime, memory, irq_chip, @@ -431,12 +437,12 @@ pub trait VirtioPciDevice: VirtioDevice { self, #[cfg(target_arch = "x86_64")] pci_io_window_allocator: &mut RangeAllocator, pci_mmio_window_allocator: &mut RangeAllocator, - irq_allocator: &mut IrqAllocator, + interrupt_manager: &InterruptManager, tokio_runtime: Handle, memory: Arc, irq_chip: Arc, ) -> Result> { - self.into_virtio_pci_device(irq_allocator, tokio_runtime, memory, irq_chip)? + self.into_virtio_pci_device(interrupt_manager, tokio_runtime, memory, irq_chip)? .into_pci_device( #[cfg(target_arch = "x86_64")] pci_io_window_allocator, diff --git a/crates/vm-vmm/src/device/error.rs b/crates/vm-vmm/src/device/error.rs index f9f0c98e..a9c5c516 100644 --- a/crates/vm-vmm/src/device/error.rs +++ b/crates/vm-vmm/src/device/error.rs @@ -2,6 +2,7 @@ use std::error::Error; use thiserror::Error; use vm_core::device::error::DeviceError; +use vm_core::interrupt_manager::InterruptManagerError; use vm_core::utils::address_space::AddressSpaceError; use vm_virtio::result::VirtioError; @@ -25,6 +26,9 @@ pub enum InitDeviceError { #[error("Failed to alloc resource, {0}")] AllocResource(Box), + #[error("Failed to alloc interrupt: {0}")] + AllocInterrupt(#[from] InterruptManagerError), + #[error("Failed to register monitor command for device {device}")] RegisterMonitorCommand { device: String }, diff --git a/crates/vm-vmm/src/vm/config.rs b/crates/vm-vmm/src/vm/config.rs index 87dd68a8..5c72efdf 100644 --- a/crates/vm-vmm/src/vm/config.rs +++ b/crates/vm-vmm/src/vm/config.rs @@ -92,7 +92,7 @@ impl Vm { let device_manager = DeviceManagerBuilder::new( vm_instance.clone(), irq_chip.clone(), - vm_instance.create_irq_allocator()?, + vm_instance.create_irq_manager()?, memory_address_space.clone(), &mut monitor_server_builder, )? diff --git a/crates/vm-vmm/src/vm/device_builder.rs b/crates/vm-vmm/src/vm/device_builder.rs index 76b17457..4d2c8bef 100644 --- a/crates/vm-vmm/src/vm/device_builder.rs +++ b/crates/vm-vmm/src/vm/device_builder.rs @@ -6,7 +6,7 @@ use vm_core::arch::aarch64::layout::*; use vm_core::arch::irq::InterruptController; #[cfg(target_arch = "x86_64")] use vm_core::arch::x86_64::layout::*; -use vm_core::virtualization::irq_allocator::IrqAllocator; +use vm_core::interrupt_manager::InterruptManager; use vm_core::virtualization::vm::HypervisorVm; use vm_device::device::Device; use vm_device::device::VirtioTransport; @@ -40,7 +40,7 @@ mod vfio; pub struct DeviceManagerBuilder<'a> { #[allow(dead_code)] vm: Arc, - irq_allocator: IrqAllocator, + interrupt_manager: Arc, irq_chip: Arc, memory: Arc, monitor_server_builder: &'a mut MonitorServerBuilder, @@ -77,7 +77,7 @@ impl<'a> DeviceManagerBuilder<'a> { self.device_manager .attach_device(Box::new(dev.into_mmio_device( &mut self.mmio_allocator, - &mut self.irq_allocator, + &self.interrupt_manager, &mut self.virtio_mmio_index_allocator, tokio::runtime::Handle::current(), self.memory.clone(), @@ -90,7 +90,7 @@ impl<'a> DeviceManagerBuilder<'a> { #[cfg(target_arch = "x86_64")] self.pci_pio_allocator.get_mut().unwrap(), self.pci_mmio_allocator.get_mut().unwrap(), - &mut self.irq_allocator, + &self.interrupt_manager, tokio::runtime::Handle::current(), self.memory.clone(), self.irq_chip.clone(), @@ -110,7 +110,7 @@ impl<'a> DeviceManagerBuilder<'a> { VirtioTransport::Mmio => { let device = dev.into_mmio_device( &mut self.mmio_allocator, - &mut self.irq_allocator, + &self.interrupt_manager, &mut self.virtio_mmio_index_allocator, tokio::runtime::Handle::current(), self.memory.clone(), @@ -123,7 +123,7 @@ impl<'a> DeviceManagerBuilder<'a> { } VirtioTransport::Pci => { let device = dev.into_virtio_pci_device( - &mut self.irq_allocator, + &self.interrupt_manager, tokio::runtime::Handle::current(), self.memory.clone(), self.irq_chip.clone(), @@ -158,7 +158,7 @@ impl<'a> DeviceManagerBuilder<'a> { self.device_manager .attach_device(Box::new(dev.into_mmio_device( &mut self.mmio_allocator, - &mut self.irq_allocator, + &self.interrupt_manager, &mut self.virtio_mmio_index_allocator, tokio::runtime::Handle::current(), self.memory.clone(), @@ -171,7 +171,7 @@ impl<'a> DeviceManagerBuilder<'a> { #[cfg(target_arch = "x86_64")] self.pci_pio_allocator.get_mut().unwrap(), self.pci_mmio_allocator.get_mut().unwrap(), - &mut self.irq_allocator, + &self.interrupt_manager, tokio::runtime::Handle::current(), self.memory.clone(), self.irq_chip.clone(), @@ -236,10 +236,11 @@ impl<'a> DeviceManagerBuilder<'a> { pub fn new( vm: Arc, irq_chip: Arc, - irq_allocator: IrqAllocator, + interrupt_manager: InterruptManager, memory: Arc, monitor_server_builder: &'a mut MonitorServerBuilder, ) -> Result { + let interrupt_manager = Arc::new(interrupt_manager); let device_manager = DeviceManagerV2::default(); let mut virtio_mmio_index_allocator = RangeAllocator::::default(); @@ -247,7 +248,7 @@ impl<'a> DeviceManagerBuilder<'a> { Ok(DeviceManagerBuilder { vm, - irq_allocator, + interrupt_manager, irq_chip, memory, monitor_server_builder, diff --git a/crates/vm-vmm/src/vm/device_builder/arch/aarch64.rs b/crates/vm-vmm/src/vm/device_builder/arch/aarch64.rs index fe76d72a..5b5c8de8 100644 --- a/crates/vm-vmm/src/vm/device_builder/arch/aarch64.rs +++ b/crates/vm-vmm/src/vm/device_builder/arch/aarch64.rs @@ -29,9 +29,7 @@ impl<'a> DeviceManagerBuilder<'a> { { let pl011 = Pl011::new( &mut self.mmio_allocator, - self.irq_allocator - .alloc() - .map_err(|err| InitDeviceError::AllocResource(Box::new(err)))?, + self.interrupt_manager.allocate_irq()?, self.irq_chip.clone(), )?; self.device_manager.attach_device(Box::new(pl011))?; diff --git a/crates/vm-vmm/src/vm/device_builder/vfio.rs b/crates/vm-vmm/src/vm/device_builder/vfio.rs index 60cb7fec..bfc182bc 100644 --- a/crates/vm-vmm/src/vm/device_builder/vfio.rs +++ b/crates/vm-vmm/src/vm/device_builder/vfio.rs @@ -36,7 +36,7 @@ impl<'a> DeviceManagerBuilder<'a> { #[cfg(target_arch = "x86_64")] self.pci_pio_allocator.get_mut().unwrap(), self.pci_mmio_allocator.get_mut().unwrap(), - &mut self.irq_allocator, + self.interrupt_manager.clone(), vfio_device, )?; diff --git a/crates/vm-vmm/src/vm/snapshot.rs b/crates/vm-vmm/src/vm/snapshot.rs index ac804f09..326887ad 100644 --- a/crates/vm-vmm/src/vm/snapshot.rs +++ b/crates/vm-vmm/src/vm/snapshot.rs @@ -117,7 +117,7 @@ impl Vm { let mut device_manager = DeviceManagerBuilder::new( vm_instance.clone(), irq_chip.clone(), - vm_instance.create_irq_allocator()?, + vm_instance.create_irq_manager()?, memory_address_space.clone(), &mut monitor_server_builder, )? diff --git a/crates/vm-vmm/src/vmm/error.rs b/crates/vm-vmm/src/vmm/error.rs index 809cb420..e613a3ac 100644 --- a/crates/vm-vmm/src/vmm/error.rs +++ b/crates/vm-vmm/src/vmm/error.rs @@ -2,6 +2,7 @@ use thiserror::Error; use vm_core::arch::irq::error::IrqChipError; use vm_core::cpu::error::CpuError; use vm_core::device::error::DeviceSnapshotError; +use vm_core::interrupt_manager::InterruptManagerError; use vm_core::monitor::MonitorError; use vm_core::virtualization::hypervisor::error::HypervisorError; use vm_core::virtualization::vm::error::VmError; @@ -56,6 +57,9 @@ pub enum VmmError { #[error("{0}")] Memory(#[from] vm_mm::error::Error), + #[error("{0}")] + InterruptManager(#[from] InterruptManagerError), + #[error("Failed to setup with bootloader, error: {0}")] Bootloader(#[from] BootloaderError),