diff --git a/src/cap.rs b/src/cap.rs index f44d41f7..c32de022 100644 --- a/src/cap.rs +++ b/src/cap.rs @@ -139,6 +139,8 @@ pub enum Cap { S390UserSigp = KVM_CAP_S390_USER_SIGP, #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] SplitIrqchip = KVM_CAP_SPLIT_IRQCHIP, + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + DisableExits = KVM_CAP_X86_DISABLE_EXITS, ImmediateExit = KVM_CAP_IMMEDIATE_EXIT, ArmVmIPASize = KVM_CAP_ARM_VM_IPA_SIZE, MsiDevid = KVM_CAP_MSI_DEVID, diff --git a/src/ioctls/system.rs b/src/ioctls/system.rs index 150b5544..5176a2c3 100644 --- a/src/ioctls/system.rs +++ b/src/ioctls/system.rs @@ -213,9 +213,12 @@ impl Kvm { /// assert!(kvm.get_max_vcpus() > 0); /// ``` pub fn get_max_vcpus(&self) -> usize { - match self.check_extension_int(Cap::MaxVcpus) { - 0 => self.get_nr_vcpus(), - x => x as usize, + let v = self.check_extension_int(Cap::MaxVcpus); + + if v <= 0 { + self.get_nr_vcpus() + } else { + v as usize } } @@ -233,9 +236,38 @@ impl Kvm { /// assert!(kvm.get_max_vcpu_id() > 0); /// ``` pub fn get_max_vcpu_id(&self) -> usize { - match self.check_extension_int(Cap::MaxVcpuId) { - 0 => self.get_max_vcpus(), - x => x as usize, + let v = self.check_extension_int(Cap::MaxVcpuId); + + if v <= 0 { + self.get_max_vcpus() + } else { + v as usize + } + } + + /// Returns the "disable idle exiting" capability. + /// + /// The `KVM_CAP_X86_DISABLE_EXITS` capability provides userspace with per-VM capability + /// to not intercept MWAIT/HLT/PAUSE/CSTATE, which means though instructions won't cause + /// vm-exits and helps to improve latency in some workloads. + /// + /// # Example + /// + /// ``` + /// # extern crate kvm_bindings; + /// # use kvm_bindings::{KVM_X86_DISABLE_EXITS_HLT, KVM_X86_DISABLE_EXITS_PAUSE}; + /// # use kvm_ioctls::Kvm; + /// let kvm = Kvm::new().unwrap(); + /// assert!(kvm.get_disable_exits() & KVM_X86_DISABLE_EXITS_HLT != 0); + /// assert!(kvm.get_disable_exits() & KVM_X86_DISABLE_EXITS_PAUSE != 0); + /// ``` + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub fn get_disable_exits(&self) -> u32 { + let x = self.check_extension_int(Cap::DisableExits); + if x > 0 { + x as u32 + } else { + 0 } } @@ -542,7 +574,9 @@ impl FromRawFd for Kvm { mod tests { use super::*; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - use kvm_bindings::KVM_MAX_CPUID_ENTRIES; + use kvm_bindings::{ + KVM_MAX_CPUID_ENTRIES, KVM_X86_DISABLE_EXITS_HLT, KVM_X86_DISABLE_EXITS_PAUSE, + }; use libc::{fcntl, FD_CLOEXEC, F_GETFD}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use vmm_sys_util::fam::FamStruct; @@ -598,6 +632,18 @@ mod tests { assert!(kvm.get_nr_memslots() >= 32); } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + #[test] + fn test_kvm_get_disable_exits() { + let kvm = Kvm::new().unwrap(); + let disable_exits = kvm.get_disable_exits(); + + if disable_exits != 0 { + assert!(disable_exits & KVM_X86_DISABLE_EXITS_HLT != 0); + assert!(disable_exits & KVM_X86_DISABLE_EXITS_PAUSE != 0); + } + } + #[test] fn test_create_vm() { let kvm = Kvm::new().unwrap();