From ba78382f34c10dcb04f352b959b16b469fba417a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Aug 2026 14:32:41 -0700 Subject: [PATCH 01/21] KVM: x86: Update "last guest TSC" snapshot prior to enabling IRQs/preemption When refreshing the last observed guest TSC during a guest time update, write the snapshot before enabling IRQs, i.e. before enabling preemption. If the task is migrated between updating the local tsc_timestamp, e.g. to account for catch-up mode, and setting last_guest_tsc, kvm_arch_vcpu_load() would set the vCPU's TSC offset using the old last_guest_tsc. In practice, the bug is largely benign as it's not even strictly necessary for KVM to refresh last_guest_tsc when updating guest time, as KVM's goal is purely to prevent the guest from observing time jump backwards, i.e. super duper strictly speaking, KVM only *needs* to update last_guest_tsc in the VM-Exit path. In fact, the update kvm_guest_time_update() in wasn't even added to play nice with kvm_arch_vcpu_load(), it was added by commit 28e4639adf0c ("KVM: x86: Fix kvmclock bug") to fix code that no longer exists. As of commit 28e4639adf0c, kvm_guest_time_update() also consumed last_guest_tsc, to try and prevent guest time from jumping backwards. That code was eventually removed by commit f25e656d31ad ("KVM: x86: fix tsc catchup issue with tsc scaling"), but the last_guest_tsc update hung around. Keep the update even though it's technically ok to drop the update, e.g. so that the tsc_catchup updates aren't lost, and so that the guest won't see a PV clock timestamp that appears to be in the future. Link: https://patch.msgid.link/20260826213303.914988-2-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 79468ddfe473..a359606b7655 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1820,6 +1820,12 @@ int kvm_guest_time_update(struct kvm_vcpu *v) } } + /* + * Refresh L1's last "observed" TSC to match the PV clock's timestamp, + * e.g. so that the guest can't see a TSC that's behind the reference. + */ + vcpu->last_guest_tsc = tsc_timestamp; + local_irq_restore(flags); /* With all the info we got, fill in the values */ @@ -1841,7 +1847,6 @@ int kvm_guest_time_update(struct kvm_vcpu *v) hv_clock.tsc_to_system_mul = vcpu->pvclock_tsc_mul; hv_clock.tsc_timestamp = tsc_timestamp; hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset; - vcpu->last_guest_tsc = tsc_timestamp; /* If the host uses TSC clocksource, then it is stable */ hv_clock.flags = 0; From d4f54ed48e0043371f8b81aac3450ea86ce30a3e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:42 -0700 Subject: [PATCH 02/21] KVM: x86: Improve accuracy of KVM clock when TSC scaling is in force The kvm_guest_time_update() function scales the host TSC frequency to the guest's using kvm_scale_tsc() and the v->arch.l1_tsc_scaling_ratio scaling ratio previously calculated for that vCPU. Then calculates the scaling factors for the KVM clock itself based on that guest TSC frequency. However, it uses kHz as the unit when scaling, and then multiplies by 1000 only at the end. With a host TSC frequency of 3000MHz and a guest set to 2500MHz, the result of kvm_scale_tsc() will actually come out at 2,499,999kHz. So the KVM clock advertised to the guest is based on a frequency of 2,499,999,000 Hz. By using Hz as the unit from the beginning, the KVM clock would be based on a more accurate frequency of 2,499,999,999 Hz in this example. Use u64 for the hw_tsc_hz field since an unsigned int would overflow for TSC frequencies above 4GHz. Fixes: 78db6a503796 ("KVM: x86: rewrite handling of scaled TSC for kvmclock") Reviewed-by: Paul Durrant Signed-off-by: David Woodhouse Tested-by: Dongli Zhang Link: https://patch.msgid.link/20260826213303.914988-3-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/cpuid.c | 1 + arch/x86/kvm/x86.c | 18 ++++++++++-------- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3af7395c2430..a384e25793ad 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -865,7 +865,7 @@ struct kvm_vcpu_arch { gpa_t time; s8 pvclock_tsc_shift; u32 pvclock_tsc_mul; - unsigned int hw_tsc_khz; + u64 hw_tsc_hz; struct gfn_to_pfn_cache pv_time; /* set guest stopped flag in pvclock flags field */ bool pvclock_set_guest_stopped_request; diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c index 851f151efb35..38450e9fca9a 100644 --- a/arch/x86/kvm/cpuid.c +++ b/arch/x86/kvm/cpuid.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a359606b7655..b38aafac7226 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -1763,7 +1764,8 @@ static void kvm_setup_guest_pvclock(struct pvclock_vcpu_time_info *ref_hv_clock, int kvm_guest_time_update(struct kvm_vcpu *v) { struct pvclock_vcpu_time_info hv_clock = {}; - unsigned long flags, tgt_tsc_khz; + unsigned long flags; + u64 tgt_tsc_hz; unsigned seq; struct kvm_vcpu_arch *vcpu = &v->arch; struct kvm_arch *ka = &v->kvm->arch; @@ -1789,8 +1791,8 @@ int kvm_guest_time_update(struct kvm_vcpu *v) /* Keep irq disabled to prevent changes to the clock */ local_irq_save(flags); - tgt_tsc_khz = get_cpu_tsc_khz(); - if (unlikely(tgt_tsc_khz == 0)) { + tgt_tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ; + if (unlikely(tgt_tsc_hz == 0)) { local_irq_restore(flags); kvm_make_request(KVM_REQ_CLOCK_UPDATE, v); return 1; @@ -1831,16 +1833,16 @@ int kvm_guest_time_update(struct kvm_vcpu *v) /* With all the info we got, fill in the values */ if (kvm_caps.has_tsc_control) { - tgt_tsc_khz = kvm_scale_tsc(tgt_tsc_khz, + tgt_tsc_hz = kvm_scale_tsc(tgt_tsc_hz, v->arch.l1_tsc_scaling_ratio); - tgt_tsc_khz = tgt_tsc_khz ? : 1; + tgt_tsc_hz = tgt_tsc_hz ? : 1; } - if (unlikely(vcpu->hw_tsc_khz != tgt_tsc_khz)) { - kvm_get_time_scale(NSEC_PER_SEC, tgt_tsc_khz * 1000LL, + if (unlikely(vcpu->hw_tsc_hz != tgt_tsc_hz)) { + kvm_get_time_scale(NSEC_PER_SEC, tgt_tsc_hz, &vcpu->pvclock_tsc_shift, &vcpu->pvclock_tsc_mul); - vcpu->hw_tsc_khz = tgt_tsc_khz; + vcpu->hw_tsc_hz = tgt_tsc_hz; } hv_clock.tsc_shift = vcpu->pvclock_tsc_shift; From dd0a8675f4ba65c208b12ea3d9bd45093c7aa2cf Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:43 -0700 Subject: [PATCH 03/21] KVM: x86: Explicitly disable TSC scaling without CONSTANT_TSC KVM does make an attempt to cope with non-constant TSC, and has notifiers to handle host TSC frequency changes. However, it *only* adjusts the KVM clock, and doesn't adjust TSC frequency scaling when the host changes. This is presumably because non-constant TSCs were fixed in hardware long before TSC scaling was implemented, so there should never be real CPUs which have TSC scaling but *not* CONSTANT_TSC. Such a combination could potentially happen in some odd L1 nesting environment, but it isn't worth trying to support it. Just make the dependency explicit. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Link: https://patch.msgid.link/20260826213303.914988-4-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/svm/svm.c | 3 ++- arch/x86/kvm/vmx/vmx.c | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 7d59d301e1e5..f5aa3d7d3a10 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -5620,7 +5620,8 @@ static __init int svm_hardware_setup(void) XFEATURE_MASK_BNDCSR); if (tsc_scaling) { - if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) { + if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR) || + !boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) { tsc_scaling = false; } else { pr_info("TSC scaling supported\n"); diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 612ab07d4100..54d93167e342 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -2843,6 +2843,16 @@ static int setup_vmcs_config(struct vmcs_config *vmcs_conf, if (!cpu_has_sgx()) _cpu_based_2nd_exec_control &= ~SECONDARY_EXEC_ENCLS_EXITING; + /* + * KVM doesn't re-derive the TSC scaling ratio when the host TSC + * frequency changes, so TSC scaling is only usable with a constant + * TSC. Clear the control here rather than in vmx_hardware_setup() so + * that the per-CPU configs recomputed by vmx_check_processor_compat() + * stay consistent with the golden vmcs_config. + */ + if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) + _cpu_based_2nd_exec_control &= ~SECONDARY_EXEC_TSC_SCALING; + if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_TERTIARY_CONTROLS) _cpu_based_3rd_exec_control = adjust_vmx_controls64(KVM_OPTIONAL_VMX_TERTIARY_VM_EXEC_CONTROL, From 7254e09bb5e90089d82c7ee65ce180f49c38c43e Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:44 -0700 Subject: [PATCH 04/21] KVM: x86: Activate master clock immediately on vCPU creation Previously, the master clock was only activated when the first vCPU processed KVM_REQ_MASTERCLOCK_UPDATE during KVM_RUN. This meant that KVM_GET_CLOCK could not return the host_tsc field until after the first KVM_RUN, making it impossible for userspace to follow the documented TSC migration procedure without a dummy vCPU run. Fix this by calling kvm_update_masterclock() directly from kvm_arch_vcpu_postcreate(), after kvm_synchronize_tsc() has already set all_vcpus_matched_freq. This ensures the master clock is active immediately, and KVM_GET_CLOCK returns a valid {host_tsc, realtime} pair as soon as a vCPU exists. Signed-off-by: David Woodhouse Link: https://patch.msgid.link/20260826213303.914988-5-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b38aafac7226..a4f4b072d2ac 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9447,6 +9447,8 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) return; vcpu_load(vcpu); kvm_synchronize_tsc(vcpu, NULL); + if (kvm_check_request(KVM_REQ_MASTERCLOCK_UPDATE, vcpu)) + kvm_update_masterclock(vcpu->kvm); vcpu_put(vcpu); /* poll control enabled by default */ From 7ffdb9d111c3e0ce881f037a7834e107f1e4b361 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:45 -0700 Subject: [PATCH 05/21] KVM: x86: Compute kvmclock base without pvclock_gtod_data get_kvmclock_base_ns() needs CLOCK_MONOTONIC_RAW + offs_boot. Compute this directly rather than reading offs_boot from the pvclock_gtod_data private copy. offs_boot only changes at suspend/resume so does not need to be atomically paired with the raw clock read. Signed-off-by: David Woodhouse Assisted-by: Kiro:claude-opus-4.6-1m Link: https://patch.msgid.link/20260826213303.914988-6-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a4f4b072d2ac..043d6d18fb4a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -930,7 +930,7 @@ static void update_pvclock_gtod(struct timekeeper *tk) static s64 get_kvmclock_base_ns(void) { /* Count up from boot time, but with the frequency of the raw clock. */ - return ktime_to_ns(ktime_add(ktime_get_raw(), pvclock_gtod_data.offs_boot)); + return ktime_to_ns(ktime_mono_to_any(ktime_get_raw(), TK_OFFS_BOOT)); } #else static s64 get_kvmclock_base_ns(void) From 4c710e8182f4fe31889663c5d893e3be692ae3c6 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:46 -0700 Subject: [PATCH 06/21] KVM: x86: Avoid NTP frequency skew for KVM clock on 32-bit host Now that 64-bit KVM doesn't consume pvclock_gtod_data when getting the kvmclock base, use the ktime_mono_to_any() version on 32-bit hosts so that they too are unaffected by NPT sync. Note, even if KVM still used pvclock_gtod_data for getting kvmclock base, it would still be very doable and reasonable to avoid skew on 32-bit hosts, it's just much simpler now that KVM uses ktime_mono_to_any(). Specifically, commit 53fafdbb8b21 ("KVM: x86: switch KVMCLOCK base to monotonic raw clock") did so only for 64-bit hosts, by capturing the boot offset from within the existing clocksource notifier update_pvclock_gtod(). That notifier was added in commit 16e8d74d2da9 ("KVM: x86: notifier for clocksource changes") but only on x86_64, because its original purpose was just to disable the "master clock" mode which is only supported on x86_64. Now that the notifier is used for more than disabling master clock mode, enabling it would be trivial for 32-bit builds as well, but as above, that's a moot point since get_kvmclock_base_ns() no longer relies on the notifier. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant [sean: rebase on top of ktime_mono_to_any() usage] Link: https://patch.msgid.link/20260826213303.914988-7-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 043d6d18fb4a..113c9c564ad3 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -926,19 +926,13 @@ static void update_pvclock_gtod(struct timekeeper *tk) write_seqcount_end(&vdata->seq); } +#endif static s64 get_kvmclock_base_ns(void) { /* Count up from boot time, but with the frequency of the raw clock. */ return ktime_to_ns(ktime_mono_to_any(ktime_get_raw(), TK_OFFS_BOOT)); } -#else -static s64 get_kvmclock_base_ns(void) -{ - /* Master clock not used, so we can just use CLOCK_BOOTTIME. */ - return ktime_get_boottime_ns(); -} -#endif static uint32_t div_frac(uint32_t dividend, uint32_t divisor) { From 796b73bba57728f8a67744916459afbed75f629a Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Aug 2026 14:32:47 -0700 Subject: [PATCH 07/21] KVM: x86: Drop unnecessary CPU pinning when computing/getting kvmclock When computing the current kvmclock value, don't pin the task to the current CPU for the entire duration of the master clock path, as the CPU pinning was never about ensuring rdtsc() and cpu_tsc_khz would agree. As pointed out by David, ka->use_master_clock can only be true when the host clocksource is TSC based, which in turn requires a stable, constant and synchronised TSC across all CPUs. The CPU pinning was added in commit e2c2206a1899 ("KVM: x86: Fix potential preemption when get the current kvmclock timestamp") purely in response to a CONFIG_DEBUG_PREEMPT=y bug due to accessing a per-CPU variable with preemption enabled. Despite what the comment would suggest, including rdtsc() in the {get,put}_cpu() section was opportunistic. In fact, Paolo even said exactly that when suggesting that KVM guarantee the rdtsc() would execute on the same CPU[*]: : Also, rdtsc() should really be on the same CPU as __this_cpu_read. We : know it's not really really necessary because the master clock is : active, but since we need a get_cpu/put_cpu pair, better be clean. Nothing has changed in the last ~9 years, i.e. the rdtsc() still *should* be on the same CPU, but super strictly speaking, all will be fine if the task is migrated between grabbing the frequency and doing rdtsc(). Dropping the CPU pinning will allow dropping the rdtsc() entirely without having to resort to a large "rewrite get_kvmclock()" patch. Opportunistically add a comment to explain why KVM needs to snapshot the frequency, because that _is_ a hard requirement to avoid reintroducing the bug fixed by commit e70b57a6ce4e ("KVM: X86: Fix softlockup when get the current kvmclock") Link: https://lore.kernel.org/all/ae8de642-8f14-a70a-1fab-57e2c4093cd5@redhat.com [*] Suggested-by: David Woodhouse Link: https://patch.msgid.link/20260826213303.914988-8-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 113c9c564ad3..b26699cf302d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1657,13 +1657,18 @@ static void __get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) { struct kvm_arch *ka = &kvm->arch; struct pvclock_vcpu_time_info hv_clock; + u64 tsc_hz; - /* both __this_cpu_read() and rdtsc() should be on the same cpu */ + /* + * Snapshot and validate the TSC frequency as kvmclock_cpu_down_prep() + * zeros the per-CPU value when a CPU is going offline. + */ get_cpu(); + tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ; + put_cpu(); data->flags = 0; - if (ka->use_master_clock && - (cpu_feature_enabled(X86_FEATURE_CONSTANT_TSC) || __this_cpu_read(cpu_tsc_khz))) { + if (ka->use_master_clock && tsc_hz) { #ifdef CONFIG_X86_64 struct timespec64 ts; @@ -1677,15 +1682,13 @@ static void __get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) data->flags |= KVM_CLOCK_TSC_STABLE; hv_clock.tsc_timestamp = ka->master_cycle_now; hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset; - kvm_get_time_scale(NSEC_PER_SEC, get_cpu_tsc_khz() * 1000LL, + kvm_get_time_scale(NSEC_PER_SEC, tsc_hz, &hv_clock.tsc_shift, &hv_clock.tsc_to_system_mul); data->clock = __pvclock_read_cycles(&hv_clock, data->host_tsc); } else { data->clock = get_kvmclock_base_ns() + ka->kvmclock_offset; } - - put_cpu(); } static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) From 1a926fb39304ca8aaa4355ecda3052aa53018317 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Aug 2026 14:32:48 -0700 Subject: [PATCH 08/21] KVM: x86: Move "no master clock" fallback from __get_kvmclock() to get_kvmclock() Move the fallback logic for getting the current kvmclock when not in master clock mode out of __get_kvmclock() and into its sole caller, get_kvmclock(). This will allow using early-return logic in the master clock code, without having to resort to a do-while() loop and/or gotos. No functional change intended. Link: https://patch.msgid.link/20260826213303.914988-9-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b26699cf302d..789d96991026 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1653,12 +1653,16 @@ static unsigned long get_cpu_tsc_khz(void) } /* Called within read_seqcount_begin/retry for kvm->pvclock_sc. */ -static void __get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) +static bool __get_kvmclock_master_clock(struct kvm *kvm, + struct kvm_clock_data *data) { struct kvm_arch *ka = &kvm->arch; struct pvclock_vcpu_time_info hv_clock; u64 tsc_hz; + if (!ka->use_master_clock) + return false; + /* * Snapshot and validate the TSC frequency as kvmclock_cpu_down_prep() * zeros the per-CPU value when a CPU is going offline. @@ -1667,8 +1671,10 @@ static void __get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ; put_cpu(); - data->flags = 0; - if (ka->use_master_clock && tsc_hz) { + if (!tsc_hz) + return false; + + { #ifdef CONFIG_X86_64 struct timespec64 ts; @@ -1686,9 +1692,9 @@ static void __get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) &hv_clock.tsc_shift, &hv_clock.tsc_to_system_mul); data->clock = __pvclock_read_cycles(&hv_clock, data->host_tsc); - } else { - data->clock = get_kvmclock_base_ns() + ka->kvmclock_offset; } + + return true; } static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) @@ -1697,8 +1703,11 @@ static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) unsigned seq; do { + data->flags = 0; + seq = read_seqcount_begin(&ka->pvclock_sc); - __get_kvmclock(kvm, data); + if (!__get_kvmclock_master_clock(kvm, data)) + data->clock = get_kvmclock_base_ns() + ka->kvmclock_offset; } while (read_seqcount_retry(&ka->pvclock_sc, seq)); } From 8e7e24b88e26be5214a22995bb585065f4065c25 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:49 -0700 Subject: [PATCH 09/21] KVM: x86: Wrap all of __get_kvmclock_master_clock() with CONFIG_X86_64=y Wrap the entire use_master_clock block in #ifdef CONFIG_X86_64, since use_master_clock is never true on 32-bit (host_tsc_clocksource is only set under CONFIG_X86_64), and declare hv_clock inside the block so it is not left as an unused variable on 32-bit. Signed-off-by: David Woodhouse [sean: keep only the CONFIG_X86_64 ifdef, update changelog accordingly] Link: https://patch.msgid.link/20260826213303.914988-10-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 789d96991026..e23bbb3b6f82 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1656,8 +1656,10 @@ static unsigned long get_cpu_tsc_khz(void) static bool __get_kvmclock_master_clock(struct kvm *kvm, struct kvm_clock_data *data) { +#ifdef CONFIG_X86_64 struct kvm_arch *ka = &kvm->arch; struct pvclock_vcpu_time_info hv_clock; + struct timespec64 ts; u64 tsc_hz; if (!ka->use_master_clock) @@ -1674,27 +1676,24 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm, if (!tsc_hz) return false; - { -#ifdef CONFIG_X86_64 - struct timespec64 ts; - - if (kvm_get_walltime_and_clockread(&ts, &data->host_tsc)) { - data->realtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec; - data->flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC; - } else -#endif + if (kvm_get_walltime_and_clockread(&ts, &data->host_tsc)) { + data->realtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec; + data->flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC; + } else { data->host_tsc = rdtsc(); - - data->flags |= KVM_CLOCK_TSC_STABLE; - hv_clock.tsc_timestamp = ka->master_cycle_now; - hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset; - kvm_get_time_scale(NSEC_PER_SEC, tsc_hz, - &hv_clock.tsc_shift, - &hv_clock.tsc_to_system_mul); - data->clock = __pvclock_read_cycles(&hv_clock, data->host_tsc); } + data->flags |= KVM_CLOCK_TSC_STABLE; + hv_clock.tsc_timestamp = ka->master_cycle_now; + hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset; + kvm_get_time_scale(NSEC_PER_SEC, tsc_hz, + &hv_clock.tsc_shift, + &hv_clock.tsc_to_system_mul); + data->clock = __pvclock_read_cycles(&hv_clock, data->host_tsc); return true; +#else + return false; +#endif } static void get_kvmclock(struct kvm *kvm, struct kvm_clock_data *data) From 25f75fb43fd53138c248869334fdff4555a7a1e4 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:50 -0700 Subject: [PATCH 10/21] KVM: x86: Fall back to non-master-clock if clockread fails in get_kvmclock() When computing kvmclock and it's currently in master-clock mode, fall back to the non-master-clock path if the clock read fails, e.g. if the kernel's clocksource is transitioning away from TSC but ka->use_master_clock hasn't been updated yet. The rdtsc() fallback was added (well, kept) in commit c68dc1b577ea ("KVM: x86: Report host tsc and realtime values in KVM_GET_CLOCK") purely to avoid uninitialized variables and compilation problems on 32-bit kernels (already addressed). In hindsight, keeping the rdtsc() was a hack and a mistake. Link: https://lore.kernel.org/all/CAOQ_QsgVqS_PuJo8F10Gg5Xw+tKt+5gDx+kJf1j3CiPO4MAOqg@mail.gmail.com Signed-off-by: David Woodhouse [sean: isolate from refactoring changes, write changelog] Link: https://patch.msgid.link/20260826213303.914988-11-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e23bbb3b6f82..872d49a2eeb0 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1676,14 +1676,13 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm, if (!tsc_hz) return false; - if (kvm_get_walltime_and_clockread(&ts, &data->host_tsc)) { - data->realtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec; - data->flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC; - } else { - data->host_tsc = rdtsc(); - } + if (!kvm_get_walltime_and_clockread(&ts, &data->host_tsc)) + return false; + + data->realtime = ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec; + data->flags |= KVM_CLOCK_REALTIME | KVM_CLOCK_HOST_TSC | + KVM_CLOCK_TSC_STABLE; - data->flags |= KVM_CLOCK_TSC_STABLE; hv_clock.tsc_timestamp = ka->master_cycle_now; hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset; kvm_get_time_scale(NSEC_PER_SEC, tsc_hz, From abdef42276d88417f6a0c1f9fae8190accc3bc38 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:51 -0700 Subject: [PATCH 11/21] KVM: x86: Fix KVM clock precision in get_kvmclock() with TSC scaling When in master clock mode, the KVM clock is defined in terms of the guest TSC. But get_kvmclock() was computing it from the host TSC without applying TSC scaling, leading to a systemic drift from the values the guest computes from its own TSC. Store the VM's TSC scaling ratio in kvm_arch and precompute the guest-TSC-based mul/shift in pvclock_update_vm_gtod_copy(). Use these in get_kvmclock() to scale the host TSC delta to guest TSC before converting to nanoseconds. This avoids "definition C" of the KVM clock described in commit 633d7652f80f ("KVM: x86/xen: Do not corrupt KVM clock in kvm_xen_shared_info_init()"). Signed-off-by: David Woodhouse Link: https://patch.msgid.link/20260826213303.914988-12-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 4 +++ arch/x86/kvm/x86.c | 61 ++++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index a384e25793ad..1e3b53e1d2bb 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1237,6 +1237,7 @@ struct kvm_arch { u64 last_tsc_write; u32 last_tsc_khz; u64 last_tsc_offset; + u64 last_tsc_scaling_ratio; u64 cur_tsc_nsec; u64 cur_tsc_write; u64 cur_tsc_offset; @@ -1252,6 +1253,9 @@ struct kvm_arch { u64 master_kernel_ns; u64 master_cycle_now; struct ratelimit_state kvmclock_update_rs; + u64 master_tsc_scaling_ratio; + s8 master_tsc_shift; + u32 master_tsc_mul; #ifdef CONFIG_KVM_HYPERV struct kvm_hv hyperv; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 872d49a2eeb0..4567896b7cf7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1249,6 +1249,7 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc, kvm->arch.last_tsc_write = tsc; kvm->arch.last_tsc_khz = vcpu->arch.virtual_tsc_khz; kvm->arch.last_tsc_offset = offset; + kvm->arch.last_tsc_scaling_ratio = vcpu->arch.l1_tsc_scaling_ratio; vcpu->arch.last_guest_tsc = tsc; @@ -1561,6 +1562,8 @@ static bool kvm_get_walltime_and_clockread(struct timespec64 *ts, * */ +static unsigned long get_cpu_tsc_khz(void); + static void pvclock_update_vm_gtod_copy(struct kvm *kvm) { #ifdef CONFIG_X86_64 @@ -1584,9 +1587,30 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm) && !ka->backwards_tsc_observed && !ka->boot_vcpu_runs_old_kvmclock; - if (ka->use_master_clock) + if (ka->use_master_clock) { + u64 tsc_hz; + atomic_set(&kvm_guest_has_master_clock, 1); + /* + * Copy the scaling ratio and precompute the mul/shift for + * converting guest TSC to nanoseconds. These are used by + * get_kvmclock() to compute kvmclock from the host TSC + * without needing a vCPU reference. + */ + ka->master_tsc_scaling_ratio = ka->last_tsc_scaling_ratio; + tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ; + if (tsc_hz && kvm_caps.has_tsc_control) + tsc_hz = kvm_scale_tsc(tsc_hz, + ka->master_tsc_scaling_ratio); + if (tsc_hz) + kvm_get_time_scale(NSEC_PER_SEC, tsc_hz, + &ka->master_tsc_shift, + &ka->master_tsc_mul); + else + ka->use_master_clock = false; + } + vclock_mode = pvclock_gtod_data.clock.vclock_mode; trace_kvm_update_master_clock(ka->use_master_clock, vclock_mode, vcpus_matched); @@ -1660,22 +1684,10 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm, struct kvm_arch *ka = &kvm->arch; struct pvclock_vcpu_time_info hv_clock; struct timespec64 ts; - u64 tsc_hz; if (!ka->use_master_clock) return false; - /* - * Snapshot and validate the TSC frequency as kvmclock_cpu_down_prep() - * zeros the per-CPU value when a CPU is going offline. - */ - get_cpu(); - tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ; - put_cpu(); - - if (!tsc_hz) - return false; - if (!kvm_get_walltime_and_clockread(&ts, &data->host_tsc)) return false; @@ -1685,10 +1697,25 @@ static bool __get_kvmclock_master_clock(struct kvm *kvm, hv_clock.tsc_timestamp = ka->master_cycle_now; hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset; - kvm_get_time_scale(NSEC_PER_SEC, tsc_hz, - &hv_clock.tsc_shift, - &hv_clock.tsc_to_system_mul); - data->clock = __pvclock_read_cycles(&hv_clock, data->host_tsc); + + /* + * Use the precomputed guest-TSC-based mul/shift so that the kvmclock + * value matches what the guest computes from its own TSC. + */ + hv_clock.tsc_shift = ka->master_tsc_shift; + hv_clock.tsc_to_system_mul = ka->master_tsc_mul; + + if (kvm_caps.has_tsc_control) { + u64 tsc_delta = data->host_tsc - ka->master_cycle_now; + + tsc_delta = kvm_scale_tsc(tsc_delta, ka->master_tsc_scaling_ratio); + data->clock = hv_clock.system_time + + pvclock_scale_delta(tsc_delta, + hv_clock.tsc_to_system_mul, + hv_clock.tsc_shift); + } else { + data->clock = __pvclock_read_cycles(&hv_clock, data->host_tsc); + } return true; #else return false; From c56419275caad2d99264b7c50b0701552ed3ef75 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:52 -0700 Subject: [PATCH 12/21] KVM: x86: Use get_kvmclock() in kvm_get_wall_clock_epoch() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that get_kvmclock() correctly handles TSC scaling and captures both wallclock and kvmclock from the same TSC reading, kvm_get_wall_clock_epoch() can simply call it instead of duplicating the pvclock computation. This eliminates the last instance of the "definition C" kvmclock calculation — as described in commit 633d7652f80f ("KVM: x86/xen: Do not corrupt KVM clock in kvm_xen_shared_info_init()") — which computed nanoseconds directly from the host TSC without accounting for guest TSC scaling. Signed-off-by: David Woodhouse Link: https://patch.msgid.link/20260826213303.914988-13-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 59 +++++++--------------------------------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4567896b7cf7..e0e13235a69e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1941,63 +1941,22 @@ int kvm_guest_time_update(struct kvm_vcpu *v) * wallclock and kvmclock times, and subtracting one from the other. * * Fall back to using their values at slightly different moments by - * calling ktime_get_real_ns() and get_kvmclock_ns() separately. + * calling ktime_get_real_ns() and get_kvmclock() separately. */ uint64_t kvm_get_wall_clock_epoch(struct kvm *kvm) { -#ifdef CONFIG_X86_64 - struct pvclock_vcpu_time_info hv_clock; - struct kvm_arch *ka = &kvm->arch; - unsigned long seq, local_tsc_khz; - struct timespec64 ts; - uint64_t host_tsc; + struct kvm_clock_data data; - do { - seq = read_seqcount_begin(&ka->pvclock_sc); - - local_tsc_khz = 0; - if (!ka->use_master_clock) - break; - - /* - * The TSC read and the call to get_cpu_tsc_khz() must happen - * on the same CPU. - */ - get_cpu(); - - local_tsc_khz = get_cpu_tsc_khz(); - - if (local_tsc_khz && - !kvm_get_walltime_and_clockread(&ts, &host_tsc)) - local_tsc_khz = 0; /* Fall back to old method */ - - put_cpu(); - - /* - * These values must be snapshotted within the seqcount loop. - * After that, it's just mathematics which can happen on any - * CPU at any time. - */ - hv_clock.tsc_timestamp = ka->master_cycle_now; - hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset; - - } while (read_seqcount_retry(&ka->pvclock_sc, seq)); + get_kvmclock(kvm, &data); /* - * If the conditions were right, and obtaining the wallclock+TSC was - * successful, calculate the KVM clock at the corresponding time and - * subtract one from the other to get the guest's epoch in nanoseconds - * since 1970-01-01. + * If get_kvmclock() captured both wallclock and kvmclock from the + * same TSC reading, use them for a precise epoch calculation. */ - if (local_tsc_khz) { - kvm_get_time_scale(NSEC_PER_SEC, local_tsc_khz * NSEC_PER_USEC, - &hv_clock.tsc_shift, - &hv_clock.tsc_to_system_mul); - return ts.tv_nsec + NSEC_PER_SEC * ts.tv_sec - - __pvclock_read_cycles(&hv_clock, host_tsc); - } -#endif - return ktime_get_real_ns() - get_kvmclock_ns(kvm); + if (data.flags & KVM_CLOCK_REALTIME) + return data.realtime - data.clock; + + return ktime_get_real_ns() - data.clock; } /* From d9173f59df3a625b0e8b7df9873b7358996acc6a Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:53 -0700 Subject: [PATCH 13/21] KVM: x86: Fix compute_guest_tsc() to handle negative time deltas The compute_guest_tsc() function computes the guest TSC at a given kernel_ns timestamp. When the master clock reference point (master_kernel_ns) is earlier than vcpu->arch.this_tsc_nsec, the delta is negative. Since pvclock_scale_delta() takes a u64, the negative value wraps to a huge positive number, producing a wildly wrong result. Handle negative deltas explicitly by scaling the absolute value of the delta and applying it to this_tsc_write with the appropriate sign. This is believed to be unreachable in practice; no path has been identified which invokes compute_guest_tsc() with a timestamp from before the vCPU's TSC generation was established. Fix it for robustness, in the spirit of defence in depth. Signed-off-by: David Woodhouse Link: https://patch.msgid.link/20260826213303.914988-14-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index e0e13235a69e..f918db1c8127 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1056,11 +1056,15 @@ static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz) static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns) { - u64 tsc = pvclock_scale_delta(kernel_ns-vcpu->arch.this_tsc_nsec, - vcpu->arch.virtual_tsc_mult, - vcpu->arch.virtual_tsc_shift); - tsc += vcpu->arch.this_tsc_write; - return tsc; + s64 delta_ns = kernel_ns - vcpu->arch.this_tsc_nsec; + u64 tsc; + + /* Handle negative deltas gracefully (master clock ref may be earlier) */ + tsc = pvclock_scale_delta(abs(delta_ns), + vcpu->arch.virtual_tsc_mult, + vcpu->arch.virtual_tsc_shift); + + return vcpu->arch.this_tsc_write + (delta_ns >= 0 ? tsc : -tsc); } #ifdef CONFIG_X86_64 From 917a53a4b461df5a848856e0715aa2d1fa3783fe Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Aug 2026 14:32:54 -0700 Subject: [PATCH 14/21] KVM: x86: Disable preemption, not IRQs, when getting TSC+freq pair Disable "just" preemption, not IRQs, when reading the TSC+frequency pair to update guest time, as disabling IRQs to protect against task migration is overkill (though it's *extremely* hard to see that it's overkill). Disabling IRQs was added by commit 18068523d3a0 ("KVM: paravirtualized clocksource: host part") before there was any coordination with timekeeping (presumably disabling IRQs prevented the kernel from completing a software- induced frequency change). After the coordination and locking was added, commit c09664bb4418 ("KVM: x86: fix deadlock in clock-in-progress request handling") moved the locking and coordination out of IRQ protection, and thus made disabling IRQs pointless, except for protecting get_cpu_tsc_khz(). And while cpu_tsc_khz is written only from IRQ context, and the *extremely* confusing double IPIs sent by __kvmclock_cpufreq_notifier() to update the per-CPU frequency make it seem like they would require readers to disable IRQs, it is safe to read and consume cpu_tsc_khz (via get_cpu_tsc_khz()) with IRQs enabled. The per-CPU variable is specifically written only in IRQ context to ensure hotplugging a CPU wouldn't write cpu_tsc_khz with a stale value (because apparently disabling IRQs would be too simple?!?). As for the double IPIs in the frequency notifier, both IPIs are red herrings. The actual sequence that ensures KVM updates guest time with the new frequency is that the first write is completed *before* the notifier sets KVM_REQ_CLOCK_UPDATE for all vCPUs that last ran on the target pCPU. The first write is done via IPI to adhere to the above rules, and the second IPI is sent purely to kick any vCPU that happens to be running on the target CPU out of the guest. I.e. the second IPI writes cpu_tsc_khz out of pure KVM laziness: it saves having to define another IPI callback. In fact prior to commit 8cfdc0008542 ("KVM: x86: Make cpu_tsc_khz updates use local CPU"), KVM did indeed use an empty callback to ack the IPI. As for why it was deemed cleaner to abuse tsc_khz_changed()... Link: https://patch.msgid.link/20260826213303.914988-15-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f918db1c8127..4a1ddb49c6c2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1799,7 +1799,6 @@ static void kvm_setup_guest_pvclock(struct pvclock_vcpu_time_info *ref_hv_clock, int kvm_guest_time_update(struct kvm_vcpu *v) { struct pvclock_vcpu_time_info hv_clock = {}; - unsigned long flags; u64 tgt_tsc_hz; unsigned seq; struct kvm_vcpu_arch *vcpu = &v->arch; @@ -1824,11 +1823,14 @@ int kvm_guest_time_update(struct kvm_vcpu *v) } } while (read_seqcount_retry(&ka->pvclock_sc, seq)); - /* Keep irq disabled to prevent changes to the clock */ - local_irq_save(flags); + /* + * Ensure reading the TSC+frequency pair is done on the same CPU. When + * NOT using the master clock, the TSC frequency may vary between CPUs. + */ + preempt_disable(); tgt_tsc_hz = (u64)get_cpu_tsc_khz() * HZ_PER_KHZ; if (unlikely(tgt_tsc_hz == 0)) { - local_irq_restore(flags); + preempt_enable(); kvm_make_request(KVM_REQ_CLOCK_UPDATE, v); return 1; } @@ -1863,7 +1865,7 @@ int kvm_guest_time_update(struct kvm_vcpu *v) */ vcpu->last_guest_tsc = tsc_timestamp; - local_irq_restore(flags); + preempt_enable(); /* With all the info we got, fill in the values */ From f21b04302404fa87826caa7f5fd3f7e07ab6782e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Aug 2026 14:32:55 -0700 Subject: [PATCH 15/21] KVM: x86: Make master clock logic in guest PV clock updates 64-bit only Wrap kvm_guest_time_update()'s entire use_master_clock block in #ifdef CONFIG_X86_64 and provide a hardcoded-to-false variable for the 32-bit path, as use_master_clock is never true on 32-bit (host_tsc_clocksource is only set under CONFIG_X86_64) Keep the local "ka" variable outside of the 64-bit-only code as it's also used for Xen code, but tag it as potentially unused since it's not used on 32-bit kernels without Xen emulation. For all intents and purposes, no functional change intended. Link: https://patch.msgid.link/20260826213303.914988-16-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4a1ddb49c6c2..14e7efdd74ed 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1798,22 +1798,21 @@ static void kvm_setup_guest_pvclock(struct pvclock_vcpu_time_info *ref_hv_clock, int kvm_guest_time_update(struct kvm_vcpu *v) { + struct kvm_arch *ka __maybe_unused = &v->kvm->arch; struct pvclock_vcpu_time_info hv_clock = {}; u64 tgt_tsc_hz; - unsigned seq; struct kvm_vcpu_arch *vcpu = &v->arch; - struct kvm_arch *ka = &v->kvm->arch; s64 kernel_ns; u64 tsc_timestamp, host_tsc; - bool use_master_clock; - - kernel_ns = 0; - host_tsc = 0; /* * If the host uses TSC clock, then passthrough TSC as stable * to the guest. */ +#ifdef CONFIG_X86_64 + bool use_master_clock; + unsigned int seq; + do { seq = read_seqcount_begin(&ka->pvclock_sc); use_master_clock = ka->use_master_clock; @@ -1822,7 +1821,9 @@ int kvm_guest_time_update(struct kvm_vcpu *v) kernel_ns = ka->master_kernel_ns; } } while (read_seqcount_retry(&ka->pvclock_sc, seq)); - +#else + const bool use_master_clock = false; +#endif /* * Ensure reading the TSC+frequency pair is done on the same CPU. When * NOT using the master clock, the TSC frequency may vary between CPUs. From 92fac63cc73920175f712cec792f9ab698923ffb Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:56 -0700 Subject: [PATCH 16/21] KVM: x86: Upscale TSC to "now", not master clock when updating PV clocks When doing TSC upscaling in software, e.g. when the guest TSC frequency is configured to run faster than the host without hardware support, always advance guest TSC to "now", not to the master clock's reference values, which represents some time in the past. In master clock mode, there are two points of time which need to be taken into account. First there is the master clock reference point, stored in kvm->arch.master_kernel_ns (and associated host TSC ->master_cycle_now). Secondly, there is the time *now*, at the point kvm_update_guest_time() is being called. With software TSC upscaling, the guest TSC is getting further and further ahead of the host TSC as time elapses. So at time "now", the guest TSC should be further ahead of the host, than it was at master_kernel_ns. Not taking that into account means KVM was advancing the guest TSC only by the amount appropriate for the snapshot taken in the past, *not* to the current time (which is what RDTSC is supposed to return). Signed-off-by: David Woodhouse Co-developed-by: Sean Christopherson Link: https://patch.msgid.link/20260826213303.914988-17-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 14e7efdd74ed..4180e18e0cbb 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1798,12 +1798,11 @@ static void kvm_setup_guest_pvclock(struct pvclock_vcpu_time_info *ref_hv_clock, int kvm_guest_time_update(struct kvm_vcpu *v) { + u64 tgt_tsc_hz, tsc_timestamp, host_tsc, master_tsc, master_ns; struct kvm_arch *ka __maybe_unused = &v->kvm->arch; struct pvclock_vcpu_time_info hv_clock = {}; - u64 tgt_tsc_hz; struct kvm_vcpu_arch *vcpu = &v->arch; s64 kernel_ns; - u64 tsc_timestamp, host_tsc; /* * If the host uses TSC clock, then passthrough TSC as stable @@ -1816,10 +1815,16 @@ int kvm_guest_time_update(struct kvm_vcpu *v) do { seq = read_seqcount_begin(&ka->pvclock_sc); use_master_clock = ka->use_master_clock; - if (use_master_clock) { - host_tsc = ka->master_cycle_now; - kernel_ns = ka->master_kernel_ns; + if (!use_master_clock) + continue; + + if (!kvm_get_time_and_clockread(&kernel_ns, &host_tsc)) { + use_master_clock = false; + continue; } + + master_tsc = ka->master_cycle_now; + master_ns = ka->master_kernel_ns; } while (read_seqcount_retry(&ka->pvclock_sc, seq)); #else const bool use_master_clock = false; @@ -1885,8 +1890,18 @@ int kvm_guest_time_update(struct kvm_vcpu *v) hv_clock.tsc_shift = vcpu->pvclock_tsc_shift; hv_clock.tsc_to_system_mul = vcpu->pvclock_tsc_mul; - hv_clock.tsc_timestamp = tsc_timestamp; - hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset; + /* + * If the master clock is NOT in use, the reference time placed in the + * hv_clock is "now". If master clock is in use, the reference time is + * the master clock's snapshot from some time in the past, not "now". + */ + if (use_master_clock) { + hv_clock.tsc_timestamp = kvm_read_l1_tsc(v, master_tsc); + hv_clock.system_time = master_ns + v->kvm->arch.kvmclock_offset; + } else { + hv_clock.tsc_timestamp = tsc_timestamp; + hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset; + } /* If the host uses TSC clocksource, then it is stable */ hv_clock.flags = 0; From 2918af628d0dae8476f89abeb76fe9fe3fd029cb Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:57 -0700 Subject: [PATCH 17/21] KVM: x86: Simplify and comment kvm_get_time_scale() The kvm_get_time_scale() function was entirely opaque. Add comments explaining what it does: compute a fixed-point multiplier and shift for converting TSC ticks to nanoseconds via pvclock_scale_delta(). Rename the local variables from the cryptic tps64/tps32/scaled64 to base_hz_u64/base32/scaled_hz_u64 to make the code self-documenting. The "tps32" name stood for "Ticks Per Second" but was misleading since it held the shifted base frequency, not a tick count. No functional change. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Link: https://patch.msgid.link/20260826213303.914988-18-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 55 +++++++++++++++++++++++++++++++++------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 4180e18e0cbb..fb585470746e 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -940,32 +940,57 @@ static uint32_t div_frac(uint32_t dividend, uint32_t divisor) return dividend; } -static void kvm_get_time_scale(uint64_t scaled_hz, uint64_t base_hz, +static void kvm_get_time_scale(u64 scaled_hz, u64 base_hz, s8 *pshift, u32 *pmultiplier) { - uint64_t scaled64; - int32_t shift = 0; - uint64_t tps64; - uint32_t tps32; + u64 scaled_hz_u64 = scaled_hz; + s32 shift = 0; + u64 base_hz_u64; + u32 base32; - tps64 = base_hz; - scaled64 = scaled_hz; - while (tps64 > scaled64*2 || tps64 & 0xffffffff00000000ULL) { - tps64 >>= 1; + /* + * This function calculates a fixed-point multiplier and shift such + * that: + * time_ns = (tsc_cycles << shift) * multiplier >> 32 + * + * Where tsc_cycles tick at base_hz, and time_ns should count at + * scaled_hz (typically NSEC_PER_SEC for a TSC→nanoseconds conversion). + * + * The multiplier is: (scaled_hz << 32) / base_hz, adjusted by shift + * to keep everything in range. + */ + + base_hz_u64 = base_hz; + + /* + * Start by shifting base_hz right until it fits in 32 bits, and + * is lower than double the target rate. This introduces a negative + * shift value which would result in pvclock_scale_delta() shifting + * the actual tick count right before performing the multiplication. + */ + while (base_hz_u64 > scaled_hz_u64 * 2 || base_hz_u64 >> 32) { + base_hz_u64 >>= 1; shift--; } - tps32 = (uint32_t)tps64; - while (tps32 <= scaled64 || scaled64 & 0xffffffff00000000ULL) { - if (scaled64 & 0xffffffff00000000ULL || tps32 & 0x80000000) - scaled64 >>= 1; + /* Now the shifted base_hz fits in 32 bits. */ + base32 = (u32)base_hz_u64; + + /* + * Next, shift scaled_hz right until it fits in 32 bits, and ensure + * that the shifted base_hz is strictly larger (so that the result of the + * final division also fits in 32 bits). + */ + while (base32 <= scaled_hz_u64 || scaled_hz_u64 >> 32) { + if (scaled_hz_u64 >> 32 || base32 & BIT(31)) + scaled_hz_u64 >>= 1; else - tps32 <<= 1; + base32 <<= 1; shift++; } *pshift = shift; - *pmultiplier = div_frac(scaled64, tps32); + *pmultiplier = div_frac(scaled_hz_u64, base32); } #ifdef CONFIG_X86_64 From d4bbf2a8eb82ec8dfcdace0c56d024d3e83c21ad Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:58 -0700 Subject: [PATCH 18/21] KVM: x86: Remove implicit rdtsc() from kvm_compute_l1_tsc_offset() Let the callers pass the host TSC value in as an explicit parameter. This leaves some fairly obviously stupid code, which is using this function to compare the guest TSC at some *other* time, with the newly-minted TSC value from rdtsc(). Unless it's being used to measure *elapsed* time, that isn't very sensible. In this case, "obviously stupid" is an improvement over being non-obviously so. No functional change intended. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant Link: https://patch.msgid.link/20260826213303.914988-19-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/msrs.c | 3 ++- arch/x86/kvm/x86.c | 11 ++++++----- arch/x86/kvm/x86.h | 3 ++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/arch/x86/kvm/msrs.c b/arch/x86/kvm/msrs.c index dd3bb04878ca..37d5bed3529f 100644 --- a/arch/x86/kvm/msrs.c +++ b/arch/x86/kvm/msrs.c @@ -1631,7 +1631,8 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info) if (msr_info->host_initiated) { kvm_synchronize_tsc(vcpu, &data); } else if (!vcpu->arch.guest_tsc_protected) { - u64 adj = kvm_compute_l1_tsc_offset(vcpu, data) - vcpu->arch.l1_tsc_offset; + u64 adj = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data) - + vcpu->arch.l1_tsc_offset; adjust_tsc_offset_guest(vcpu, adj); vcpu->arch.ia32_tsc_adjust_msr += adj; } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index fb585470746e..eecc3aa28f28 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1155,11 +1155,12 @@ u64 kvm_scale_tsc(u64 tsc, u64 ratio) return _tsc; } -u64 kvm_compute_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc) +u64 kvm_compute_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 host_tsc, + u64 target_tsc) { u64 tsc; - tsc = kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio); + tsc = kvm_scale_tsc(host_tsc, vcpu->arch.l1_tsc_scaling_ratio); return target_tsc - tsc; } @@ -1321,7 +1322,7 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value) bool synchronizing = false; raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); - offset = kvm_compute_l1_tsc_offset(vcpu, data); + offset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data); ns = get_kvmclock_base_ns(); elapsed = ns - kvm->arch.last_tsc_nsec; @@ -1370,7 +1371,7 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value) } else { u64 delta = nsec_to_cycles(vcpu, elapsed); data += delta; - offset = kvm_compute_l1_tsc_offset(vcpu, data); + offset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), data); } matched = true; } @@ -2627,7 +2628,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) mark_tsc_unstable("KVM discovered backwards TSC"); if (kvm_check_tsc_unstable()) { - u64 offset = kvm_compute_l1_tsc_offset(vcpu, + u64 offset = kvm_compute_l1_tsc_offset(vcpu, rdtsc(), vcpu->arch.last_guest_tsc); kvm_vcpu_write_tsc_offset(vcpu, offset); if (!vcpu->arch.guest_tsc_protected) diff --git a/arch/x86/kvm/x86.h b/arch/x86/kvm/x86.h index 0f5919b092e4..1d9a66048b01 100644 --- a/arch/x86/kvm/x86.h +++ b/arch/x86/kvm/x86.h @@ -335,7 +335,8 @@ u64 kvm_scale_tsc(u64 tsc, u64 ratio); u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc); u64 kvm_calc_nested_tsc_offset(u64 l1_offset, u64 l2_offset, u64 l2_multiplier); u64 kvm_calc_nested_tsc_multiplier(u64 l1_multiplier, u64 l2_multiplier); -u64 kvm_compute_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc); +u64 kvm_compute_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 host_tsc, + u64 target_tsc); void kvm_vcpu_write_tsc_offset(struct kvm_vcpu *vcpu, u64 l1_offset); static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, From ef7d809987c9c36d2b50ae0f0feb07251ff98cf8 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Wed, 26 Aug 2026 14:32:59 -0700 Subject: [PATCH 19/21] KVM: x86: Use kernel timekeeping snapshots for getting kvmclock time since boot Replace the KVM-private vgettsc()+do_kvmclock_base() timekeeping reimplementation with calls to the recently crafted, generic ktime_get_snapshot_id() interface. This is the first step towards dropping KVM's homebrewed implementation entirely (do_monotonic() and do_realtime() will be converted in the near future). As with KVM's implementation, the snapshot provides both the system time and the raw_cycles (TSC), atomically paired using a sequence counter. The equivalents to vgettsc()'s TSC and HVCLOCK modes respectively are if the clocksource itself is TSC (cs_id == CSID_X86_TSC) and if the underlying hardware clocksource is TSC (hw_csid == CSID_X86_TSC). In the Hyper-V case, i.e. hw_csid == CSID_X86_TSC, if the clocksource couldn't provide a raw hardware counter value, treat the clock not being based on TSC, which which is equivalent to vgettsc() returning VDSO_CLOCKMODE_NONE. Unlike KVM's current implementation, don't include offs_boot in the atomically-acquired tuple as there's simply no need to do so: the time since boot only changes at boot (duh) and at suspend/resume boundaries. Unless processes aren't being frozen/thawed before/after suspend/resume, which would completely break suspend/resume, TK_OFFS_BOOT can't change while kvm_get_time_and_clockread() is running. And if KVM does somehow try to take a snapshot during suspend, timekeeping core will WARN and refuse to provide the snapshot. This is a step towards eliminating the pvclock_gtod_data private copy of timekeeping state and the associated notifier callback. Signed-off-by: David Woodhouse [sean: separate from other conversions, massage changelog accordingly] Link: https://patch.msgid.link/20260826213303.914988-20-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 57 ++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index eecc3aa28f28..5746a77942de 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -35,6 +35,7 @@ #include "smm.h" #include +#include #include #include #include @@ -1437,29 +1438,6 @@ static inline u64 vgettsc(struct pvclock_clock *clock, u64 *tsc_timestamp, return v * clock->mult; } -/* - * As with get_kvmclock_base_ns(), this counts from boot time, at the - * frequency of CLOCK_MONOTONIC_RAW (hence adding gtos->offs_boot). - */ -static int do_kvmclock_base(s64 *t, u64 *tsc_timestamp) -{ - struct pvclock_gtod_data *gtod = &pvclock_gtod_data; - unsigned long seq; - int mode; - u64 ns; - - do { - seq = read_seqcount_begin(>od->seq); - ns = gtod->raw_clock.base_cycles; - ns += vgettsc(>od->raw_clock, tsc_timestamp, &mode); - ns >>= gtod->raw_clock.shift; - ns += ktime_to_ns(ktime_add(gtod->raw_clock.offset, gtod->offs_boot)); - } while (unlikely(read_seqcount_retry(>od->seq, seq))); - *t = ns; - - return mode; -} - /* * This calculates CLOCK_MONOTONIC at the time of the TSC snapshot, with * no boot time offset. @@ -1504,6 +1482,29 @@ static int do_realtime(struct timespec64 *ts, u64 *tsc_timestamp) return mode; } +static bool kvm_snapshot_has_tsc(struct system_time_snapshot *snap, + u64 *tsc_timestamp) +{ + /* + * ktime_get_snapshot_id() cannot fail for standard clock IDs + * (only for invalid/aux clocks or during suspend, with a WARN). + */ + if (!snap->valid) + return false; + + if (snap->cs_id == CSID_X86_TSC) { + *tsc_timestamp = snap->cycles; + return true; + } + + if (snap->hw_csid == CSID_X86_TSC && snap->hw_cycles) { + *tsc_timestamp = snap->hw_cycles; + return true; + } + + return false; +} + /* * Calculates the kvmclock_base_ns (CLOCK_MONOTONIC_RAW + boot time) and * reports the TSC value from which it do so. Returns true if host is @@ -1511,12 +1512,14 @@ static int do_realtime(struct timespec64 *ts, u64 *tsc_timestamp) */ static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp) { - /* checked again under seqlock below */ - if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode)) + struct system_time_snapshot snap = {}; + + ktime_get_snapshot_id(CLOCK_MONOTONIC_RAW, &snap); + if (!kvm_snapshot_has_tsc(&snap, tsc_timestamp)) return false; - return gtod_is_based_on_tsc(do_kvmclock_base(kernel_ns, - tsc_timestamp)); + *kernel_ns = ktime_to_ns(ktime_mono_to_any(snap.systime, TK_OFFS_BOOT)); + return true; } /* From 0a0ab23b05f031ee849357fe0a5e1f667b46277e Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Aug 2026 14:33:00 -0700 Subject: [PATCH 20/21] KVM: x86: Use kernel timekeeping snapshot for monotonic clock Replace the KVM-private vgettsc()+/do_monotonic() timekeeping reimplementation with calls to the recently crafted, generic ktime_get_snapshot_id() interface. As noted previously, the snapshot provides both the system time and the raw_cycles (TSC), atomically paired using a sequence counter. Signed-off-by: David Woodhouse [sean: separate from other conversions] Link: https://patch.msgid.link/20260826213303.914988-21-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 5746a77942de..f0955f7baf6a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1438,29 +1438,6 @@ static inline u64 vgettsc(struct pvclock_clock *clock, u64 *tsc_timestamp, return v * clock->mult; } -/* - * This calculates CLOCK_MONOTONIC at the time of the TSC snapshot, with - * no boot time offset. - */ -static int do_monotonic(s64 *t, u64 *tsc_timestamp) -{ - struct pvclock_gtod_data *gtod = &pvclock_gtod_data; - unsigned long seq; - int mode; - u64 ns; - - do { - seq = read_seqcount_begin(>od->seq); - ns = gtod->clock.base_cycles; - ns += vgettsc(>od->clock, tsc_timestamp, &mode); - ns >>= gtod->clock.shift; - ns += ktime_to_ns(gtod->clock.offset); - } while (unlikely(read_seqcount_retry(>od->seq, seq))); - *t = ns; - - return mode; -} - static int do_realtime(struct timespec64 *ts, u64 *tsc_timestamp) { struct pvclock_gtod_data *gtod = &pvclock_gtod_data; @@ -1528,12 +1505,14 @@ static bool kvm_get_time_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp) */ bool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp) { - /* checked again under seqlock below */ - if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode)) + struct system_time_snapshot snap = {}; + + ktime_get_snapshot_id(CLOCK_MONOTONIC, &snap); + if (!kvm_snapshot_has_tsc(&snap, tsc_timestamp)) return false; - return gtod_is_based_on_tsc(do_monotonic(kernel_ns, - tsc_timestamp)); + *kernel_ns = ktime_to_ns(snap.systime); + return true; } /* From d7841275e1fb4ad1e1877e56725ebda5b6e3143d Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 26 Aug 2026 14:33:01 -0700 Subject: [PATCH 21/21] KVM: x86: Use kernel timekeeping snapshot to get walltime+TSC Replace the KVM-private vgettsc()+/do_do_realtime() timekeeping reimplementation with calls to the recently crafted, generic ktime_get_snapshot_id() interface. As noted previously, the snapshot provides both the system time and the raw_cycles (TSC), atomically paired using a sequence counter. With great pleasure, delete the now unused read_tsc() and vgettsc() Signed-off-by: David Woodhouse [sean: separate from other conversions, express joy at vgettsc()'s demise] Link: https://patch.msgid.link/20260826213303.914988-22-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/x86.c | 85 ++++------------------------------------------ 1 file changed, 6 insertions(+), 79 deletions(-) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index f0955f7baf6a..4d612231bcf2 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -1383,82 +1383,6 @@ void kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 *user_value) #ifdef CONFIG_X86_64 -static u64 read_tsc(void) -{ - u64 ret = (u64)rdtsc_ordered(); - u64 last = pvclock_gtod_data.clock.cycle_last; - - if (likely(ret >= last)) - return ret; - - /* - * GCC likes to generate cmov here, but this branch is extremely - * predictable (it's just a function of time and the likely is - * very likely) and there's a data dependence, so force GCC - * to generate a branch instead. I don't barrier() because - * we don't actually need a barrier, and if this function - * ever gets inlined it will generate worse code. - */ - asm volatile (""); - return last; -} - -static inline u64 vgettsc(struct pvclock_clock *clock, u64 *tsc_timestamp, - int *mode) -{ - u64 tsc_pg_val; - long v; - - switch (clock->vclock_mode) { - case VDSO_CLOCKMODE_HVCLOCK: - if (hv_read_tsc_page_tsc(hv_get_tsc_page(), - tsc_timestamp, &tsc_pg_val)) { - /* TSC page valid */ - *mode = VDSO_CLOCKMODE_HVCLOCK; - v = (tsc_pg_val - clock->cycle_last) & - clock->mask; - } else { - /* TSC page invalid */ - *mode = VDSO_CLOCKMODE_NONE; - } - break; - case VDSO_CLOCKMODE_TSC: - *mode = VDSO_CLOCKMODE_TSC; - *tsc_timestamp = read_tsc(); - v = (*tsc_timestamp - clock->cycle_last) & - clock->mask; - break; - default: - *mode = VDSO_CLOCKMODE_NONE; - } - - if (*mode == VDSO_CLOCKMODE_NONE) - *tsc_timestamp = v = 0; - - return v * clock->mult; -} - -static int do_realtime(struct timespec64 *ts, u64 *tsc_timestamp) -{ - struct pvclock_gtod_data *gtod = &pvclock_gtod_data; - unsigned long seq; - int mode; - u64 ns; - - do { - seq = read_seqcount_begin(>od->seq); - ts->tv_sec = gtod->wall_time_sec; - ns = gtod->clock.base_cycles; - ns += vgettsc(>od->clock, tsc_timestamp, &mode); - ns >>= gtod->clock.shift; - } while (unlikely(read_seqcount_retry(>od->seq, seq))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return mode; -} - static bool kvm_snapshot_has_tsc(struct system_time_snapshot *snap, u64 *tsc_timestamp) { @@ -1525,11 +1449,14 @@ bool kvm_get_monotonic_and_clockread(s64 *kernel_ns, u64 *tsc_timestamp) static bool kvm_get_walltime_and_clockread(struct timespec64 *ts, u64 *tsc_timestamp) { - /* checked again under seqlock below */ - if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode)) + struct system_time_snapshot snap = {}; + + ktime_get_snapshot_id(CLOCK_REALTIME, &snap); + if (!kvm_snapshot_has_tsc(&snap, tsc_timestamp)) return false; - return gtod_is_based_on_tsc(do_realtime(ts, tsc_timestamp)); + *ts = ktime_to_timespec64(snap.systime); + return true; } #endif