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 src/arch/src/aarch64/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub const FDT_MAX_SIZE: usize = 0x20_0000;
pub const IRQ_BASE: u32 = 32;

/// Last usable interrupt on aarch64.
pub const IRQ_MAX: u32 = 159;
pub const IRQ_MAX: u32 = 223;

/// Timer interrupts
pub const GTIMER_SEC: u32 = 13;
Expand Down
4 changes: 2 additions & 2 deletions src/arch/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ pub mod x86_64;
#[cfg(target_arch = "x86_64")]
pub use crate::x86_64::{
arch_memory_regions, configure_system, layout::CMDLINE_MAX_SIZE, layout::FIRMWARE_SIZE,
layout::FIRMWARE_START, layout::IRQ_BASE, layout::IRQ_MAX, layout::MMIO_MEM_START,
layout::RESET_VECTOR, Error,
layout::FIRMWARE_START, layout::IRQ_BASE, layout::IRQ_MAX, layout::IRQ_MAX_SPLIT,
layout::MMIO_MEM_START, layout::RESET_VECTOR, Error,
};

/// Type for returning public functions outcome.
Expand Down
6 changes: 5 additions & 1 deletion src/arch/src/x86_64/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,12 @@ pub const HIMEM_START: u64 = 0x0010_0000; //1 MB.
// Typically, on x86 systems 16 IRQs are used (0-15).
/// First usable IRQ ID for virtio device interrupts on x86_64.
pub const IRQ_BASE: u32 = 5;
/// Last usable IRQ ID for virtio device interrupts on x86_64.
/// Last usable IRQ ID for virtio device interrupts on x86_64 when using
/// KVM's in-kernel IOAPIC (hardcoded to 24 pins by KVM_IOAPIC_NUM_PINS).
pub const IRQ_MAX: u32 = 15;
/// Last usable IRQ ID when using the userspace split irqchip, which
/// emulates an IOAPIC with `IOAPIC_NUM_PINS` redirection entries.
pub const IRQ_MAX_SPLIT: u32 = 223;

/// Address for the TSS setup.
pub const KVM_TSS_ADDRESS: u64 = 0xfffb_d000;
Expand Down
4 changes: 2 additions & 2 deletions src/cpuid/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// SPDX-License-Identifier: Apache-2.0

#[cfg(target_arch = "x86")]
use std::arch::x86::{CpuidResult, __cpuid_count, __get_cpuid_max};
use std::arch::x86::{__cpuid_count, __get_cpuid_max, CpuidResult};
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::{CpuidResult, __cpuid_count, __get_cpuid_max};
use std::arch::x86_64::{__cpuid_count, __get_cpuid_max, CpuidResult};

use crate::cpu_leaf::*;

Expand Down
6 changes: 4 additions & 2 deletions src/devices/src/legacy/ioapic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::Error as DeviceError;

const IOAPIC_BASE: u32 = 0xfec0_0000;
const APIC_DEFAULT_ADDRESS: u32 = 0xfee0_0000;
const IOAPIC_NUM_PINS: usize = 24;
const IOAPIC_NUM_PINS: usize = 256;

const IO_REG_SEL: u64 = 0x00;
const IO_WIN: u64 = 0x10;
Expand Down Expand Up @@ -114,7 +114,9 @@ impl IoApic {
cap: KVM_CAP_SPLIT_IRQCHIP,
..Default::default()
};
cap.args[0] = 24;
// args[0] is the number of GSIs reserved for the userspace IOAPIC;
// must match the emulated IOAPIC's pin count.
cap.args[0] = IOAPIC_NUM_PINS as u64;
vm.enable_cap(&cap)?;
}

Expand Down
4 changes: 3 additions & 1 deletion src/devices/src/legacy/kvmgicv2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ impl KvmGicV2 {
};
device_fd.set_device_attr(&attr).unwrap();

