* [PATCH v9 01/21] KVM: x86: Update "last guest TSC" snapshot prior to enabling IRQs/preemption
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 02/21] KVM: x86: Improve accuracy of KVM clock when TSC scaling is in force Sean Christopherson
` (20 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
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.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 d94b59140c45..d3b47e38698c 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;
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 02/21] KVM: x86: Improve accuracy of KVM clock when TSC scaling is in force
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 01/21] KVM: x86: Update "last guest TSC" snapshot prior to enabling IRQs/preemption Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 03/21] KVM: x86: Explicitly disable TSC scaling without CONSTANT_TSC Sean Christopherson
` (19 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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. Use div_u64() for the Xen CPUID leaf to
play nice with 32-bit kernels.
Fixes: 78db6a503796 ("KVM: x86: rewrite handling of scaled TSC for kvmclock")
Reviewed-by: Paul Durrant <paul@xen.org>
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Tested-by: Dongli Zhang <dongli.zhang@oracle.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 283847619ff8..6ddc988576d0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -864,7 +864,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 ddb022cb203a..ca26be88c204 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -16,6 +16,7 @@
#include <linux/vmalloc.h>
#include <linux/uaccess.h>
#include <linux/sched/stat.h>
+#include <linux/units.h>
#include <asm/processor.h>
#include <asm/user.h>
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index d3b47e38698c..ce6d155b2ee6 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -61,6 +61,7 @@
#include <linux/mem_encrypt.h>
#include <linux/suspend.h>
#include <linux/smp.h>
+#include <linux/units.h>
#include <trace/events/ipi.h>
#include <trace/events/kvm.h>
@@ -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;
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 03/21] KVM: x86: Explicitly disable TSC scaling without CONSTANT_TSC
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 01/21] KVM: x86: Update "last guest TSC" snapshot prior to enabling IRQs/preemption Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 02/21] KVM: x86: Improve accuracy of KVM clock when TSC scaling is in force Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 04/21] KVM: x86: Activate master clock immediately on vCPU creation Sean Christopherson
` (18 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 9d607b98bd06..3057ca7051db 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -5602,7 +5602,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 e3bfe6aca1a0..9abd2ed3aeae 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -2841,6 +2841,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,
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 04/21] KVM: x86: Activate master clock immediately on vCPU creation
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (2 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 03/21] KVM: x86: Explicitly disable TSC scaling without CONSTANT_TSC Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 05/21] KVM: x86: Compute kvmclock base without pvclock_gtod_data Sean Christopherson
` (17 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 ce6d155b2ee6..137a1dd2b85a 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 */
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 05/21] KVM: x86: Compute kvmclock base without pvclock_gtod_data
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (3 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 04/21] KVM: x86: Activate master clock immediately on vCPU creation Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 06/21] KVM: x86: Avoid NTP frequency skew for KVM clock on 32-bit host Sean Christopherson
` (16 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Assisted-by: Kiro:claude-opus-4.6-1m
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 137a1dd2b85a..67c762b3bf28 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)
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 06/21] KVM: x86: Avoid NTP frequency skew for KVM clock on 32-bit host
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (4 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 05/21] KVM: x86: Compute kvmclock base without pvclock_gtod_data Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 07/21] KVM: x86: Drop unnecessary CPU pinning when computing/getting kvmclock Sean Christopherson
` (15 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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,
enable it for the 32-bit build too so that get_kvmclock_base_ns() can be
unaffected by NTP sync on 32-bit too.
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
[sean: rebase on top of ktime_mono_to_any() usage]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/x86.c | 19 ++++++-------------
1 file changed, 6 insertions(+), 13 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 67c762b3bf28..93b49be0d887 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -874,7 +874,6 @@ static inline bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu)
kvm_request_pending(vcpu) || xfer_to_guest_mode_work_pending();
}
-#ifdef CONFIG_X86_64
struct pvclock_clock {
int vclock_mode;
u64 cycle_last;
@@ -932,13 +931,6 @@ 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)
{
@@ -6873,6 +6865,7 @@ static void pvclock_irq_work_fn(struct irq_work *w)
}
static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_irq_work_fn);
+#endif
/*
* Notification about pvclock gtod data update.
@@ -6880,26 +6873,26 @@ static DEFINE_IRQ_WORK(pvclock_irq_work, pvclock_irq_work_fn);
static int pvclock_gtod_notify(struct notifier_block *nb, unsigned long unused,
void *priv)
{
- struct pvclock_gtod_data *gtod = &pvclock_gtod_data;
struct timekeeper *tk = priv;
update_pvclock_gtod(tk);
+#ifdef CONFIG_X86_64
/*
* Disable master clock if host does not trust, or does not use,
* TSC based clocksource. Delegate queue_work() to irq_work as
* this is invoked with tk_core.seq write held.
*/
- if (!gtod_is_based_on_tsc(gtod->clock.vclock_mode) &&
+ if (!gtod_is_based_on_tsc(pvclock_gtod_data.clock.vclock_mode) &&
atomic_read(&kvm_guest_has_master_clock) != 0)
irq_work_queue(&pvclock_irq_work);
+#endif
return 0;
}
static struct notifier_block pvclock_gtod_notifier = {
.notifier_call = pvclock_gtod_notify,
};
-#endif
void kvm_setup_xss_caps(void)
{
@@ -7118,9 +7111,9 @@ int kvm_x86_vendor_init(struct kvm_x86_init_ops *ops)
if (pi_inject_timer == -1)
pi_inject_timer = housekeeping_enabled(HK_TYPE_TIMER);
-#ifdef CONFIG_X86_64
pvclock_gtod_register_notifier(&pvclock_gtod_notifier);
+#ifdef CONFIG_X86_64
if (hypervisor_is_type(X86_HYPER_MS_HYPERV))
set_hv_tscchange_cb(kvm_hyperv_tsc_notifier);
#endif
@@ -7177,8 +7170,8 @@ void kvm_x86_vendor_exit(void)
CPUFREQ_TRANSITION_NOTIFIER);
cpuhp_remove_state_nocalls(CPUHP_AP_X86_KVM_CLK_ONLINE);
}
-#ifdef CONFIG_X86_64
pvclock_gtod_unregister_notifier(&pvclock_gtod_notifier);
+#ifdef CONFIG_X86_64
irq_work_sync(&pvclock_irq_work);
cancel_work_sync(&pvclock_gtod_work);
#endif
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 07/21] KVM: x86: Drop unnecessary CPU pinning when computing/getting kvmclock
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (5 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 06/21] KVM: x86: Avoid NTP frequency skew for KVM clock on 32-bit host Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 08/21] KVM: x86: Move "no master clock" fallback from __get_kvmclock() to get_kvmclock() Sean Christopherson
` (14 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
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 <dwmw@amazon.co.uk>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 93b49be0d887..56e095b14441 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1655,13 +1655,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 &&
- (static_cpu_has(X86_FEATURE_CONSTANT_TSC) || __this_cpu_read(cpu_tsc_khz))) {
+ if (ka->use_master_clock && tsc_hz) {
#ifdef CONFIG_X86_64
struct timespec64 ts;
@@ -1675,15 +1680,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)
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 08/21] KVM: x86: Move "no master clock" fallback from __get_kvmclock() to get_kvmclock()
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (6 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 07/21] KVM: x86: Drop unnecessary CPU pinning when computing/getting kvmclock Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 09/21] KVM: x86: Wrap all of __get_kvmclock_master_clock() with CONFIG_X86_64=y Sean Christopherson
` (13 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
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.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 56e095b14441..e0d623a122eb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1651,12 +1651,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.
@@ -1665,8 +1669,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;
@@ -1684,9 +1690,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)
@@ -1695,8 +1701,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));
}
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 09/21] KVM: x86: Wrap all of __get_kvmclock_master_clock() with CONFIG_X86_64=y
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (7 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 08/21] KVM: x86: Move "no master clock" fallback from __get_kvmclock() to get_kvmclock() Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 10/21] KVM: x86: Fall back to non-master-clock if clockread fails in get_kvmclock() Sean Christopherson
` (12 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
[sean: keep only the CONFIG_X86_64 ifdef, update changelog accordingly]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 e0d623a122eb..304e078cb899 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1654,8 +1654,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)
@@ -1672,27 +1674,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)
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 10/21] KVM: x86: Fall back to non-master-clock if clockread fails in get_kvmclock()
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (8 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 09/21] KVM: x86: Wrap all of __get_kvmclock_master_clock() with CONFIG_X86_64=y Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 11/21] KVM: x86: Fix KVM clock precision in get_kvmclock() with TSC scaling Sean Christopherson
` (11 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
[sean: isolate from refactoring changes, write changelog]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 304e078cb899..33ba840d3267 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1674,14 +1674,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,
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 11/21] KVM: x86: Fix KVM clock precision in get_kvmclock() with TSC scaling
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (9 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 10/21] KVM: x86: Fall back to non-master-clock if clockread fails in get_kvmclock() Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 12/21] KVM: x86: Use get_kvmclock() in kvm_get_wall_clock_epoch() Sean Christopherson
` (10 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 6ddc988576d0..2878a5181cd9 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1236,6 +1236,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;
@@ -1251,6 +1252,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 33ba840d3267..61c65241554d 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1247,6 +1247,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;
@@ -1559,6 +1560,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
@@ -1582,9 +1585,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);
@@ -1658,22 +1682,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;
@@ -1683,10 +1695,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;
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 12/21] KVM: x86: Use get_kvmclock() in kvm_get_wall_clock_epoch()
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (10 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 11/21] KVM: x86: Fix KVM clock precision in get_kvmclock() with TSC scaling Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 13/21] KVM: x86: Fix compute_guest_tsc() to handle negative time deltas Sean Christopherson
` (9 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 61c65241554d..50e92090ba65 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1939,63 +1939,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;
}
/*
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 13/21] KVM: x86: Fix compute_guest_tsc() to handle negative time deltas
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (11 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 12/21] KVM: x86: Use get_kvmclock() in kvm_get_wall_clock_epoch() Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 14/21] KVM: x86: Disable preemption, not IRQs, when getting TSC+freq pair Sean Christopherson
` (8 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 50e92090ba65..76c16a15f059 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1054,11 +1054,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
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 14/21] KVM: x86: Disable preemption, not IRQs, when getting TSC+freq pair
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (12 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 13/21] KVM: x86: Fix compute_guest_tsc() to handle negative time deltas Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 15/21] KVM: x86: Make master clock logic in guest PV clock updates 64-bit only Sean Christopherson
` (7 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
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()...
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 76c16a15f059..a8dde1d898fb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1797,7 +1797,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;
@@ -1822,11 +1821,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;
}
@@ -1861,7 +1863,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 */
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 15/21] KVM: x86: Make master clock logic in guest PV clock updates 64-bit only
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (13 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 14/21] KVM: x86: Disable preemption, not IRQs, when getting TSC+freq pair Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 16/21] KVM: x86: Upscale TSC to "now", not master clock when updating PV clocks Sean Christopherson
` (6 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
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.
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
arch/x86/kvm/x86.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a8dde1d898fb..d3630b2bfd3b 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1796,22 +1796,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;
+
+ /*
+ * 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;
- kernel_ns = 0;
- host_tsc = 0;
-
- /*
- * If the host uses TSC clock, then passthrough TSC as stable
- * to the guest.
- */
do {
seq = read_seqcount_begin(&ka->pvclock_sc);
use_master_clock = ka->use_master_clock;
@@ -1820,7 +1819,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.
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 16/21] KVM: x86: Upscale TSC to "now", not master clock when updating PV clocks
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (14 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 15/21] KVM: x86: Make master clock logic in guest PV clock updates 64-bit only Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 17/21] KVM: x86: Simplify and comment kvm_get_time_scale() Sean Christopherson
` (5 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 d3630b2bfd3b..56c2fe11d866 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1796,12 +1796,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
@@ -1814,10 +1813,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;
@@ -1883,8 +1888,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;
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 17/21] KVM: x86: Simplify and comment kvm_get_time_scale()
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (15 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 16/21] KVM: x86: Upscale TSC to "now", not master clock when updating PV clocks Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 18/21] KVM: x86: Remove implicit rdtsc() from kvm_compute_l1_tsc_offset() Sean Christopherson
` (4 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 56c2fe11d866..7661c49ccaed 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -938,32 +938,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
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 18/21] KVM: x86: Remove implicit rdtsc() from kvm_compute_l1_tsc_offset()
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (16 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 17/21] KVM: x86: Simplify and comment kvm_get_time_scale() Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 19/21] KVM: x86: Use kernel timekeeping snapshots for getting kvmclock time since boot Sean Christopherson
` (3 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
Reviewed-by: Paul Durrant <paul@xen.org>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 66fa7140d65d..22ceb39d41f6 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 7661c49ccaed..aa39a423694c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1153,11 +1153,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;
}
@@ -1319,7 +1320,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;
@@ -1368,7 +1369,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;
}
@@ -2625,7 +2626,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,
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 19/21] KVM: x86: Use kernel timekeeping snapshots for getting kvmclock time since boot
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (17 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 18/21] KVM: x86: Remove implicit rdtsc() from kvm_compute_l1_tsc_offset() Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 20/21] KVM: x86: Use kernel timekeeping snapshot for monotonic clock Sean Christopherson
` (2 subsequent siblings)
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
From: David Woodhouse <dwmw@amazon.co.uk>
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 <dwmw@amazon.co.uk>
[sean: separate from other conversions, massage changelog accordingly]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 aa39a423694c..85c456dd29d5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -35,6 +35,7 @@
#include "smm.h"
#include <linux/clocksource.h>
+#include <linux/timekeeping.h>
#include <linux/interrupt.h>
#include <linux/kvm.h>
#include <linux/fs.h>
@@ -1435,29 +1436,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.
@@ -1502,6 +1480,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
@@ -1509,12 +1510,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;
}
/*
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 20/21] KVM: x86: Use kernel timekeeping snapshot for monotonic clock
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (18 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 19/21] KVM: x86: Use kernel timekeeping snapshots for getting kvmclock time since boot Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-10 22:54 ` [PATCH v9 21/21] KVM: x86: Use kernel timekeeping snapshot to get walltime+TSC Sean Christopherson
2026-08-11 13:58 ` [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Woodhouse, David
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
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 <dwmw@amazon.co.uk>
[sean: separate from other conversions]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 85c456dd29d5..1513e4ae2353 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1436,29 +1436,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;
@@ -1526,12 +1503,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;
}
/*
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH v9 21/21] KVM: x86: Use kernel timekeeping snapshot to get walltime+TSC
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (19 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 20/21] KVM: x86: Use kernel timekeeping snapshot for monotonic clock Sean Christopherson
@ 2026-08-10 22:54 ` Sean Christopherson
2026-08-11 13:58 ` [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Woodhouse, David
21 siblings, 0 replies; 23+ messages in thread
From: Sean Christopherson @ 2026-08-10 22:54 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm, linux-kernel, Paul Durrant, David Woodhouse, Dongli Zhang
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 <dwmw@amazon.co.uk>
[sean: separate from other conversions, express joy at vgettsc()'s demise]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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 1513e4ae2353..a638898e528f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1381,82 +1381,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)
{
@@ -1523,11 +1447,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
--
2.55.0.679.g6767b8d81c-goog
^ permalink raw reply related [flat|nested] 23+ messages in thread* Re: [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1
2026-08-10 22:54 [PATCH v9 00/21] KVM: x86: Cleaning up the KVM clock mess, part 1 Sean Christopherson
` (20 preceding siblings ...)
2026-08-10 22:54 ` [PATCH v9 21/21] KVM: x86: Use kernel timekeeping snapshot to get walltime+TSC Sean Christopherson
@ 2026-08-11 13:58 ` Woodhouse, David
21 siblings, 0 replies; 23+ messages in thread
From: Woodhouse, David @ 2026-08-11 13:58 UTC (permalink / raw)
To: Sean Christopherson, Paolo Bonzini
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Paul Durrant,
Dongli Zhang
[-- Attachment #1.1: Type: text/plain, Size: 1037 bytes --]
On Mon, 2026-08-10 at 15:54 -0700, Sean Christopherson wrote:
> Part 1 of David's series to clean up the host-side mess of kvmclock. The cut
> point in this version is still quite arbitrary, but what's left for "part 2"
> fits nicely into 2-3 buckets:
>
> 1: Masterclock overhaul
> 2. New uAPI and tests
>
> As mentioned elsewhere, my plan is to throw this into an unstable topic branch
> asap so it can be used as a base for part 2, but will target 7.4, not 7.3. I
> won't publish it to kvm-x86/next until 7.3-rc1, to avoid polluting linux-next,
> and I'll rebase the whole thing on one of 7.3-rc1, 7.3-rc2, or an updated
> kvm/next.
Thanks.
I've rebased part2 on top of your part1 (and confirmed that you did
indeed pick from my unposted kvmclock8 branch and not the last posted
v7; thanks for that!).
To avoid introducing confusion, I'll try to build stuff as fixup
commits to be autosquashed, starting with that TSC offset thing and I
think I had some other Sashiko feedback to look at too...
[-- Attachment #1.2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 4017 bytes --]
[-- Attachment #2.1: Type: text/plain, Size: 215 bytes --]
Amazon Development Centre (London) Ltd. Registered in England and Wales with registration number 04543232 with its registered office at 1 Principal Place, Worship Street, London EC2A 2FA, United Kingdom.
[-- Attachment #2.2: Type: text/html, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread