From 5549d846da6f6c13eade15bad94f49b0885caf4a Mon Sep 17 00:00:00 2001 From: Anirudh Rayabharam Date: Tue, 12 Aug 2025 17:00:45 +0000 Subject: [PATCH] vmm: support firmware boot on mshv arm64 MSHV (Microsoft Hypervisor) doesn't expose an ITS to guests. Instead it exposes a GICv2m MSI Frame for mapping MSIs to SPIs. Update the MADT generation code to create the GIC MSI Frame structure instead of the ITS structure whenever the guest vGIC is using a GICv2m frame. This allows booting guests via firmware on MSHV. Signed-off-by: Anirudh Rayabharam --- vmm/src/acpi.rs | 17 ++++++++++++++- vmm/src/cpu.rs | 56 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/vmm/src/acpi.rs b/vmm/src/acpi.rs index de2f58129..5a8ab2580 100644 --- a/vmm/src/acpi.rs +++ b/vmm/src/acpi.rs @@ -39,6 +39,8 @@ pub const ACPI_APIC_GENERIC_CPU_INTERFACE: u8 = 11; #[cfg(target_arch = "aarch64")] pub const ACPI_APIC_GENERIC_DISTRIBUTOR: u8 = 12; #[cfg(target_arch = "aarch64")] +pub const ACPI_APIC_GIC_MSI_FRAME: u8 = 13; +#[cfg(target_arch = "aarch64")] pub const ACPI_APIC_GENERIC_REDISTRIBUTOR: u8 = 14; #[cfg(target_arch = "aarch64")] pub const ACPI_APIC_GENERIC_TRANSLATOR: u8 = 15; @@ -649,7 +651,20 @@ fn create_acpi_tables_internal( xsdt_table_pointers.push(facp_addr.0); // MADT - let madt = cpu_manager.lock().unwrap().create_madt(); + #[cfg(target_arch = "aarch64")] + let vgic = device_manager + .lock() + .unwrap() + .get_interrupt_controller() + .unwrap() + .lock() + .unwrap() + .get_vgic() + .unwrap(); + let madt = cpu_manager.lock().unwrap().create_madt( + #[cfg(target_arch = "aarch64")] + vgic, + ); let madt_addr = facp_addr.checked_add(facp.len() as u64).unwrap(); tables_bytes.extend_from_slice(madt.as_slice()); xsdt_table_pointers.push(madt_addr.0); diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index 8eb552297..01a51f152 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -41,6 +41,8 @@ use hypervisor::CpuVendor; use hypervisor::HypervisorType; #[cfg(feature = "guest_debug")] use hypervisor::StandardRegisters; +#[cfg(target_arch = "aarch64")] +use hypervisor::arch::aarch64::gic::Vgic; #[cfg(all(target_arch = "aarch64", feature = "guest_debug"))] use hypervisor::arch::aarch64::regs::{ID_AA64MMFR0_EL1, TCR_EL1, TTBR1_EL1}; #[cfg(target_arch = "x86_64")] @@ -274,6 +276,21 @@ struct GicD { pub reserved1: [u8; 3], } +#[cfg(target_arch = "aarch64")] +#[allow(dead_code)] +#[repr(C, packed)] +#[derive(IntoBytes, Immutable, FromBytes)] +struct GicMsiFrame { + pub r#type: u8, + pub length: u8, + pub reserved0: u16, + pub msi_frame_id: u32, + pub base_address: u64, + pub flags: u32, + pub spi_count: u16, + pub spi_base: u16, +} + #[cfg(target_arch = "aarch64")] #[allow(dead_code)] #[repr(C, packed)] @@ -1471,7 +1488,7 @@ impl CpuManager { } #[cfg(not(target_arch = "riscv64"))] - pub fn create_madt(&self) -> Sdt { + pub fn create_madt(&self, #[cfg(target_arch = "aarch64")] vgic: Arc>) -> Sdt { use crate::acpi; // This is also checked in the commandline parsing. assert!(self.config.boot_vcpus <= self.config.max_vcpus); @@ -1520,6 +1537,8 @@ impl CpuManager { #[cfg(target_arch = "aarch64")] { + use arch::layout::{GIC_V2M_COMPATIBLE, SPI_BASE, SPI_NUM}; + /* Notes: * Ignore Local Interrupt Controller Address at byte offset 36 of MADT table. */ @@ -1585,16 +1604,31 @@ impl CpuManager { }; madt.append(gicr); - // See 5.2.12.18 GIC Interrupt Translation Service (ITS) Structure in ACPI spec. - let gicits = GicIts { - r#type: acpi::ACPI_APIC_GENERIC_TRANSLATOR, - length: 20, - reserved0: 0, - translation_id: 0, - base_address: vgic_config.msi_addr, - reserved1: 0, - }; - madt.append(gicits); + if vgic.lock().unwrap().msi_compatibility() == GIC_V2M_COMPATIBLE { + // See 5.2.12.16 GIC MSI Frame Structure in ACPI spec. + let gic_msi_frame = GicMsiFrame { + r#type: acpi::ACPI_APIC_GIC_MSI_FRAME, + length: 24, + reserved0: 0, + msi_frame_id: 0, + base_address: vgic_config.msi_addr, + flags: 1, + spi_count: SPI_NUM as u16, + spi_base: SPI_BASE as u16, + }; + madt.append(gic_msi_frame); + } else { + // See 5.2.12.18 GIC Interrupt Translation Service (ITS) Structure in ACPI spec. + let gicits = GicIts { + r#type: acpi::ACPI_APIC_GENERIC_TRANSLATOR, + length: 20, + reserved0: 0, + translation_id: 0, + base_address: vgic_config.msi_addr, + reserved1: 0, + }; + madt.append(gicits); + } madt.update_checksum(); }