From 9e1e3086e710275583adfadc9e74fbc57cba9232 Mon Sep 17 00:00:00 2001 From: Liu Jiang Date: Sat, 5 Jun 2021 15:53:31 +0800 Subject: [PATCH 1/2] Add method to query KVM_CAP_X86_DISABLE_EXITS Add method to query KVM_CAP_X86_DISABLE_EXITS for x86 platforms. Signed-off-by: Liu Jiang --- src/cap.rs | 2 ++ src/ioctls/system.rs | 42 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) 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..b288ad43 100644 --- a/src/ioctls/system.rs +++ b/src/ioctls/system.rs @@ -239,6 +239,32 @@ impl Kvm { } } + /// 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 + } + } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn get_cpuid(&self, kind: u64, num_entries: usize) -> Result { if num_entries > KVM_MAX_CPUID_ENTRIES { @@ -542,7 +568,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 +626,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(); From a04ad9b04217798470034a6ca4046916ce73b479 Mon Sep 17 00:00:00 2001 From: Liu Jiang Date: Sat, 5 Jun 2021 16:07:43 +0800 Subject: [PATCH 2/2] Correctly handle error from check_extension_int() Kvm::check_extension_int() may return negative value as error code, so Kvm::get_max_vcpus() and Kvm::get_max_vcpu_id() should handle the error cases. Signed-off-by: Liu Jiang --- src/ioctls/system.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ioctls/system.rs b/src/ioctls/system.rs index b288ad43..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,12 @@ 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 } }