[PATCH v6 30/36] KVM: x86: Re-synchronize TSC after KVM_SET_TSC_KHZ
From: David Woodhouse
Date: Fri Jul 03 2026 - 17:45:14 EST
From: David Woodhouse <dwmw@xxxxxxxxxxxx>
KVM_SET_TSC_KHZ changes the vCPU's TSC scaling ratio but does not
update the VM-wide cur_tsc_scaling_ratio used by get_kvmclock().
This causes get_kvmclock() to use a stale (default 1:1) ratio when
computing the KVM clock, leading to drift between the host-side
kvmclock and what the guest observes.
Fix this by calling kvm_synchronize_tsc() after changing the TSC
frequency. This:
- Updates cur_tsc_scaling_ratio (consumed by pvclock_update_vm_gtod_copy)
- Ensures the TSC value is continuous across the frequency change
- Triggers kvm_track_tsc_matching() for proper masterclock handling
- Allows subsequent vCPUs to synchronize via the 1-second slop hack
Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
---
arch/x86/kvm/x86.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 80fe69974ded..37a768b2fe16 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -206,6 +206,7 @@ module_param(mitigate_smt_rsb, bool, 0444);
#ifdef CONFIG_X86_64
static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp);
#endif
+static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value);
#define KVM_MAX_NR_USER_RETURN_MSRS 16
struct kvm_user_return_msrs {
@@ -2584,6 +2585,7 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
{
u32 thresh_lo, thresh_hi;
int use_scaling = 0;
+ u64 tsc;
/* tsc_khz can be zero if TSC calibration fails */
if (user_tsc_khz == 0) {
@@ -2611,7 +2613,17 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz)
user_tsc_khz, thresh_lo, thresh_hi);
use_scaling = 1;
}
- return set_tsc_khz(vcpu, user_tsc_khz, use_scaling);
+ /*
+ * Read the guest TSC before changing the ratio, so we can
+ * re-synchronize to preserve continuity across the change.
+ */
+ tsc = kvm_read_l1_tsc(vcpu, rdtsc());
+
+ if (set_tsc_khz(vcpu, user_tsc_khz, use_scaling))
+ return -1;
+
+ kvm_synchronize_tsc(vcpu, &tsc);
+ return 0;
}
static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
--
2.54.0