diff --git a/hypervisor/src/cpu.rs b/hypervisor/src/cpu.rs index 578abe4d6..a240c17e2 100644 --- a/hypervisor/src/cpu.rs +++ b/hypervisor/src/cpu.rs @@ -252,6 +252,11 @@ pub enum HypervisorCpuError { /// #[error("Failed to get TSC frequency: {0}")] GetTscKhz(#[source] anyhow::Error), + /// + /// Error setting TSC frequency + /// + #[error("Failed to set TSC frequency: {0}")] + SetTscKhz(#[source] anyhow::Error), } #[derive(Debug)] @@ -447,6 +452,7 @@ pub trait Vcpu: Send + Sync { /// Return the list of initial MSR entries for a VCPU /// fn boot_msr_entries(&self) -> Vec; + #[cfg(target_arch = "x86_64")] /// /// Get the frequency of the TSC if available @@ -454,4 +460,11 @@ pub trait Vcpu: Send + Sync { fn tsc_khz(&self) -> Result> { Ok(None) } + #[cfg(target_arch = "x86_64")] + /// + /// Set the frequency of the TSC if available + /// + fn set_tsc_khz(&self, _freq: u32) -> Result<()> { + Ok(()) + } } diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index c4fa9f74f..cf8cf8e23 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -1890,6 +1890,7 @@ impl cpu::Vcpu for KvmVcpu { }; let vcpu_events = self.get_vcpu_events()?; + let tsc_khz = self.tsc_khz()?; Ok(VcpuKvmState { cpuid, @@ -1902,6 +1903,7 @@ impl cpu::Vcpu for KvmVcpu { xsave, xcrs, mp_state, + tsc_khz, } .into()) } @@ -2004,6 +2006,10 @@ impl cpu::Vcpu for KvmVcpu { self.set_lapic(&state.lapic_state)?; self.set_fpu(&state.fpu)?; + if let Some(freq) = state.tsc_khz { + self.set_tsc_khz(freq)?; + } + // Try to set all MSRs previously stored. // If the number of MSRs set from SET_MSRS is different from the // expected amount, we fallback onto a slower method by setting MSRs @@ -2186,6 +2192,23 @@ impl cpu::Vcpu for KvmVcpu { Ok(v) => Ok(Some(v)), } } + + #[cfg(target_arch = "x86_64")] + /// + /// Set the frequency of the TSC if available + /// + fn set_tsc_khz(&self, freq: u32) -> cpu::Result<()> { + match self.fd.set_tsc_khz(freq) { + Err(e) => { + if e.errno() == libc::EIO { + Ok(()) + } else { + Err(cpu::HypervisorCpuError::SetTscKhz(e.into())) + } + } + Ok(_) => Ok(()), + } + } } impl KvmVcpu { diff --git a/hypervisor/src/kvm/x86_64/mod.rs b/hypervisor/src/kvm/x86_64/mod.rs index 2a0ed6a6d..78da26d60 100644 --- a/hypervisor/src/kvm/x86_64/mod.rs +++ b/hypervisor/src/kvm/x86_64/mod.rs @@ -67,6 +67,7 @@ pub struct VcpuKvmState { pub xsave: Xsave, pub xcrs: ExtendedControlRegisters, pub mp_state: MpState, + pub tsc_khz: Option, } impl From for kvm_regs { diff --git a/vmm/src/seccomp_filters.rs b/vmm/src/seccomp_filters.rs index 7b37e4316..29d2df60f 100644 --- a/vmm/src/seccomp_filters.rs +++ b/vmm/src/seccomp_filters.rs @@ -366,6 +366,7 @@ fn create_vmm_ioctl_seccomp_rule_kvm() -> Result, BackendError> const KVM_SET_LAPIC: u64 = 0x4400_ae8f; const KVM_SET_MSRS: u64 = 0x4008_ae89; const KVM_SET_SREGS: u64 = 0x4138_ae84; + const KVM_SET_TSC_KHZ: u64 = 0xaea2; const KVM_SET_TSS_ADDR: u64 = 0xae47; const KVM_SET_XCRS: u64 = 0x4188_aea7; const KVM_SET_XSAVE: u64 = 0x5000_aea5; @@ -392,6 +393,7 @@ fn create_vmm_ioctl_seccomp_rule_kvm() -> Result, BackendError> and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_IDENTITY_MAP_ADDR)?], and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_LAPIC)?], and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_SREGS)?], + and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_TSC_KHZ)?], and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_TSS_ADDR,)?], and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_MSRS)?], and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_XCRS,)?],