From 3f9e8d676a75a61302396e72dc4d36fa060bc09a Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 10 May 2022 16:47:34 +0100 Subject: [PATCH] hypervisor: Move creation of irq routing struct to hypervisor crate This removes the requirement to leak as many datastructures from the hypervisor crate into the vmm crate. Signed-off-by: Rob Bradford --- Cargo.lock | 1 + hypervisor/Cargo.toml | 3 +- hypervisor/src/kvm/mod.rs | 59 +++++++++++++++++++++++ hypervisor/src/mshv/mod.rs | 22 +++++++++ hypervisor/src/vm.rs | 3 ++ vmm/src/interrupt.rs | 95 +++++--------------------------------- 6 files changed, 98 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e5c180c95..318855cef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -356,6 +356,7 @@ dependencies = [ "serde_derive", "serde_json", "thiserror", + "vm-device", "vm-memory", "vmm-sys-util", ] diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml index f6fe74dd8..92423d9f5 100644 --- a/hypervisor/Cargo.toml +++ b/hypervisor/Cargo.toml @@ -18,11 +18,12 @@ libc = "0.2.125" log = "0.4.17" kvm-ioctls = { version = "0.11.0", optional = true } kvm-bindings = { git = "https://github.com/cloud-hypervisor/kvm-bindings", branch = "ch-v0.5.0-tdx", features = ["with-serde", "fam-wrappers"], optional = true } -mshv-bindings = {git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true } +mshv-bindings = { git = "https://github.com/rust-vmm/mshv", branch = "main", features = ["with-serde", "fam-wrappers"], optional = true } mshv-ioctls = { git = "https://github.com/rust-vmm/mshv", branch = "main", optional = true} serde = { version = "1.0.137", features = ["rc"] } serde_derive = "1.0.137" serde_json = "1.0.81" +vm-device = { path = "../vm-device" } vm-memory = { version = "0.7.0", features = ["backend-mmap", "backend-atomic"] } vmm-sys-util = { version = "0.9.0", features = ["with-serde"] } diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index cfde8b803..19592af1f 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -32,6 +32,7 @@ use std::result; #[cfg(target_arch = "x86_64")] use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, RwLock}; +use vm_device::interrupt::InterruptSourceConfig; use vmm_sys_util::eventfd::EventFd; // x86_64 dependencies #[cfg(target_arch = "x86_64")] @@ -284,6 +285,64 @@ impl vm::Vm for KvmVm { .unregister_ioevent(fd, addr, NoDatamatch) .map_err(|e| vm::HypervisorVmError::UnregisterIoEvent(e.into())) } + + /// + /// Constructs a routing entry + /// + fn make_routing_entry( + &self, + gsi: u32, + config: &InterruptSourceConfig, + ) -> kvm_irq_routing_entry { + match &config { + InterruptSourceConfig::MsiIrq(cfg) => { + let mut kvm_route = kvm_irq_routing_entry { + gsi, + type_: KVM_IRQ_ROUTING_MSI, + ..Default::default() + }; + + kvm_route.u.msi.address_lo = cfg.low_addr; + kvm_route.u.msi.address_hi = cfg.high_addr; + kvm_route.u.msi.data = cfg.data; + + if self.check_extension(crate::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 modified_devid = (cfg.devid & 0x00ff_0000) >> 8 | cfg.devid & 0xff; + + kvm_route.flags = KVM_MSI_VALID_DEVID; + kvm_route.u.msi.__bindgen_anon_1.devid = modified_devid; + } + kvm_route + } + InterruptSourceConfig::LegacyIrq(cfg) => { + let mut kvm_route = kvm_irq_routing_entry { + gsi, + type_: KVM_IRQ_ROUTING_IRQCHIP, + ..Default::default() + }; + kvm_route.u.irqchip.irqchip = cfg.irqchip; + kvm_route.u.irqchip.pin = cfg.pin; + + kvm_route + } + } + } + /// /// Sets the GSI routing table entries, overwriting any previously set /// entries, as per the `KVM_SET_GSI_ROUTING` ioctl. diff --git a/hypervisor/src/mshv/mod.rs b/hypervisor/src/mshv/mod.rs index 539a54cea..3ac344137 100644 --- a/hypervisor/src/mshv/mod.rs +++ b/hypervisor/src/mshv/mod.rs @@ -23,6 +23,7 @@ use vm::DataMatch; #[cfg(target_arch = "x86_64")] pub mod x86_64; use crate::device; +use vm_device::interrupt::InterruptSourceConfig; use vmm_sys_util::eventfd::EventFd; #[cfg(target_arch = "x86_64")] pub use x86_64::VcpuMshvState as CpuState; @@ -957,6 +958,27 @@ impl vm::Vm for MshvVm { .map_err(|e| vm::HypervisorVmError::CreatePassthroughDevice(e.into())) } + /// + /// Constructs a routing entry + /// + fn make_routing_entry( + &self, + gsi: u32, + config: &InterruptSourceConfig, + ) -> mshv_msi_routing_entry { + match config { + InterruptSourceConfig::MsiIrq(cfg) => mshv_msi_routing_entry { + gsi, + address_lo: cfg.low_addr, + address_hi: cfg.high_addr, + data: cfg.data, + }, + _ => { + unreachable!() + } + } + } + fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> { let mut msi_routing = vec_with_array_field::(entries.len()); diff --git a/hypervisor/src/vm.rs b/hypervisor/src/vm.rs index 55682d3a7..9c2076e44 100644 --- a/hypervisor/src/vm.rs +++ b/hypervisor/src/vm.rs @@ -28,6 +28,7 @@ use kvm_ioctls::Cap; use std::fs::File; use std::sync::Arc; use thiserror::Error; +use vm_device::interrupt::InterruptSourceConfig; use vmm_sys_util::eventfd::EventFd; /// @@ -245,6 +246,8 @@ pub trait Vm: Send + Sync { ) -> Result<()>; /// Unregister an event from a certain address it has been previously registered to. fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>; + // Construct a routing entry + fn make_routing_entry(&self, gsi: u32, config: &InterruptSourceConfig) -> IrqRoutingEntry; /// Sets the GSI routing table entries, overwriting any previously set fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>; /// Creates a memory region structure that can be used with {create/remove}_user_memory_region diff --git a/vmm/src/interrupt.rs b/vmm/src/interrupt.rs index a775fedf6..95ef748fb 100644 --- a/vmm/src/interrupt.rs +++ b/vmm/src/interrupt.rs @@ -303,9 +303,7 @@ impl InterruptManager for MsiInterruptManager { #[cfg(feature = "kvm")] 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; + use hypervisor::kvm::kvm_irq_routing_entry; type KvmRoutingEntry = RoutingEntry; pub type KvmMsiInterruptManager = MsiInterruptManager; @@ -316,66 +314,10 @@ pub mod kvm { gsi: u32, config: &InterruptSourceConfig, ) -> Result> { - if let InterruptSourceConfig::MsiIrq(cfg) = &config { - let mut kvm_route = kvm_irq_routing_entry { - gsi, - type_: KVM_IRQ_ROUTING_MSI, - ..Default::default() - }; - - kvm_route.u.msi.address_lo = cfg.low_addr; - kvm_route.u.msi.address_hi = cfg.high_addr; - 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 = modified_bdf.into(); - } - - let kvm_entry = KvmRoutingEntry { - route: kvm_route, - masked: false, - }; - - return Ok(Box::new(kvm_entry)); - } else if let InterruptSourceConfig::LegacyIrq(cfg) = &config { - let mut kvm_route = kvm_irq_routing_entry { - gsi, - type_: KVM_IRQ_ROUTING_IRQCHIP, - ..Default::default() - }; - kvm_route.u.irqchip.irqchip = cfg.irqchip; - kvm_route.u.irqchip.pin = cfg.pin; - let kvm_entry = KvmRoutingEntry { - route: kvm_route, - masked: false, - }; - - return Ok(Box::new(kvm_entry)); - } - - Err(io::Error::new( - io::ErrorKind::Other, - "Interrupt config type not supported", - )) + Ok(Box::new(Self { + masked: false, + route: vm.make_routing_entry(gsi, config), + })) } } } @@ -383,36 +325,21 @@ pub mod kvm { #[cfg(feature = "mshv")] pub mod mshv { use super::*; - use hypervisor::mshv::*; + use hypervisor::mshv::mshv_msi_routing_entry; type MshvRoutingEntry = RoutingEntry; pub type MshvMsiInterruptManager = MsiInterruptManager; impl MshvRoutingEntry { pub fn make_entry( - _vm: &Arc, + vm: &Arc, gsi: u32, config: &InterruptSourceConfig, ) -> Result> { - if let InterruptSourceConfig::MsiIrq(cfg) = &config { - let route = mshv_msi_routing_entry { - gsi, - address_lo: cfg.low_addr, - address_hi: cfg.high_addr, - data: cfg.data, - }; - let entry = MshvRoutingEntry { - route, - masked: false, - }; - - return Ok(Box::new(entry)); - } - - Err(io::Error::new( - io::ErrorKind::Other, - "Interrupt config type not supported", - )) + Ok(Box::new(Self { + masked: false, + route: vm.make_routing_entry(gsi, config), + })) } } }