From c9374d87ac453d49185aa7b734df089444166484 Mon Sep 17 00:00:00 2001 From: Michael Zhao Date: Tue, 30 Nov 2021 09:34:23 +0800 Subject: [PATCH] vmm: Update `devid` in `kvm_irq_routing_entry` After introducing multiple PCI segments, the `devid` value in `kvm_irq_routing_entry` exceeds the maximum supported range on AArch64. This commit restructed the `devid` to the allowed range. Signed-off-by: Michael Zhao --- vmm/src/interrupt.rs | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/vmm/src/interrupt.rs b/vmm/src/interrupt.rs index 3b4c2f465..7501dfe31 100644 --- a/vmm/src/interrupt.rs +++ b/vmm/src/interrupt.rs @@ -331,6 +331,7 @@ pub mod kvm { use super::*; use hypervisor::kvm::KVM_MSI_VALID_DEVID; use hypervisor::kvm::{kvm_irq_routing_entry, KVM_IRQ_ROUTING_IRQCHIP, KVM_IRQ_ROUTING_MSI}; + use pci::PciBdf; type KvmRoutingEntry = RoutingEntry; pub type KvmMsiInterruptManager = MsiInterruptManager; @@ -353,8 +354,26 @@ pub mod kvm { kvm_route.u.msi.data = cfg.data; if vm.check_extension(hypervisor::Cap::MsiDevid) { + // On AArch64, there is limitation on the range of the 'devid', + // it can not be greater than 65536 (the max of u16). + // + // BDF can not be used directly, because 'segment' is in high + // 16 bits. The layout of the u32 BDF is: + // |---- 16 bits ----|-- 8 bits --|-- 5 bits --|-- 3 bits --| + // | segment | bus | device | function | + // + // Now that we support 1 bus only in a segment, we can build a + // 'devid' by replacing the 'bus' bits with the low 8 bits of + // 'segment' data. + // This way we can resolve the range checking problem and give + // different `devid` to all the devices. Limitation is that at + // most 256 segments can be supported. + // + let bdf: PciBdf = PciBdf::from(cfg.devid); + let modified_bdf: PciBdf = + PciBdf::new(0, bdf.segment() as u8, bdf.device(), bdf.function()); kvm_route.flags = KVM_MSI_VALID_DEVID; - kvm_route.u.msi.__bindgen_anon_1.devid = cfg.devid; + kvm_route.u.msi.__bindgen_anon_1.devid = modified_bdf.into(); } let kvm_entry = KvmRoutingEntry {