diff --git a/alioth/src/hv/kvm/kvm.rs b/alioth/src/hv/kvm/kvm.rs index b313d0b1..97f5db65 100644 --- a/alioth/src/hv/kvm/kvm.rs +++ b/alioth/src/hv/kvm/kvm.rs @@ -31,6 +31,7 @@ use std::arch::x86_64::CpuidResult; use std::collections::HashMap; use std::fs::File; use std::mem::{size_of, transmute}; +use std::num::NonZero; use std::os::fd::OwnedFd; use std::path::Path; use std::ptr::null_mut; @@ -78,8 +79,6 @@ pub enum KvmError { MmapVcpuFd { error: std::io::Error }, #[snafu(display("Failed to check KVM capability"))] CheckCap { error: std::io::Error }, - #[snafu(display("KVM Capability {ext:?} not supported"))] - NotSupported { ext: KvmCap }, #[snafu(display("Failed to enable capability {cap:?}"))] EnableCap { cap: KvmCap, error: std::io::Error }, #[snafu(display("Failed to create guest memfd"))] @@ -141,13 +140,8 @@ impl Kvm { }) } - pub fn check_extension(&self, id: KvmCap) -> Result { - let ret = unsafe { kvm_check_extension(&self.fd, id) }.context(kvm_error::CheckCap)?; - if ret == 0 { - kvm_error::NotSupported { ext: id }.fail() - } else { - Ok(ret) - } + pub fn check_extension(&self, id: KvmCap) -> Result> { + check_extension(&self.fd, id) } } @@ -163,3 +157,12 @@ impl Hypervisor for Kvm { Kvm::get_supported_cpuids(self) } } + +fn check_extension(fd: &OwnedFd, id: KvmCap) -> Result> { + let ret = unsafe { kvm_check_extension(fd, id) }.context(kvm_error::CheckCap)?; + if let Some(v) = NonZero::new(ret) { + Ok(v) + } else { + error::Capability { cap: id.name() }.fail() + } +} diff --git a/alioth/src/hv/kvm/kvm_x86_64.rs b/alioth/src/hv/kvm/kvm_x86_64.rs index 8e8f8ac1..2691ae22 100644 --- a/alioth/src/hv/kvm/kvm_x86_64.rs +++ b/alioth/src/hv/kvm/kvm_x86_64.rs @@ -56,18 +56,17 @@ impl Kvm { .map(map_f) .collect(); - // Enable KVM_FEATURE_MSI_EXT_DEST_ID if KVM_CAP_X2APIC_API is supported - let ext = self.check_extension(KvmCap::X2APIC_API)?; - let flag = KvmX2apicApiFlag::from_bits_retain(ext as u64); - let x2apic_flags = - KvmX2apicApiFlag::USE_32BIT_IDS | KvmX2apicApiFlag::DISABLE_BROADCAST_QUIRK; let leaf_features = CpuidIn { func: KVM_CPUID_FEATURES, index: None, }; if let Some(entry) = cpuids.get_mut(&leaf_features) - && flag.contains(x2apic_flags) + && let Ok(ext) = self.check_extension(KvmCap::X2APIC_API) + && KvmX2apicApiFlag::from_bits_retain(ext.get() as u64).contains( + KvmX2apicApiFlag::USE_32BIT_IDS | KvmX2apicApiFlag::DISABLE_BROADCAST_QUIRK, + ) { + // Enable KVM_FEATURE_MSI_EXT_DEST_ID if KVM_CAP_X2APIC_API is supported entry.eax |= KvmCpuidFeature::MSI_EXT_DEST_ID.bits(); } diff --git a/alioth/src/hv/kvm/vm/vm.rs b/alioth/src/hv/kvm/vm/vm.rs index 642fdf99..ebdb1d1f 100644 --- a/alioth/src/hv/kvm/vm/vm.rs +++ b/alioth/src/hv/kvm/vm/vm.rs @@ -22,6 +22,7 @@ mod x86_64; use std::collections::HashMap; use std::fmt::{self, Display, Formatter}; use std::io::ErrorKind; +use std::num::NonZero; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd}; use std::os::unix::thread::JoinHandleExt; use std::sync::Arc; @@ -36,7 +37,7 @@ use snafu::ResultExt; use crate::arch::sev::{SevPolicy, SnpPageType, SnpPolicy}; use crate::ffi; use crate::hv::kvm::vcpu::KvmVcpu; -use crate::hv::kvm::{KvmError, kvm_error}; +use crate::hv::kvm::{KvmError, check_extension, kvm_error}; use crate::hv::{ Error, IoeventFd, IoeventFdRegistry, IrqFd, IrqSender, Kvm, MemMapOption, MsiSender, Result, Vm, VmConfig, VmMemory, error, @@ -49,11 +50,10 @@ use crate::sys::kvm::{ KVM_IRQ_ROUTING_IRQCHIP, KVM_IRQ_ROUTING_MSI, KvmCap, KvmEnableCap, KvmEncRegion, KvmIoEventFd, KvmIoEventFdFlag, KvmIrqRouting, KvmIrqRoutingEntry, KvmIrqRoutingIrqchip, KvmIrqRoutingMsi, KvmIrqfd, KvmIrqfdFlag, KvmMemFlag, KvmMemoryAttribute, KvmMemoryAttributes, KvmMsi, - KvmUserspaceMemoryRegion, KvmUserspaceMemoryRegion2, kvm_check_extension, kvm_create_vm, - kvm_enable_cap, kvm_get_vcpu_mmap_size, kvm_ioeventfd, kvm_irqfd, - kvm_memory_encrypt_reg_region, kvm_memory_encrypt_unreg_region, kvm_set_gsi_routing, - kvm_set_memory_attributes, kvm_set_user_memory_region, kvm_set_user_memory_region2, - kvm_signal_msi, + KvmUserspaceMemoryRegion, KvmUserspaceMemoryRegion2, kvm_create_vm, kvm_enable_cap, + kvm_get_vcpu_mmap_size, kvm_ioeventfd, kvm_irqfd, kvm_memory_encrypt_reg_region, + kvm_memory_encrypt_unreg_region, kvm_set_gsi_routing, kvm_set_memory_attributes, + kvm_set_user_memory_region, kvm_set_user_memory_region2, kvm_signal_msi, }; #[cfg(target_arch = "aarch64")] @@ -124,13 +124,8 @@ impl VmInner { Ok(()) } - pub fn check_extension(&self, id: KvmCap) -> Result { - let ret = unsafe { kvm_check_extension(&self.fd, id) }.context(kvm_error::CheckCap)?; - if ret == 0 { - kvm_error::NotSupported { ext: id }.fail() - } else { - Ok(ret) - } + pub fn check_extension(&self, id: KvmCap) -> Result> { + check_extension(&self.fd, id) } pub fn enable_cap(&self, cap: &KvmEnableCap) -> Result<(), KvmError> { @@ -692,12 +687,7 @@ impl Vm for KvmVm { &self, #[cfg(target_arch = "aarch64")] devid: u32, ) -> Result { - if self.vm.check_extension(KvmCap::SIGNAL_MSI)? == 0 { - return error::Capability { - cap: "KVM_CAP_SIGNAL_MSI", - } - .fail(); - } + self.vm.check_extension(KvmCap::SIGNAL_MSI)?; Ok(KvmMsiSender { vm: self.vm.clone(), #[cfg(target_arch = "aarch64")] diff --git a/alioth/src/hv/kvm/vm/vm_x86_64.rs b/alioth/src/hv/kvm/vm/vm_x86_64.rs index 27086caf..5b1aabac 100644 --- a/alioth/src/hv/kvm/vm/vm_x86_64.rs +++ b/alioth/src/hv/kvm/vm/vm_x86_64.rs @@ -97,7 +97,7 @@ impl KvmVm { } } Some(Coco::AmdSnp { .. }) => { - let bitmap = self.vm.check_extension(KvmCap::EXIT_HYPERCALL)?; + let bitmap = self.vm.check_extension(KvmCap::EXIT_HYPERCALL)?.get(); let request = KvmEnableCap { cap: KvmCap::EXIT_HYPERCALL, args: [bitmap as _, 0, 0, 0], diff --git a/alioth/src/utils/utils.rs b/alioth/src/utils/utils.rs index ebf65302..8b4e30ac 100644 --- a/alioth/src/utils/utils.rs +++ b/alioth/src/utils/utils.rs @@ -140,6 +140,14 @@ macro_rules! c_enum { pub const fn raw(self) -> $TyName { self.0 } + + #[allow(dead_code)] + pub const fn name(self) -> &'static str { + match self { + $($EnumName::$VARIANT => stringify!($VARIANT),)* + _ => "Unknown" + } + } } impl ::core::fmt::Debug for $EnumName {