From 633d7652f80f817ef4980153fc9fd58d77c75d0c Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 3 Jul 2026 22:17:40 +0100 Subject: [PATCH 1/3] KVM: x86/xen: Do not corrupt KVM clock in kvm_xen_shared_info_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KVM clock is an interesting thing. It is defined as "nanoseconds since the guest was created", but in practice it runs at two *different* rates — or three different rates, if you count implementation bugs. Definition A is that it runs synchronously with the CLOCK_MONOTONIC_RAW of the host, with a delta of kvm->arch.kvmclock_offset. But that version doesn't actually get used in the common case, where the host has a reliable TSC and the guest TSCs are all running at the same rate and in sync with each other, and kvm->arch.use_master_clock is set. In that common case, definition B is used: There is a reference point in time at kvm->arch.master_kernel_ns (again a CLOCK_MONOTONIC_RAW time), and a corresponding host TSC value kvm->arch.master_cycle_now. This fixed point in time is converted to guest units (the time offset by kvmclock_offset and the TSC Value scaled and offset to be a guest TSC value) and advertised to the guest in the pvclock structure. While in this 'use_master_clock' mode, the fixed point in time never needs to be changed, and the clock runs precisely in time with the guest TSC, at the rate advertised in the pvclock structure. The third definition C is implemented in kvm_get_wall_clock_epoch() and __get_kvmclock(), using the master_cycle_now and master_kernel_ns fields but converting the *host* TSC cycles directly to a value in nanoseconds instead of scaling via the guest TSC. One might naïvely think that all three definitions are identical, since CLOCK_MONOTONIC_RAW is not skewed by NTP frequency corrections; all three are just the result of counting the host TSC at a known frequency, or the scaled guest TSC at a known precise fraction of the host's frequency. The problem is with arithmetic precision, and the way that frequency scaling is done in a division-free way by multiplying by a scale factor, then shifting right. In practice, all three ways of calculating the KVM clock will suffer a systemic drift from each other. Eventually, definition C should just be eliminated. Commit 451a707813ae ("KVM: x86/xen: improve accuracy of Xen timers") worked around it for the specific case of Xen timers, which are defined in terms of the KVM clock and suffered from a continually increasing error in timer expiry times. That commit notes that get_kvmclock_ns() is non-trivial to fix and says "I'll come back to that", which remains true. Definitions A and B do need to coexist, the former to handle the case where the host or guest TSC is suboptimally configured. But KVM should be more careful about switching between them, and the discontinuity in guest time which could result. In particular, KVM_REQ_MASTERCLOCK_UPDATE will take a new snapshot of time as the reference in master_kernel_ns and master_cycle_now, yanking the guest's clock back to match definition A at that moment. When invoked from in 'use_master_clock' mode, kvm_update_masterclock() should probably *adjust* kvm->arch.kvmclock_offset to account for the drift, instead of yanking the clock back to definition A. But in the meantime there are a bunch of places where it just doesn't need to be invoked at all. To start with: there is no need to do such an update when a Xen guest populates the shared_info page. This seems to have been a hangover from the very first implementation of shared_info which automatically populated the vcpu_info structures at their default locations, but even then it should just have raised KVM_REQ_CLOCK_UPDATE on each vCPU instead of using KVM_REQ_MASTERCLOCK_UPDATE. And now that userspace is expected to explicitly set the vcpu_info even in its default locations, there's not even any need for that either. Fixes: 629b5348841a ("KVM: x86/xen: update wallclock region") Reviewed-by: Paul Durrant Signed-off-by: David Woodhouse Signed-off-by: Sean Christopherson --- arch/x86/kvm/xen.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 694b31c1fcc9..913cbd52ce6c 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -98,8 +98,6 @@ static int kvm_xen_shared_info_init(struct kvm *kvm) wc->version = wc_version + 1; read_unlock_irq(&gpc->lock); - kvm_make_all_cpus_request(kvm, KVM_REQ_MASTERCLOCK_UPDATE); - out: srcu_read_unlock(&kvm->srcu, idx); return ret; From 36a85200643e62d20a91f0bc1a811187b59f7762 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 28 Jul 2026 15:40:00 +0100 Subject: [PATCH 2/3] KVM: x86/xen: Prevent runstate times from becoming negative When kvm_xen_update_runstate() is invoked to set a vCPU's runstate, the time spent in the previous runstate is accounted. This is based on the delta between the current KVM clock time, and the previous value stored in vcpu->arch.xen.runstate_entry_time. If the KVM clock goes backwards, that delta will be negative. Or, since it's an unsigned 64-bit integer, very *large*. Linux guests deal with that particularly badly, reporting 100% steal time for ever more (well, for *centuries* at least, until the delta has been consumed). So when a negative delta is detected, just refrain from updating the runstate times until the KVM clock catches up with runstate_entry_time again. Also clamp steal_ns to delta_ns to prevent steal time from exceeding the total elapsed time, and handle negative steal_ns (which can happen if run_delay goes backwards across a scheduler update). The userspace APIs for setting the runstate times do not allow them to be set past the current KVM clock, but userspace can still adjust the KVM clock *after* setting the runstate times, which would cause this situation to occur. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Link: https://patch.msgid.link/20260728144954.355376-21-dwmw2@infradead.org Signed-off-by: Sean Christopherson --- arch/x86/kvm/xen.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/xen.c b/arch/x86/kvm/xen.c index 913cbd52ce6c..da14c2ab3db2 100644 --- a/arch/x86/kvm/xen.c +++ b/arch/x86/kvm/xen.c @@ -586,29 +586,45 @@ void kvm_xen_update_runstate(struct kvm_vcpu *v, int state) { struct kvm_vcpu_xen *vx = &v->arch.xen; u64 now = get_kvmclock_ns(v->kvm); - u64 delta_ns = now - vx->runstate_entry_time; u64 run_delay = current->sched_info.run_delay; + s64 delta_ns = now - vx->runstate_entry_time; + s64 steal_ns = run_delay - vx->last_steal; + /* + * If the vCPU was never run before, its prior state should + * be considered RUNSTATE_offline. + */ if (unlikely(!vx->runstate_entry_time)) vx->current_runstate = RUNSTATE_offline; + /* + * If KVM clock went backwards, just update the current runstate + * but don't account any time. Leave entry_time unchanged so the + * next positive delta covers the full period once the clock + * catches up. Update last_steal every time so stolen time only + * reflects the interval since the most recent call. + */ + if (delta_ns < 0) + goto update_guest; + /* * Time waiting for the scheduler isn't "stolen" if the * vCPU wasn't running anyway. */ - if (vx->current_runstate == RUNSTATE_running) { - u64 steal_ns = run_delay - vx->last_steal; + if (vx->current_runstate == RUNSTATE_running && steal_ns > 0) { + if (steal_ns > delta_ns) + steal_ns = delta_ns; delta_ns -= steal_ns; - vx->runstate_times[RUNSTATE_runnable] += steal_ns; } - vx->last_steal = run_delay; vx->runstate_times[vx->current_runstate] += delta_ns; - vx->current_runstate = state; vx->runstate_entry_time = now; + update_guest: + vx->current_runstate = state; + vx->last_steal = run_delay; if (vx->runstate_cache.active) kvm_xen_update_runstate_guest(v, state == RUNSTATE_runnable); } From 7d3bd21e457bd091beb982553fcf32fd9ee5929f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 28 Jul 2026 15:40:02 +0100 Subject: [PATCH 3/3] KVM: x86: Remove runtime Xen TSC frequency CPUID update Remove the code in kvm_cpuid() that dynamically updates the Xen TSC info CPUID leaf at runtime, as KVM is updating the wrong sub-leaf anyway (0x40000x03/2 EAX is the *host* TSC frequency per the Xen ABI, not the guest frequency which belongs in 0x40000x03/0 ECX). Simply drop the code instead of fixing it to fill the correct sub-leaf, as modifying guest CPUID entries/output at runtime is generally undesirable, and providing userspace the necessary data to fill the sub-leaf itself is useful for other reasons, e.g. to fill the generic 0x40000010 timing leaf and to provide exact scaling information to aid save/restore. Signed-off-by: David Woodhouse Link: https://patch.msgid.link/20260728144954.355376-23-dwmw2@infradead.org [sean: tweak changelog to take this patch before the new uAPI] Signed-off-by: Sean Christopherson --- arch/x86/kvm/cpuid.c | 16 ---------------- arch/x86/kvm/xen.h | 13 ------------- 2 files changed, 29 deletions(-) diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 591d2294acd7..4c86847a9629 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -2117,22 +2117,6 @@ bool kvm_cpuid(struct kvm_vcpu *vcpu, u32 *eax, u32 *ebx, } else if (function == 0x80000007) { if (kvm_hv_invtsc_suppressed(vcpu)) *edx &= ~feature_bit(CONSTANT_TSC); - } else if (IS_ENABLED(CONFIG_KVM_XEN) && - kvm_xen_is_tsc_leaf(vcpu, function)) { - /* - * Update guest TSC frequency information if necessary. - * Ignore failures, there is no sane value that can be - * provided if KVM can't get the TSC frequency. - */ - if (kvm_check_request(KVM_REQ_CLOCK_UPDATE, vcpu)) - kvm_guest_time_update(vcpu); - - if (index == 1) { - *ecx = vcpu->arch.pvclock_tsc_mul; - *edx = vcpu->arch.pvclock_tsc_shift; - } else if (index == 2) { - *eax = vcpu->arch.hw_tsc_khz; - } } } else { *eax = *ebx = *ecx = *edx = 0; diff --git a/arch/x86/kvm/xen.h b/arch/x86/kvm/xen.h index 59e6128a7bd3..f372855857a8 100644 --- a/arch/x86/kvm/xen.h +++ b/arch/x86/kvm/xen.h @@ -50,14 +50,6 @@ static inline void kvm_xen_sw_enable_lapic(struct kvm_vcpu *vcpu) kvm_xen_inject_vcpu_vector(vcpu); } -static inline bool kvm_xen_is_tsc_leaf(struct kvm_vcpu *vcpu, u32 function) -{ - return static_branch_unlikely(&kvm_xen_enabled.key) && - vcpu->arch.xen.cpuid.base && - function <= vcpu->arch.xen.cpuid.limit && - function == (vcpu->arch.xen.cpuid.base | XEN_CPUID_LEAF(3)); -} - static inline bool kvm_xen_msr_enabled(struct kvm *kvm) { return static_branch_unlikely(&kvm_xen_enabled.key) && @@ -177,11 +169,6 @@ static inline bool kvm_xen_timer_enabled(struct kvm_vcpu *vcpu) { return false; } - -static inline bool kvm_xen_is_tsc_leaf(struct kvm_vcpu *vcpu, u32 function) -{ - return false; -} #endif int kvm_xen_hypercall(struct kvm_vcpu *vcpu);