* [PATCH v4 00/15] x86: major paravirt cleanup @ 2021-01-20 13:55 Juergen Gross 2021-01-20 13:55 ` [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() Juergen Gross 0 siblings, 1 reply; 5+ messages in thread From: Juergen Gross @ 2021-01-20 13:55 UTC (permalink / raw) To: xen-devel, linux-kernel, x86, virtualization, linux-hyperv, kvm, clang-built-linux Cc: Juergen Gross, Peter Zijlstra, Josh Poimboeuf, Jason Baron, Steven Rostedt, Ard Biesheuvel, Thomas Gleixner, Mel Gorman, Ingo Molnar, Michal Hocko, Paul E . McKenney, Borislav Petkov, H. Peter Anvin, Boris Ostrovsky, Stefano Stabellini, Andy Lutomirski, Deep Shah, VMware, Inc., K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger, Wei Liu, Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel, Daniel Lezcano, Nathan Chancellor, Nick Desaulniers [Resend due to all the Cc:'s missing] This is a major cleanup of the paravirt infrastructure aiming at eliminating all custom code patching via paravirt patching. This is achieved by using ALTERNATIVE instead, leading to the ability to give objtool access to the patched in instructions. In order to remove most of the 32-bit special handling from pvops the time related operations are switched to use static_call() instead. At the end of this series all paravirt patching has to do is to replace indirect calls with direct ones. In a further step this could be switched to static_call(), too, but that would require a major header file disentangling. For a clean build without any objtool warnings a modified objtool is required. Currently this is available in the "tip" tree in the objtool/core branch. Changes in V4: - fixed several build failures - removed objtool patch, as objtool patches are in tip now - added patch 1 for making usage of static_call easier - even more cleanup Changes in V3: - added patches 7 and 12 - addressed all comments Changes in V2: - added patches 5-12 Juergen Gross (14): x86/xen: use specific Xen pv interrupt entry for MCE x86/xen: use specific Xen pv interrupt entry for DF x86/pv: switch SWAPGS to ALTERNATIVE x86/xen: drop USERGS_SYSRET64 paravirt call x86: rework arch_local_irq_restore() to not use popf x86/paravirt: switch time pvops functions to use static_call() x86/alternative: support "not feature" and ALTERNATIVE_TERNARY x86: add new features for paravirt patching x86/paravirt: remove no longer needed 32-bit pvops cruft x86/paravirt: simplify paravirt macros x86/paravirt: switch iret pvops to ALTERNATIVE x86/paravirt: add new macros PVOP_ALT* supporting pvops in ALTERNATIVEs x86/paravirt: switch functions with custom code to ALTERNATIVE x86/paravirt: have only one paravirt patch function Peter Zijlstra (1): static_call: Pull some static_call declarations to the type headers arch/x86/Kconfig | 1 + arch/x86/entry/entry_32.S | 4 +- arch/x86/entry/entry_64.S | 28 ++- arch/x86/include/asm/alternative-asm.h | 4 + arch/x86/include/asm/alternative.h | 7 + arch/x86/include/asm/cpufeatures.h | 2 + arch/x86/include/asm/idtentry.h | 6 + arch/x86/include/asm/irqflags.h | 53 ++---- arch/x86/include/asm/mshyperv.h | 2 +- arch/x86/include/asm/paravirt.h | 197 ++++++++------------ arch/x86/include/asm/paravirt_types.h | 227 +++++++++--------------- arch/x86/kernel/Makefile | 3 +- arch/x86/kernel/alternative.c | 49 ++++- arch/x86/kernel/asm-offsets.c | 7 - arch/x86/kernel/asm-offsets_64.c | 3 - arch/x86/kernel/cpu/vmware.c | 5 +- arch/x86/kernel/irqflags.S | 11 -- arch/x86/kernel/kvm.c | 2 +- arch/x86/kernel/kvmclock.c | 2 +- arch/x86/kernel/paravirt-spinlocks.c | 9 + arch/x86/kernel/paravirt.c | 83 +++------ arch/x86/kernel/paravirt_patch.c | 109 ------------ arch/x86/kernel/tsc.c | 2 +- arch/x86/xen/enlighten_pv.c | 36 ++-- arch/x86/xen/irq.c | 23 --- arch/x86/xen/time.c | 11 +- arch/x86/xen/xen-asm.S | 52 +----- arch/x86/xen/xen-ops.h | 3 - drivers/clocksource/hyperv_timer.c | 5 +- drivers/xen/time.c | 2 +- include/linux/static_call.h | 20 --- include/linux/static_call_types.h | 27 +++ tools/include/linux/static_call_types.h | 27 +++ 33 files changed, 376 insertions(+), 646 deletions(-) delete mode 100644 arch/x86/kernel/paravirt_patch.c -- 2.26.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() 2021-01-20 13:55 [PATCH v4 00/15] x86: major paravirt cleanup Juergen Gross @ 2021-01-20 13:55 ` Juergen Gross 2021-01-24 16:14 ` Michael Kelley 2021-02-01 19:48 ` Borislav Petkov 0 siblings, 2 replies; 5+ messages in thread From: Juergen Gross @ 2021-01-20 13:55 UTC (permalink / raw) To: xen-devel, x86, linux-kernel, linux-hyperv, virtualization, kvm Cc: Juergen Gross, Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger, Wei Liu, Deep Shah, VMware, Inc., Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel, Boris Ostrovsky, Stefano Stabellini, Daniel Lezcano The time pvops functions are the only ones left which might be used in 32-bit mode and which return a 64-bit value. Switch them to use the static_call() mechanism instead of pvops, as this allows quite some simplification of the pvops implementation. Signed-off-by: Juergen Gross <jgross@suse.com> --- V4: - drop paravirt_time.h again - don't move Hyper-V code (Michael Kelley) --- arch/x86/Kconfig | 1 + arch/x86/include/asm/mshyperv.h | 2 +- arch/x86/include/asm/paravirt.h | 17 ++++++++++++++--- arch/x86/include/asm/paravirt_types.h | 6 ------ arch/x86/kernel/cpu/vmware.c | 5 +++-- arch/x86/kernel/kvm.c | 2 +- arch/x86/kernel/kvmclock.c | 2 +- arch/x86/kernel/paravirt.c | 16 ++++++++++++---- arch/x86/kernel/tsc.c | 2 +- arch/x86/xen/time.c | 11 ++++------- drivers/clocksource/hyperv_timer.c | 5 +++-- drivers/xen/time.c | 2 +- 12 files changed, 42 insertions(+), 29 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 21f851179ff0..7ccd4a80788c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -771,6 +771,7 @@ if HYPERVISOR_GUEST config PARAVIRT bool "Enable paravirtualization code" + depends on HAVE_STATIC_CALL help This changes the kernel so it can modify itself when it is run under a hypervisor, potentially improving performance significantly diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 30f76b966857..b4ee331d29a7 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -63,7 +63,7 @@ typedef int (*hyperv_fill_flush_list_func)( static __always_inline void hv_setup_sched_clock(void *sched_clock) { #ifdef CONFIG_PARAVIRT - pv_ops.time.sched_clock = sched_clock; + paravirt_set_sched_clock(sched_clock); #endif } diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 4abf110e2243..1e45b46fae84 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -15,11 +15,22 @@ #include <linux/bug.h> #include <linux/types.h> #include <linux/cpumask.h> +#include <linux/static_call_types.h> #include <asm/frame.h> -static inline unsigned long long paravirt_sched_clock(void) +u64 dummy_steal_clock(int cpu); +u64 dummy_sched_clock(void); + +DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock); +DECLARE_STATIC_CALL(pv_sched_clock, dummy_sched_clock); + +extern bool paravirt_using_native_sched_clock; + +void paravirt_set_sched_clock(u64 (*func)(void)); + +static inline u64 paravirt_sched_clock(void) { - return PVOP_CALL0(unsigned long long, time.sched_clock); + return static_call(pv_sched_clock)(); } struct static_key; @@ -33,7 +44,7 @@ bool pv_is_native_vcpu_is_preempted(void); static inline u64 paravirt_steal_clock(int cpu) { - return PVOP_CALL1(u64, time.steal_clock, cpu); + return static_call(pv_steal_clock)(cpu); } /* The paravirtualized I/O functions */ diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index de87087d3bde..1fff349e4792 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -95,11 +95,6 @@ struct pv_lazy_ops { } __no_randomize_layout; #endif -struct pv_time_ops { - unsigned long long (*sched_clock)(void); - unsigned long long (*steal_clock)(int cpu); -} __no_randomize_layout; - struct pv_cpu_ops { /* hooks for various privileged instructions */ void (*io_delay)(void); @@ -291,7 +286,6 @@ struct pv_lock_ops { * what to patch. */ struct paravirt_patch_template { struct pv_init_ops init; - struct pv_time_ops time; struct pv_cpu_ops cpu; struct pv_irq_ops irq; struct pv_mmu_ops mmu; diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index c6ede3b3d302..84fb8e3f3d1b 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -27,6 +27,7 @@ #include <linux/clocksource.h> #include <linux/cpu.h> #include <linux/reboot.h> +#include <linux/static_call.h> #include <asm/div64.h> #include <asm/x86_init.h> #include <asm/hypervisor.h> @@ -336,11 +337,11 @@ static void __init vmware_paravirt_ops_setup(void) vmware_cyc2ns_setup(); if (vmw_sched_clock) - pv_ops.time.sched_clock = vmware_sched_clock; + paravirt_set_sched_clock(vmware_sched_clock); if (vmware_is_stealclock_available()) { has_steal_clock = true; - pv_ops.time.steal_clock = vmware_steal_clock; + static_call_update(pv_steal_clock, vmware_steal_clock); /* We use reboot notifier only to disable steal clock */ register_reboot_notifier(&vmware_pv_reboot_nb); diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 5e78e01ca3b4..351ba99f6009 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -650,7 +650,7 @@ static void __init kvm_guest_init(void) if (kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) { has_steal_clock = 1; - pv_ops.time.steal_clock = kvm_steal_clock; + static_call_update(pv_steal_clock, kvm_steal_clock); } if (pv_tlb_flush_supported()) { diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index aa593743acf6..01e7c1839ace 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -106,7 +106,7 @@ static inline void kvm_sched_clock_init(bool stable) if (!stable) clear_sched_clock_stable(); kvm_sched_clock_offset = kvm_clock_read(); - pv_ops.time.sched_clock = kvm_sched_clock_read; + paravirt_set_sched_clock(kvm_sched_clock_read); pr_info("kvm-clock: using sched offset of %llu cycles", kvm_sched_clock_offset); diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index c60222ab8ab9..44e5b0fe28cb 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -14,6 +14,7 @@ #include <linux/highmem.h> #include <linux/kprobes.h> #include <linux/pgtable.h> +#include <linux/static_call.h> #include <asm/bug.h> #include <asm/paravirt.h> @@ -167,6 +168,17 @@ static u64 native_steal_clock(int cpu) return 0; } +DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock); +DEFINE_STATIC_CALL(pv_sched_clock, native_sched_clock); + +bool paravirt_using_native_sched_clock = true; + +void paravirt_set_sched_clock(u64 (*func)(void)) +{ + static_call_update(pv_sched_clock, func); + paravirt_using_native_sched_clock = (func == native_sched_clock); +} + /* These are in entry.S */ extern void native_iret(void); @@ -272,10 +284,6 @@ struct paravirt_patch_template pv_ops = { /* Init ops. */ .init.patch = native_patch, - /* Time ops. */ - .time.sched_clock = native_sched_clock, - .time.steal_clock = native_steal_clock, - /* Cpu ops. */ .cpu.io_delay = native_io_delay, diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index f70dffc2771f..b6f7853d8077 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -254,7 +254,7 @@ unsigned long long sched_clock(void) bool using_native_sched_clock(void) { - return pv_ops.time.sched_clock == native_sched_clock; + return paravirt_using_native_sched_clock; } #else unsigned long long diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 91f5b330dcc6..01930e182e99 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -379,11 +379,6 @@ void xen_timer_resume(void) } } -static const struct pv_time_ops xen_time_ops __initconst = { - .sched_clock = xen_sched_clock, - .steal_clock = xen_steal_clock, -}; - static struct pvclock_vsyscall_time_info *xen_clock __read_mostly; static u64 xen_clock_value_saved; @@ -528,7 +523,8 @@ static void __init xen_time_init(void) void __init xen_init_time_ops(void) { xen_sched_clock_offset = xen_clocksource_read(); - pv_ops.time = xen_time_ops; + static_call_update(pv_steal_clock, xen_steal_clock); + paravirt_set_sched_clock(xen_sched_clock); x86_init.timers.timer_init = xen_time_init; x86_init.timers.setup_percpu_clockev = x86_init_noop; @@ -570,7 +566,8 @@ void __init xen_hvm_init_time_ops(void) } xen_sched_clock_offset = xen_clocksource_read(); - pv_ops.time = xen_time_ops; + static_call_update(pv_steal_clock, xen_steal_clock); + paravirt_set_sched_clock(xen_sched_clock); x86_init.timers.setup_percpu_clockev = xen_time_init; x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents; diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index ba04cb381cd3..bf3bf20bc6bd 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -18,6 +18,7 @@ #include <linux/sched_clock.h> #include <linux/mm.h> #include <linux/cpuhotplug.h> +#include <linux/static_call.h> #include <clocksource/hyperv_timer.h> #include <asm/hyperv-tlfs.h> #include <asm/mshyperv.h> @@ -445,7 +446,7 @@ static bool __init hv_init_tsc_clocksource(void) clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); hv_sched_clock_offset = hv_read_reference_counter(); - hv_setup_sched_clock(read_hv_sched_clock_tsc); + paravirt_set_sched_clock(read_hv_sched_clock_tsc); return true; } @@ -470,6 +471,6 @@ void __init hv_init_clocksource(void) clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100); hv_sched_clock_offset = hv_read_reference_counter(); - hv_setup_sched_clock(read_hv_sched_clock_msr); + static_call_update(pv_sched_clock, read_hv_sched_clock_msr); } EXPORT_SYMBOL_GPL(hv_init_clocksource); diff --git a/drivers/xen/time.c b/drivers/xen/time.c index 108edbcbc040..199c016834ed 100644 --- a/drivers/xen/time.c +++ b/drivers/xen/time.c @@ -175,7 +175,7 @@ void __init xen_time_setup_guest(void) xen_runstate_remote = !HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_runstate_update_flag); - pv_ops.time.steal_clock = xen_steal_clock; + static_call_update(pv_steal_clock, xen_steal_clock); static_key_slow_inc(¶virt_steal_enabled); if (xen_runstate_remote) -- 2.26.2 ^ permalink raw reply related [flat|nested] 5+ messages in thread
* RE: [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() 2021-01-20 13:55 ` [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() Juergen Gross @ 2021-01-24 16:14 ` Michael Kelley 2021-02-01 19:48 ` Borislav Petkov 1 sibling, 0 replies; 5+ messages in thread From: Michael Kelley @ 2021-01-24 16:14 UTC (permalink / raw) To: Juergen Gross, xen-devel, x86, linux-kernel, linux-hyperv, virtualization, kvm Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin, KY Srinivasan, Haiyang Zhang, Stephen Hemminger, Wei Liu, Deep Shah, VMware, Inc., Paolo Bonzini, Sean Christopherson, vkuznets, Wanpeng Li, Jim Mattson, Joerg Roedel, Boris Ostrovsky, Stefano Stabellini, Daniel Lezcano From: Juergen Gross <jgross@suse.com> Sent: Wednesday, January 20, 2021 5:56 AM > > The time pvops functions are the only ones left which might be > used in 32-bit mode and which return a 64-bit value. > > Switch them to use the static_call() mechanism instead of pvops, as > this allows quite some simplification of the pvops implementation. > > Signed-off-by: Juergen Gross <jgross@suse.com> > --- > V4: > - drop paravirt_time.h again > - don't move Hyper-V code (Michael Kelley) > --- > arch/x86/Kconfig | 1 + > arch/x86/include/asm/mshyperv.h | 2 +- > arch/x86/include/asm/paravirt.h | 17 ++++++++++++++--- > arch/x86/include/asm/paravirt_types.h | 6 ------ > arch/x86/kernel/cpu/vmware.c | 5 +++-- > arch/x86/kernel/kvm.c | 2 +- > arch/x86/kernel/kvmclock.c | 2 +- > arch/x86/kernel/paravirt.c | 16 ++++++++++++---- > arch/x86/kernel/tsc.c | 2 +- > arch/x86/xen/time.c | 11 ++++------- > drivers/clocksource/hyperv_timer.c | 5 +++-- > drivers/xen/time.c | 2 +- > 12 files changed, 42 insertions(+), 29 deletions(-) > [snip] > diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h > index 30f76b966857..b4ee331d29a7 100644 > --- a/arch/x86/include/asm/mshyperv.h > +++ b/arch/x86/include/asm/mshyperv.h > @@ -63,7 +63,7 @@ typedef int (*hyperv_fill_flush_list_func)( > static __always_inline void hv_setup_sched_clock(void *sched_clock) > { > #ifdef CONFIG_PARAVIRT > - pv_ops.time.sched_clock = sched_clock; > + paravirt_set_sched_clock(sched_clock); > #endif > } > This looks fine. [snip] > diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c > index ba04cb381cd3..bf3bf20bc6bd 100644 > --- a/drivers/clocksource/hyperv_timer.c > +++ b/drivers/clocksource/hyperv_timer.c > @@ -18,6 +18,7 @@ > #include <linux/sched_clock.h> > #include <linux/mm.h> > #include <linux/cpuhotplug.h> > +#include <linux/static_call.h> > #include <clocksource/hyperv_timer.h> > #include <asm/hyperv-tlfs.h> > #include <asm/mshyperv.h> > @@ -445,7 +446,7 @@ static bool __init hv_init_tsc_clocksource(void) > clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); > > hv_sched_clock_offset = hv_read_reference_counter(); > - hv_setup_sched_clock(read_hv_sched_clock_tsc); > + paravirt_set_sched_clock(read_hv_sched_clock_tsc); > > return true; > } > @@ -470,6 +471,6 @@ void __init hv_init_clocksource(void) > clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100); > > hv_sched_clock_offset = hv_read_reference_counter(); > - hv_setup_sched_clock(read_hv_sched_clock_msr); > + static_call_update(pv_sched_clock, read_hv_sched_clock_msr); > } > EXPORT_SYMBOL_GPL(hv_init_clocksource); The changes to hyperv_timer.c aren't needed and shouldn't be there, so as to preserve hyperv_timer.c as architecture neutral. With your update to hv_setup_sched_clock() in mshyperv.h, the original code works correctly. While there are two call sites for hv_setup_sched_clock(), only one is called. And once the sched clock function is set, it is never changed or overridden. Michael ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() 2021-01-20 13:55 ` [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() Juergen Gross 2021-01-24 16:14 ` Michael Kelley @ 2021-02-01 19:48 ` Borislav Petkov 1 sibling, 0 replies; 5+ messages in thread From: Borislav Petkov @ 2021-02-01 19:48 UTC (permalink / raw) To: Juergen Gross Cc: xen-devel, x86, linux-kernel, linux-hyperv, virtualization, kvm, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, K. Y. Srinivasan, Haiyang Zhang, Stephen Hemminger, Wei Liu, Deep Shah, VMware, Inc., Paolo Bonzini, Sean Christopherson, Vitaly Kuznetsov, Wanpeng Li, Jim Mattson, Joerg Roedel, Boris Ostrovsky, Stefano Stabellini, Daniel Lezcano On Wed, Jan 20, 2021 at 02:55:47PM +0100, Juergen Gross wrote: > The time pvops functions are the only ones left which might be > used in 32-bit mode and which return a 64-bit value. > > Switch them to use the static_call() mechanism instead of pvops, as > this allows quite some simplification of the pvops implementation. > > Signed-off-by: Juergen Gross <jgross@suse.com> > --- > V4: > - drop paravirt_time.h again > - don't move Hyper-V code (Michael Kelley) > --- > arch/x86/Kconfig | 1 + > arch/x86/include/asm/mshyperv.h | 2 +- > arch/x86/include/asm/paravirt.h | 17 ++++++++++++++--- > arch/x86/include/asm/paravirt_types.h | 6 ------ > arch/x86/kernel/cpu/vmware.c | 5 +++-- > arch/x86/kernel/kvm.c | 2 +- > arch/x86/kernel/kvmclock.c | 2 +- > arch/x86/kernel/paravirt.c | 16 ++++++++++++---- > arch/x86/kernel/tsc.c | 2 +- > arch/x86/xen/time.c | 11 ++++------- > drivers/clocksource/hyperv_timer.c | 5 +++-- > drivers/xen/time.c | 2 +- > 12 files changed, 42 insertions(+), 29 deletions(-) > > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig > index 21f851179ff0..7ccd4a80788c 100644 > --- a/arch/x86/Kconfig > +++ b/arch/x86/Kconfig > @@ -771,6 +771,7 @@ if HYPERVISOR_GUEST > > config PARAVIRT > bool "Enable paravirtualization code" > + depends on HAVE_STATIC_CALL > help > This changes the kernel so it can modify itself when it is run > under a hypervisor, potentially improving performance significantly > diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h > index 30f76b966857..b4ee331d29a7 100644 > --- a/arch/x86/include/asm/mshyperv.h > +++ b/arch/x86/include/asm/mshyperv.h > @@ -63,7 +63,7 @@ typedef int (*hyperv_fill_flush_list_func)( > static __always_inline void hv_setup_sched_clock(void *sched_clock) > { > #ifdef CONFIG_PARAVIRT > - pv_ops.time.sched_clock = sched_clock; > + paravirt_set_sched_clock(sched_clock); > #endif > } > > diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h > index 4abf110e2243..1e45b46fae84 100644 > --- a/arch/x86/include/asm/paravirt.h > +++ b/arch/x86/include/asm/paravirt.h > @@ -15,11 +15,22 @@ > #include <linux/bug.h> > #include <linux/types.h> > #include <linux/cpumask.h> > +#include <linux/static_call_types.h> > #include <asm/frame.h> > > -static inline unsigned long long paravirt_sched_clock(void) > +u64 dummy_steal_clock(int cpu); > +u64 dummy_sched_clock(void); > + > +DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock); > +DECLARE_STATIC_CALL(pv_sched_clock, dummy_sched_clock); Did you build this before sending? I'm test-applying this on rc6 + tip/master so I probably am using a different tree so it looks like something has changed in the meantime. -rc6 has a couple of Xen changes which made applying those to need some wiggling in... Maybe you should redo them ontop of tip/master. That is, *if* they're going to eventually go through tip. The diffstat has Xen stuff too so we might need some synchronization here what goes where how... ./arch/x86/include/asm/paravirt.h:24:1: warning: data definition has no type or storage class 24 | DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock); | ^~~~~~~~~~~~~~~~~~~ ./arch/x86/include/asm/paravirt.h:24:1: error: type defaults to ‘int’ in declaration of ‘DECLARE_STATIC_CALL’ [-Werror=implicit-int] ./arch/x86/include/asm/paravirt.h:24:1: warning: parameter names (without types) in function declaration ./arch/x86/include/asm/paravirt.h:25:1: warning: data definition has no type or storage class 25 | DECLARE_STATIC_CALL(pv_sched_clock, dummy_sched_clock); | ^~~~~~~~~~~~~~~~~~~ ./arch/x86/include/asm/paravirt.h:25:1: error: type defaults to ‘int’ in declaration of ‘DECLARE_STATIC_CALL’ [-Werror=implicit-int] ./arch/x86/include/asm/paravirt.h:25:1: warning: parameter names (without types) in function declaration ./arch/x86/include/asm/paravirt.h: In function ‘paravirt_sched_clock’: ./arch/x86/include/asm/paravirt.h:33:9: error: implicit declaration of function ‘static_call’ [-Werror=implicit-function-declaration] 33 | return static_call(pv_sched_clock)(); | ^~~~~~~~~~~ ./arch/x86/include/asm/paravirt.h:33:21: error: ‘pv_sched_clock’ undeclared (first use in this function); did you mean ‘dummy_sched_clock’? 33 | return static_call(pv_sched_clock)(); | ^~~~~~~~~~~~~~ | dummy_sched_clock ./arch/x86/include/asm/paravirt.h:33:21: note: each undeclared identifier is reported only once for each function it appears in ./arch/x86/include/asm/paravirt.h: In function ‘paravirt_steal_clock’: ./arch/x86/include/asm/paravirt.h:47:21: error: ‘pv_steal_clock’ undeclared (first use in this function); did you mean ‘dummy_steal_clock’? 47 | return static_call(pv_steal_clock)(cpu); | ^~~~~~~~~~~~~~ | dummy_steal_clock cc1: some warnings being treated as errors make[1]: *** [scripts/Makefile.build:117: arch/x86/kernel/asm-offsets.s] Error 1 make: *** [Makefile:1200: prepare0] Error 2 Thx. -- Regards/Gruss, Boris. https://people.kernel.org/tglx/notes-about-netiquette ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 00/15] x86: major paravirt cleanup @ 2021-01-20 13:25 Juergen Gross 2021-01-20 13:26 ` [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() Juergen Gross 0 siblings, 1 reply; 5+ messages in thread From: Juergen Gross @ 2021-01-20 13:25 UTC (permalink / raw) To: bpetkov, linux-kernel, x86, virtualization, linux-hyperv, kvm, clang-built-linux This is a major cleanup of the paravirt infrastructure aiming at eliminating all custom code patching via paravirt patching. This is achieved by using ALTERNATIVE instead, leading to the ability to give objtool access to the patched in instructions. In order to remove most of the 32-bit special handling from pvops the time related operations are switched to use static_call() instead. At the end of this series all paravirt patching has to do is to replace indirect calls with direct ones. In a further step this could be switched to static_call(), too, but that would require a major header file disentangling. For a clean build without any objtool warnings a modified objtool is required. Currently this is available in the "tip" tree in the objtool/core branch. Changes in V4: - fixed several build failures - removed objtool patch, as objtool patches are in tip now - added patch 1 for making usage of static_call easier - even more cleanup Changes in V3: - added patches 7 and 12 - addressed all comments Changes in V2: - added patches 5-12 Juergen Gross (14): x86/xen: use specific Xen pv interrupt entry for MCE x86/xen: use specific Xen pv interrupt entry for DF x86/pv: switch SWAPGS to ALTERNATIVE x86/xen: drop USERGS_SYSRET64 paravirt call x86: rework arch_local_irq_restore() to not use popf x86/paravirt: switch time pvops functions to use static_call() x86/alternative: support "not feature" and ALTERNATIVE_TERNARY x86: add new features for paravirt patching x86/paravirt: remove no longer needed 32-bit pvops cruft x86/paravirt: simplify paravirt macros x86/paravirt: switch iret pvops to ALTERNATIVE x86/paravirt: add new macros PVOP_ALT* supporting pvops in ALTERNATIVEs x86/paravirt: switch functions with custom code to ALTERNATIVE x86/paravirt: have only one paravirt patch function Peter Zijlstra (1): static_call: Pull some static_call declarations to the type headers arch/x86/Kconfig | 1 + arch/x86/entry/entry_32.S | 4 +- arch/x86/entry/entry_64.S | 28 ++- arch/x86/include/asm/alternative-asm.h | 4 + arch/x86/include/asm/alternative.h | 7 + arch/x86/include/asm/cpufeatures.h | 2 + arch/x86/include/asm/idtentry.h | 6 + arch/x86/include/asm/irqflags.h | 53 ++---- arch/x86/include/asm/mshyperv.h | 2 +- arch/x86/include/asm/paravirt.h | 197 ++++++++------------ arch/x86/include/asm/paravirt_types.h | 227 +++++++++--------------- arch/x86/kernel/Makefile | 3 +- arch/x86/kernel/alternative.c | 49 ++++- arch/x86/kernel/asm-offsets.c | 7 - arch/x86/kernel/asm-offsets_64.c | 3 - arch/x86/kernel/cpu/vmware.c | 5 +- arch/x86/kernel/irqflags.S | 11 -- arch/x86/kernel/kvm.c | 2 +- arch/x86/kernel/kvmclock.c | 2 +- arch/x86/kernel/paravirt-spinlocks.c | 9 + arch/x86/kernel/paravirt.c | 83 +++------ arch/x86/kernel/paravirt_patch.c | 109 ------------ arch/x86/kernel/tsc.c | 2 +- arch/x86/xen/enlighten_pv.c | 36 ++-- arch/x86/xen/irq.c | 23 --- arch/x86/xen/time.c | 11 +- arch/x86/xen/xen-asm.S | 52 +----- arch/x86/xen/xen-ops.h | 3 - drivers/clocksource/hyperv_timer.c | 5 +- drivers/xen/time.c | 2 +- include/linux/static_call.h | 20 --- include/linux/static_call_types.h | 27 +++ tools/include/linux/static_call_types.h | 27 +++ 33 files changed, 376 insertions(+), 646 deletions(-) delete mode 100644 arch/x86/kernel/paravirt_patch.c -- 2.26.2 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() 2021-01-20 13:25 [PATCH v4 00/15] x86: major paravirt cleanup Juergen Gross @ 2021-01-20 13:26 ` Juergen Gross 0 siblings, 0 replies; 5+ messages in thread From: Juergen Gross @ 2021-01-20 13:26 UTC (permalink / raw) To: bpetkov, x86, linux-kernel, linux-hyperv, virtualization, kvm The time pvops functions are the only ones left which might be used in 32-bit mode and which return a 64-bit value. Switch them to use the static_call() mechanism instead of pvops, as this allows quite some simplification of the pvops implementation. Signed-off-by: Juergen Gross <jgross@suse.com> --- V4: - drop paravirt_time.h again - don't move Hyper-V code (Michael Kelley) --- arch/x86/Kconfig | 1 + arch/x86/include/asm/mshyperv.h | 2 +- arch/x86/include/asm/paravirt.h | 17 ++++++++++++++--- arch/x86/include/asm/paravirt_types.h | 6 ------ arch/x86/kernel/cpu/vmware.c | 5 +++-- arch/x86/kernel/kvm.c | 2 +- arch/x86/kernel/kvmclock.c | 2 +- arch/x86/kernel/paravirt.c | 16 ++++++++++++---- arch/x86/kernel/tsc.c | 2 +- arch/x86/xen/time.c | 11 ++++------- drivers/clocksource/hyperv_timer.c | 5 +++-- drivers/xen/time.c | 2 +- 12 files changed, 42 insertions(+), 29 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 21f851179ff0..7ccd4a80788c 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -771,6 +771,7 @@ if HYPERVISOR_GUEST config PARAVIRT bool "Enable paravirtualization code" + depends on HAVE_STATIC_CALL help This changes the kernel so it can modify itself when it is run under a hypervisor, potentially improving performance significantly diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h index 30f76b966857..b4ee331d29a7 100644 --- a/arch/x86/include/asm/mshyperv.h +++ b/arch/x86/include/asm/mshyperv.h @@ -63,7 +63,7 @@ typedef int (*hyperv_fill_flush_list_func)( static __always_inline void hv_setup_sched_clock(void *sched_clock) { #ifdef CONFIG_PARAVIRT - pv_ops.time.sched_clock = sched_clock; + paravirt_set_sched_clock(sched_clock); #endif } diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h index 4abf110e2243..1e45b46fae84 100644 --- a/arch/x86/include/asm/paravirt.h +++ b/arch/x86/include/asm/paravirt.h @@ -15,11 +15,22 @@ #include <linux/bug.h> #include <linux/types.h> #include <linux/cpumask.h> +#include <linux/static_call_types.h> #include <asm/frame.h> -static inline unsigned long long paravirt_sched_clock(void) +u64 dummy_steal_clock(int cpu); +u64 dummy_sched_clock(void); + +DECLARE_STATIC_CALL(pv_steal_clock, dummy_steal_clock); +DECLARE_STATIC_CALL(pv_sched_clock, dummy_sched_clock); + +extern bool paravirt_using_native_sched_clock; + +void paravirt_set_sched_clock(u64 (*func)(void)); + +static inline u64 paravirt_sched_clock(void) { - return PVOP_CALL0(unsigned long long, time.sched_clock); + return static_call(pv_sched_clock)(); } struct static_key; @@ -33,7 +44,7 @@ bool pv_is_native_vcpu_is_preempted(void); static inline u64 paravirt_steal_clock(int cpu) { - return PVOP_CALL1(u64, time.steal_clock, cpu); + return static_call(pv_steal_clock)(cpu); } /* The paravirtualized I/O functions */ diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index de87087d3bde..1fff349e4792 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -95,11 +95,6 @@ struct pv_lazy_ops { } __no_randomize_layout; #endif -struct pv_time_ops { - unsigned long long (*sched_clock)(void); - unsigned long long (*steal_clock)(int cpu); -} __no_randomize_layout; - struct pv_cpu_ops { /* hooks for various privileged instructions */ void (*io_delay)(void); @@ -291,7 +286,6 @@ struct pv_lock_ops { * what to patch. */ struct paravirt_patch_template { struct pv_init_ops init; - struct pv_time_ops time; struct pv_cpu_ops cpu; struct pv_irq_ops irq; struct pv_mmu_ops mmu; diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c index c6ede3b3d302..84fb8e3f3d1b 100644 --- a/arch/x86/kernel/cpu/vmware.c +++ b/arch/x86/kernel/cpu/vmware.c @@ -27,6 +27,7 @@ #include <linux/clocksource.h> #include <linux/cpu.h> #include <linux/reboot.h> +#include <linux/static_call.h> #include <asm/div64.h> #include <asm/x86_init.h> #include <asm/hypervisor.h> @@ -336,11 +337,11 @@ static void __init vmware_paravirt_ops_setup(void) vmware_cyc2ns_setup(); if (vmw_sched_clock) - pv_ops.time.sched_clock = vmware_sched_clock; + paravirt_set_sched_clock(vmware_sched_clock); if (vmware_is_stealclock_available()) { has_steal_clock = true; - pv_ops.time.steal_clock = vmware_steal_clock; + static_call_update(pv_steal_clock, vmware_steal_clock); /* We use reboot notifier only to disable steal clock */ register_reboot_notifier(&vmware_pv_reboot_nb); diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 5e78e01ca3b4..351ba99f6009 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -650,7 +650,7 @@ static void __init kvm_guest_init(void) if (kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) { has_steal_clock = 1; - pv_ops.time.steal_clock = kvm_steal_clock; + static_call_update(pv_steal_clock, kvm_steal_clock); } if (pv_tlb_flush_supported()) { diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index aa593743acf6..01e7c1839ace 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -106,7 +106,7 @@ static inline void kvm_sched_clock_init(bool stable) if (!stable) clear_sched_clock_stable(); kvm_sched_clock_offset = kvm_clock_read(); - pv_ops.time.sched_clock = kvm_sched_clock_read; + paravirt_set_sched_clock(kvm_sched_clock_read); pr_info("kvm-clock: using sched offset of %llu cycles", kvm_sched_clock_offset); diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index c60222ab8ab9..44e5b0fe28cb 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -14,6 +14,7 @@ #include <linux/highmem.h> #include <linux/kprobes.h> #include <linux/pgtable.h> +#include <linux/static_call.h> #include <asm/bug.h> #include <asm/paravirt.h> @@ -167,6 +168,17 @@ static u64 native_steal_clock(int cpu) return 0; } +DEFINE_STATIC_CALL(pv_steal_clock, native_steal_clock); +DEFINE_STATIC_CALL(pv_sched_clock, native_sched_clock); + +bool paravirt_using_native_sched_clock = true; + +void paravirt_set_sched_clock(u64 (*func)(void)) +{ + static_call_update(pv_sched_clock, func); + paravirt_using_native_sched_clock = (func == native_sched_clock); +} + /* These are in entry.S */ extern void native_iret(void); @@ -272,10 +284,6 @@ struct paravirt_patch_template pv_ops = { /* Init ops. */ .init.patch = native_patch, - /* Time ops. */ - .time.sched_clock = native_sched_clock, - .time.steal_clock = native_steal_clock, - /* Cpu ops. */ .cpu.io_delay = native_io_delay, diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index f70dffc2771f..b6f7853d8077 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -254,7 +254,7 @@ unsigned long long sched_clock(void) bool using_native_sched_clock(void) { - return pv_ops.time.sched_clock == native_sched_clock; + return paravirt_using_native_sched_clock; } #else unsigned long long diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 91f5b330dcc6..01930e182e99 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -379,11 +379,6 @@ void xen_timer_resume(void) } } -static const struct pv_time_ops xen_time_ops __initconst = { - .sched_clock = xen_sched_clock, - .steal_clock = xen_steal_clock, -}; - static struct pvclock_vsyscall_time_info *xen_clock __read_mostly; static u64 xen_clock_value_saved; @@ -528,7 +523,8 @@ static void __init xen_time_init(void) void __init xen_init_time_ops(void) { xen_sched_clock_offset = xen_clocksource_read(); - pv_ops.time = xen_time_ops; + static_call_update(pv_steal_clock, xen_steal_clock); + paravirt_set_sched_clock(xen_sched_clock); x86_init.timers.timer_init = xen_time_init; x86_init.timers.setup_percpu_clockev = x86_init_noop; @@ -570,7 +566,8 @@ void __init xen_hvm_init_time_ops(void) } xen_sched_clock_offset = xen_clocksource_read(); - pv_ops.time = xen_time_ops; + static_call_update(pv_steal_clock, xen_steal_clock); + paravirt_set_sched_clock(xen_sched_clock); x86_init.timers.setup_percpu_clockev = xen_time_init; x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents; diff --git a/drivers/clocksource/hyperv_timer.c b/drivers/clocksource/hyperv_timer.c index ba04cb381cd3..bf3bf20bc6bd 100644 --- a/drivers/clocksource/hyperv_timer.c +++ b/drivers/clocksource/hyperv_timer.c @@ -18,6 +18,7 @@ #include <linux/sched_clock.h> #include <linux/mm.h> #include <linux/cpuhotplug.h> +#include <linux/static_call.h> #include <clocksource/hyperv_timer.h> #include <asm/hyperv-tlfs.h> #include <asm/mshyperv.h> @@ -445,7 +446,7 @@ static bool __init hv_init_tsc_clocksource(void) clocksource_register_hz(&hyperv_cs_tsc, NSEC_PER_SEC/100); hv_sched_clock_offset = hv_read_reference_counter(); - hv_setup_sched_clock(read_hv_sched_clock_tsc); + paravirt_set_sched_clock(read_hv_sched_clock_tsc); return true; } @@ -470,6 +471,6 @@ void __init hv_init_clocksource(void) clocksource_register_hz(&hyperv_cs_msr, NSEC_PER_SEC/100); hv_sched_clock_offset = hv_read_reference_counter(); - hv_setup_sched_clock(read_hv_sched_clock_msr); + static_call_update(pv_sched_clock, read_hv_sched_clock_msr); } EXPORT_SYMBOL_GPL(hv_init_clocksource); diff --git a/drivers/xen/time.c b/drivers/xen/time.c index 108edbcbc040..199c016834ed 100644 --- a/drivers/xen/time.c +++ b/drivers/xen/time.c @@ -175,7 +175,7 @@ void __init xen_time_setup_guest(void) xen_runstate_remote = !HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_runstate_update_flag); - pv_ops.time.steal_clock = xen_steal_clock; + static_call_update(pv_steal_clock, xen_steal_clock); static_key_slow_inc(¶virt_steal_enabled); if (xen_runstate_remote) -- 2.26.2 ^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2021-02-01 19:51 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2021-01-20 13:55 [PATCH v4 00/15] x86: major paravirt cleanup Juergen Gross 2021-01-20 13:55 ` [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() Juergen Gross 2021-01-24 16:14 ` Michael Kelley 2021-02-01 19:48 ` Borislav Petkov -- strict thread matches above, loose matches on Subject: below -- 2021-01-20 13:25 [PATCH v4 00/15] x86: major paravirt cleanup Juergen Gross 2021-01-20 13:26 ` [PATCH v4 07/15] x86/paravirt: switch time pvops functions to use static_call() Juergen Gross
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).