RE: [PATCH v5 36/51] x86/paravirt: Pass sched_clock save/restore helpers during registration
From: Michael Kelley
Date: Thu Jul 02 2026 - 14:23:52 EST
From: Sean Christopherson <seanjc@xxxxxxxxxx> Sent: Wednesday, July 1, 2026 12:32 PM
>
> Pass in a PV clock's save/restore helpers when configuring sched_clock
> instead of relying on each PV clock to manually set the save/restore hooks.
> In addition to bringing sanity to the code, this will allow gracefully
> "rejecting" a PV sched_clock, e.g. when running as a CoCo guest that has
> access to a "secure" TSC.
>
> No functional change intended.
>
> Reviewed-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
> Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
For the Hyper-V changes,
Reviewed-by: Michael Kelley <mhklinux@xxxxxxxxxxx>
> ---
> arch/x86/include/asm/timer.h | 9 ++++++---
> arch/x86/kernel/cpu/vmware.c | 8 +++-----
> arch/x86/kernel/kvmclock.c | 6 +++---
> arch/x86/kernel/tsc.c | 5 ++++-
> arch/x86/xen/time.c | 5 ++---
> drivers/clocksource/hyperv_timer.c | 6 ++----
> 6 files changed, 20 insertions(+), 19 deletions(-)
>
> diff --git a/arch/x86/include/asm/timer.h b/arch/x86/include/asm/timer.h
> index fe41d40a9ae6..e97cd1ae03d1 100644
> --- a/arch/x86/include/asm/timer.h
> +++ b/arch/x86/include/asm/timer.h
> @@ -14,11 +14,14 @@ extern int no_timer_check;
> extern bool using_native_sched_clock(void);
>
> #ifdef CONFIG_PARAVIRT
> -void __paravirt_set_sched_clock(u64 (*func)(void), bool stable);
> +void __paravirt_set_sched_clock(u64 (*func)(void), bool stable,
> + void (*save)(void), void (*restore)(void));
>
> -static inline void paravirt_set_sched_clock(u64 (*func)(void))
> +static inline void paravirt_set_sched_clock(u64 (*func)(void),
> + void (*save)(void),
> + void (*restore)(void))
> {
> - __paravirt_set_sched_clock(func, true);
> + __paravirt_set_sched_clock(func, true, save, restore);
> }
> #endif
>
> diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
> index 5c1ccaf4a25e..232255279a6e 100644
> --- a/arch/x86/kernel/cpu/vmware.c
> +++ b/arch/x86/kernel/cpu/vmware.c
> @@ -347,11 +347,9 @@ static void __init vmware_paravirt_ops_setup(void)
>
> vmware_cyc2ns_setup();
>
> - if (vmw_sched_clock) {
> - paravirt_set_sched_clock(vmware_sched_clock);
> - x86_platform.save_sched_clock_state = x86_init_noop;
> - x86_platform.restore_sched_clock_state = x86_init_noop;
> - }
> + if (vmw_sched_clock)
> + paravirt_set_sched_clock(vmware_sched_clock,
> + x86_init_noop, x86_init_noop);
>
> if (vmware_is_stealclock_available()) {
> has_steal_clock = true;
> diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
> index 07e875738c39..5b9955343199 100644
> --- a/arch/x86/kernel/kvmclock.c
> +++ b/arch/x86/kernel/kvmclock.c
> @@ -158,7 +158,9 @@ static void kvm_restore_sched_clock_state(void)
> static inline void kvm_sched_clock_init(bool stable)
> {
> kvm_sched_clock_offset = kvm_clock_read();
> - __paravirt_set_sched_clock(kvm_sched_clock_read, stable);
> + __paravirt_set_sched_clock(kvm_sched_clock_read, stable,
> + kvm_save_sched_clock_state,
> + kvm_restore_sched_clock_state);
>
> pr_info("kvm-clock: using sched offset of %llu cycles",
> kvm_sched_clock_offset);
> @@ -367,8 +369,6 @@ void __init kvmclock_init(bool prefer_tsc)
> #ifdef CONFIG_SMP
> x86_cpuinit.early_percpu_clock_init = kvm_setup_secondary_clock;
> #endif
> - x86_platform.save_sched_clock_state = kvm_save_sched_clock_state;
> - x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state;
> kvm_get_preset_lpj();
>
> /*
> diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
> index 7473dcab4775..83353d643150 100644
> --- a/arch/x86/kernel/tsc.c
> +++ b/arch/x86/kernel/tsc.c
> @@ -280,12 +280,15 @@ bool using_native_sched_clock(void)
> return static_call_query(pv_sched_clock) == native_sched_clock;
> }
>
> -void __paravirt_set_sched_clock(u64 (*func)(void), bool stable)
> +void __paravirt_set_sched_clock(u64 (*func)(void), bool stable,
> + void (*save)(void), void (*restore)(void))
> {
> if (!stable)
> clear_sched_clock_stable();
>
> static_call_update(pv_sched_clock, func);
> + x86_platform.save_sched_clock_state = save;
> + x86_platform.restore_sched_clock_state = restore;
> }
> #else
> u64 sched_clock_noinstr(void) __attribute__((alias("native_sched_clock")));
> diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
> index 477441752f40..8cd8bfaf1320 100644
> --- a/arch/x86/xen/time.c
> +++ b/arch/x86/xen/time.c
> @@ -566,13 +566,12 @@ static void __init xen_init_time_common(void)
> {
> xen_sched_clock_offset = xen_clocksource_read();
> static_call_update(pv_steal_clock, xen_steal_clock);
> - paravirt_set_sched_clock(xen_sched_clock);
> +
> /*
> * Xen has paravirtualized suspend/resume and so doesn't use the common
> * x86 sched_clock save/restore hooks.
> */
> - x86_platform.save_sched_clock_state = x86_init_noop;
> - x86_platform.restore_sched_clock_state = x86_init_noop;
> + paravirt_set_sched_clock(xen_sched_clock, x86_init_noop, x86_init_noop);
>
> x86_init.hyper.get_tsc_khz = xen_tsc_khz;
> x86_platform.get_wallclock = xen_get_wallclock;
> diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c
> index 220668207d19..8ee7a9de0f4f 100644
> --- a/drivers/clocksource/hyperv_timer.c
> +++ b/drivers/clocksource/hyperv_timer.c
> @@ -570,10 +570,8 @@ static void hv_restore_sched_clock_state(void)
> static __always_inline void hv_setup_sched_clock(void *sched_clock)
> {
> /* We're on x86/x64 *and* using PV ops */
> - paravirt_set_sched_clock(sched_clock);
> -
> - x86_platform.save_sched_clock_state = hv_save_sched_clock_state;
> - x86_platform.restore_sched_clock_state = hv_restore_sched_clock_state;
> + paravirt_set_sched_clock(sched_clock, hv_save_sched_clock_state,
> + hv_restore_sched_clock_state);
> }
> #else /* !CONFIG_GENERIC_SCHED_CLOCK && !CONFIG_PARAVIRT */
> static __always_inline void hv_setup_sched_clock(void *sched_clock) {}
> --
> 2.55.0.rc0.799.gd6f94ed593-goog
>