let nr_irqs: u32 = arch::aarch64::layout::IRQ_MAX - arch::aarch64::layout::IRQ_BASE + 1;
// GIC nr_irqs includes 32 private interrupts (SGIs + PPIs), so we need
// the SPI count plus 32, rounded up to a multiple of 32.
let nr_irqs: u32 = (arch::aarch64::layout::IRQ_MAX + 1).div_ceil(32) * 32;
let nr_irqs_ptr = &nr_irqs as *const u32;
let attr = kvm_bindings::kvm_device_attr {
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
Expand Down
4 changes: 3 additions & 1 deletion src/devices/src/legacy/kvmgicv3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ impl KvmGicV3 {
};
device_fd.set_device_attr(&attr)?;

let nr_irqs: u32 = arch::aarch64::layout::IRQ_MAX - arch::aarch64::layout::IRQ_BASE + 1;
// GIC nr_irqs includes 32 private interrupts (SGIs + PPIs), so we need
// the SPI count plus 32, rounded up to a multiple of 32.
let nr_irqs: u32 = (arch::aarch64::layout::IRQ_MAX + 1).div_ceil(32) * 32;
let nr_irqs_ptr = &nr_irqs as *const u32;
let attr = kvm_bindings::kvm_device_attr {
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
Expand Down
2 changes: 1 addition & 1 deletion src/devices/src/virtio/snd/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ impl SndWorker {
{
self.streams.write().unwrap()[stream_id as usize]
.buffers
.extend(std::mem::take(&mut buffers).into_iter());
.extend(std::mem::take(&mut buffers));
state = IoState::Done;
}
IoState::Ready if descriptor.len as usize != size_of::<VirtioSoundPcmXfer>() => {
Expand Down
1 change: 1 addition & 0 deletions src/krun/src/api/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ impl VmBuilder {
vmr.set_vm_config(&vm_config)
.map_err(|err| map_vm_config_error(&self.machine, err))?;
vmr.nested_enabled = self.machine.nested_virt;
vmr.split_irqchip = self.machine.split_irqchip;

// Apply filesystem configuration
#[cfg(not(feature = "tee"))]
Expand Down
15 changes: 15 additions & 0 deletions src/krun/src/api/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub struct MachineBuilder {
pub(crate) memory_mib: usize,
pub(crate) hyperthreading: bool,
pub(crate) nested_virt: bool,
pub(crate) split_irqchip: bool,
}

//--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -296,6 +297,7 @@ impl MachineBuilder {
memory_mib: 512,
hyperthreading: false,
nested_virt: false,
split_irqchip: false,
}
}

Expand All @@ -322,6 +324,19 @@ impl MachineBuilder {
self.nested_virt = enabled;
self
}

/// Enable the userspace split irqchip on x86_64.
///
/// The default in-kernel IOAPIC is hardcoded by KVM to 24 pins, leaving
/// only 11 IRQs for virtio-mmio devices. The userspace split irqchip
/// emulates a larger IOAPIC (256 pins) and raises the usable range to
/// 219 IRQs, which is needed for VMs with many virtio-mmio devices
/// (e.g. lots of virtio-fs mounts or block devices). No effect on
/// aarch64 or riscv64.
pub fn split_irqchip(mut self, enabled: bool) -> Self {
self.split_irqchip = enabled;
self
}
}

impl Default for MachineBuilder {
Expand Down
16 changes: 12 additions & 4 deletions src/vmm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,13 @@ use crate::vmm_config::net::NetBuilder;
use devices::legacy::Cmos;
#[cfg(all(target_os = "linux", target_arch = "riscv64"))]
use devices::legacy::KvmAia;
#[cfg(target_arch = "x86_64")]
use devices::legacy::KvmIoapic;
use devices::legacy::Serial;
#[cfg(target_os = "macos")]
use devices::legacy::VcpuList;
#[cfg(target_os = "macos")]
use devices::legacy::{GicV3, HvfGicV3};
#[cfg(target_arch = "x86_64")]
use devices::legacy::{IoApic, IrqChipT};
use devices::legacy::{IoApic, IrqChipT, KvmIoapic};
use devices::legacy::{IrqChip, IrqChipDevice};
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
use devices::legacy::{KvmGicV2, KvmGicV3};
Expand Down Expand Up @@ -801,10 +799,18 @@ pub fn build_microvm(
// Instantiate the MMIO device manager.
// 'mmio_base' address has to be an address which is protected by the kernel
// and is architectural specific.
#[cfg(target_arch = "x86_64")]
let irq_max = if vm_resources.split_irqchip {
arch::IRQ_MAX_SPLIT
} else {
arch::IRQ_MAX
};
#[cfg(not(target_arch = "x86_64"))]
let irq_max = arch::IRQ_MAX;
#[allow(unused_mut)]
let mut mmio_device_manager = MMIODeviceManager::new(
&mut (arch::MMIO_MEM_START.clone()),
(arch::IRQ_BASE, arch::IRQ_MAX),
(arch::IRQ_BASE, irq_max),
);

#[cfg(target_os = "macos")]
Expand All @@ -819,6 +825,8 @@ pub fn build_microvm(
// while on aarch64 we need to do it the other way around.
#[cfg(target_arch = "x86_64")]
{
// Userspace split irqchip is required for >11 virtio IRQs, since KVM's
// in-kernel IOAPIC is hardcoded at 24 pins (KVM_IOAPIC_NUM_PINS).
let ioapic: Box<dyn IrqChipT> = if vm_resources.split_irqchip {
Box::new(
IoApic::new(vm.fd(), _sender.clone())
Expand Down
2 changes: 1 addition & 1 deletion src/vmm/src/device_manager/kvm/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ mod tests {
#[cfg(target_arch = "aarch64")]
let _gic = KvmGicV3::new(vm.fd(), 1).unwrap();

let mut cmdline = kernel_cmdline::Cmdline::new(4096);
let mut cmdline = kernel_cmdline::Cmdline::new(16384);

for _i in arch::IRQ_BASE..=arch::IRQ_MAX {
device_manager
Expand Down
Loading