Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/vm-core/src/arch/aarch64/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion crates/vm-core/src/arch/x86_64/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
92 changes: 92 additions & 0 deletions crates/vm-core/src/interrupt_manager.rs
Original file line number Diff line number Diff line change
@@ -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<RangeAllocator<u32>>);

impl Allocator {
fn new(start: u32, len: usize) -> Result<Self, InterruptManagerError> {
let mut irq_allocator = RangeAllocator::<u32>::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<Self, InterruptManagerError> {
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<u32, InterruptManagerError> {
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<u32, InterruptManagerError> {
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<u32, InterruptManagerError> {
self.allocate_irq()
.map_err(|_| InterruptManagerError::AllocateGsi)
}
}
1 change: 1 addition & 0 deletions crates/vm-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
1 change: 0 additions & 1 deletion crates/vm-core/src/virtualization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ pub mod hvp;
pub mod kvm;

pub mod hypervisor;
pub mod irq_allocator;
pub mod vcpu;
pub mod vm;
13 changes: 8 additions & 5 deletions crates/vm-core/src/virtualization/hvp/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -135,7 +135,7 @@ impl HypervisorVm for AppleHypervisorVm {
)))
}

fn create_irq_allocator(&self) -> Result<IrqAllocator, VmError> {
fn create_irq_manager(&self) -> Result<InterruptManager, VmError> {
let mut spi_intid_base = 0;
let mut spi_intid_count = 0;
hv_unsafe_call!(hv_gic_get_spi_interrupt_range(
Expand All @@ -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)
}
Expand Down
23 changes: 0 additions & 23 deletions crates/vm-core/src/virtualization/irq_allocator.rs

This file was deleted.

23 changes: 18 additions & 5 deletions crates/vm-core/src/virtualization/kvm/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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;
Expand Down Expand Up @@ -73,8 +77,17 @@ impl HypervisorVm for KvmVm {
Ok(Box::new(irq_chip))
}

fn create_irq_allocator(&self) -> Result<IrqAllocator, VmError> {
Ok(IrqAllocator::new(IRQ_ALLOCATION_START, IRQ_ALLOCATION_END))
fn create_irq_manager(&self) -> Result<InterruptManager, VmError> {
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(
Expand Down
4 changes: 2 additions & 2 deletions crates/vm-core/src/virtualization/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

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

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

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

fn set_user_memory_region(
&self,
Expand Down
5 changes: 3 additions & 2 deletions crates/vm-core/src/virtualization/vm/error.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -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 },
Expand Down
19 changes: 12 additions & 7 deletions crates/vm-vfio/src/vfio_pci/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -71,7 +71,7 @@ const DEBUG_ENABLE_INTX: bool = true;
fn setup_interrupt_capability(
vm: &dyn HypervisorVm,
vfio_device: Arc<VfioDevice>,
irq_allocator: &mut IrqAllocator,
interrupt_manager: &InterruptManager,
raw: &PciConfigurationSpace,
cfg: &mut ConfigurationSpace,
) -> Result<(VfioInterruptInfo, VfioInterruptManager)> {
Expand Down Expand Up @@ -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::<std::result::Result<Vec<_>, _>>()?;
Expand All @@ -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,
Expand Down Expand Up @@ -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))
Expand All @@ -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,
});
Expand All @@ -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 {
Expand Down Expand Up @@ -288,7 +292,7 @@ impl VfioPciDevice {
vm: Arc<dyn HypervisorVm>,
#[cfg(target_arch = "x86_64")] pci_io_window_allocator: &mut RangeAllocator<u16>,
pci_mmio_window_allocator: &mut RangeAllocator<u64>,
irq_allocator: &mut IrqAllocator,
irq_manager: Arc<InterruptManager>,
vfio_device: VfioDevice,
) -> Result<Self> {
let vfio_device = Arc::new(vfio_device);
Expand Down Expand Up @@ -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,
)?;
Expand Down Expand Up @@ -414,6 +418,7 @@ impl VfioPciDevice {

let function = VfioPciFunction::new(
vm,
irq_manager,
raw_configuration_space,
configuration_space,
bar_info,
Expand Down
Loading
Loading