Juergen Gross
2023-Mar-08 15:42 UTC
[PATCH] x86/paravirt: convert simple paravirt functions to asm
All functions referenced via __PV_IS_CALLEE_SAVE() need to be assembler functions, as those functions calls are hidden from gcc. In case the kernel is compiled with "-fzero-call-used-regs" the compiler will clobber caller-saved registers at the end of C functions, which will result in unexpectedly zeroed registers at the call site of the related paravirt functions. Replace the C functions with DEFINE_PARAVIRT_ASM() constructs using the same instructions as the related paravirt calls in the PVOP_ALT_[V]CALLEE*() macros. Signed-off-by: Juergen Gross <jgross at suse.com> --- arch/x86/include/asm/paravirt_types.h | 8 +++++++- arch/x86/kernel/paravirt.c | 27 ++++++--------------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h index 8c1da419260f..49f5c6955229 100644 --- a/arch/x86/include/asm/paravirt_types.h +++ b/arch/x86/include/asm/paravirt_types.h @@ -562,8 +562,14 @@ void paravirt_flush_lazy_mmu(void); void _paravirt_nop(void); void paravirt_BUG(void); -u64 _paravirt_ident_64(u64); unsigned long paravirt_ret0(void); +#ifdef CONFIG_PARAVIRT_XXL +u64 _paravirt_ident_64(u64); +unsigned long pv_native_save_fl(void); +void pv_native_irq_disable(void); +void pv_native_irq_enable(void); +unsigned long pv_native_read_cr2(void); +#endif #define paravirt_nop ((void *)_paravirt_nop) diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 42e182868873..d25ac4b08c41 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c @@ -64,11 +64,11 @@ static unsigned paravirt_patch_call(void *insn_buff, const void *target, } #ifdef CONFIG_PARAVIRT_XXL -/* identity function, which can be inlined */ -u64 notrace _paravirt_ident_64(u64 x) -{ - return x; -} +DEFINE_PARAVIRT_ASM(_paravirt_ident_64, "mov %rdi, %rax", .text); +DEFINE_PARAVIRT_ASM(pv_native_save_fl, "pushf; pop %rax", .text); +DEFINE_PARAVIRT_ASM(pv_native_irq_disable, "cli", .text); +DEFINE_PARAVIRT_ASM(pv_native_irq_enable, "sti", .text); +DEFINE_PARAVIRT_ASM(pv_native_read_cr2, "mov %cr2, %rax", .text); #endif DEFINE_STATIC_KEY_TRUE(virt_spin_lock_key); @@ -197,11 +197,6 @@ void paravirt_end_context_switch(struct task_struct *next) arch_enter_lazy_mmu_mode(); } -static noinstr unsigned long pv_native_read_cr2(void) -{ - return native_read_cr2(); -} - static noinstr void pv_native_write_cr2(unsigned long val) { native_write_cr2(val); @@ -222,16 +217,6 @@ noinstr void pv_native_wbinvd(void) native_wbinvd(); } -static noinstr void pv_native_irq_enable(void) -{ - native_irq_enable(); -} - -static noinstr void pv_native_irq_disable(void) -{ - native_irq_disable(); -} - static noinstr void pv_native_safe_halt(void) { native_safe_halt(); @@ -298,7 +283,7 @@ struct paravirt_patch_template pv_ops = { .cpu.end_context_switch = paravirt_nop, /* Irq ops. */ - .irq.save_fl = __PV_IS_CALLEE_SAVE(native_save_fl), + .irq.save_fl = __PV_IS_CALLEE_SAVE(pv_native_save_fl), .irq.irq_disable = __PV_IS_CALLEE_SAVE(pv_native_irq_disable), .irq.irq_enable = __PV_IS_CALLEE_SAVE(pv_native_irq_enable), .irq.safe_halt = pv_native_safe_halt, -- 2.35.3
Borislav Petkov
2023-Mar-09 13:39 UTC
[PATCH] x86/paravirt: convert simple paravirt functions to asm
On Wed, Mar 08, 2023 at 04:42:10PM +0100, Juergen Gross wrote:> All functions referenced via __PV_IS_CALLEE_SAVE() need to be assembler > functions, as those functions calls are hidden from gcc. In case the > kernel is compiled with "-fzero-call-used-regs" the compiler will > clobber caller-saved registers at the end of C functions, which will > result in unexpectedly zeroed registers at the call site of the > related paravirt functions. > > Replace the C functions with DEFINE_PARAVIRT_ASM() constructs using > the same instructions as the related paravirt calls in the > PVOP_ALT_[V]CALLEE*() macros. > > Signed-off-by: Juergen Gross <jgross at suse.com> > --- > arch/x86/include/asm/paravirt_types.h | 8 +++++++- > arch/x86/kernel/paravirt.c | 27 ++++++--------------------- > 2 files changed, 13 insertions(+), 22 deletions(-)Right, works with my particular reproducer. Turning them into asm prevents the compiler from doing the callee-clobbered zeroing and that's fine as this whole paravirt gunk is hiding the "CALL" insn from it and you putting them in asm is in line with this. And a negative diffstat.. So yeah, I'll queue it soon unless someone objects. Long term, I think we should continue switching all that pv stuff to using the alternatives. Thx. -- Regards/Gruss, Boris. https://people.kernel.org/tglx/notes-about-netiquette
Borislav Petkov
2023-Mar-16 16:50 UTC
[PATCH] x86/paravirt: convert simple paravirt functions to asm
On Wed, Mar 08, 2023 at 04:42:10PM +0100, Juergen Gross wrote:> All functions referenced via __PV_IS_CALLEE_SAVE() need to be assembler > functions, as those functions calls are hidden from gcc. In case the > kernel is compiled with "-fzero-call-used-regs" the compiler will > clobber caller-saved registers at the end of C functions, which will > result in unexpectedly zeroed registers at the call site of the > related paravirt functions. > > Replace the C functions with DEFINE_PARAVIRT_ASM() constructs using > the same instructions as the related paravirt calls in the > PVOP_ALT_[V]CALLEE*() macros. > > Signed-off-by: Juergen Gross <jgross at suse.com> > --- > arch/x86/include/asm/paravirt_types.h | 8 +++++++- > arch/x86/kernel/paravirt.c | 27 ++++++--------------------- > 2 files changed, 13 insertions(+), 22 deletions(-)objtool's not happy with this for whatever reason. I'll look later as to why. .config is allmodconfig with this patch ontop of tip:x86/paravirt: vmlinux.o: warning: objtool: pv_ops[31]: pv_native_irq_disable vmlinux.o: warning: objtool: default_idle+0x1e: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[31]: pv_native_irq_disable vmlinux.o: warning: objtool: mwait_idle+0x5d: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[31]: pv_native_irq_disable vmlinux.o: warning: objtool: cpu_idle_poll.isra.0+0x94: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[31]: pv_native_irq_disable vmlinux.o: warning: objtool: intel_idle_irq+0xab: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[31]: pv_native_irq_disable vmlinux.o: warning: objtool: acpi_safe_halt+0x2a: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[31]: pv_native_irq_disable vmlinux.o: warning: objtool: poll_idle+0x86: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[42]: pv_native_read_cr2 vmlinux.o: warning: objtool: exc_double_fault+0x3b: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[42]: pv_native_read_cr2 vmlinux.o: warning: objtool: exc_nmi+0x188: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[30]: pv_native_save_fl vmlinux.o: warning: objtool: __sev_put_ghcb+0x11: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[30]: pv_native_save_fl vmlinux.o: warning: objtool: __sev_get_ghcb+0x13: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[42]: pv_native_read_cr2 vmlinux.o: warning: objtool: exc_page_fault+0x1e: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[30]: pv_native_save_fl vmlinux.o: warning: objtool: lockdep_hardirqs_on+0xd0: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[30]: pv_native_save_fl vmlinux.o: warning: objtool: lockdep_hardirqs_off+0xe7: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[30]: pv_native_save_fl vmlinux.o: warning: objtool: look_up_lock_class+0x52: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[32]: pv_native_irq_enable vmlinux.o: warning: objtool: lock_is_held_type+0x143: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[30]: pv_native_save_fl vmlinux.o: warning: objtool: ct_kernel_enter.constprop.0+0x37: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[32]: pv_native_irq_enable vmlinux.o: warning: objtool: ct_idle_exit+0x51: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[30]: pv_native_save_fl vmlinux.o: warning: objtool: ct_idle_enter+0xe: call to {dynamic}() leaves .noinstr.text section vmlinux.o: warning: objtool: pv_ops[30]: pv_native_save_fl vmlinux.o: warning: objtool: check_preemption_disabled+0x4c: call to {dynamic}() leaves .noinstr.text section -- Regards/Gruss, Boris. https://people.kernel.org/tglx/notes-about-netiquette
Peter Zijlstra
2023-Mar-16 20:14 UTC
[PATCH] x86/paravirt: convert simple paravirt functions to asm
On Wed, Mar 08, 2023 at 04:42:10PM +0100, Juergen Gross wrote:> +DEFINE_PARAVIRT_ASM(pv_native_irq_disable, "cli", .text); > +DEFINE_PARAVIRT_ASM(pv_native_irq_enable, "sti", .text); > +DEFINE_PARAVIRT_ASM(pv_native_read_cr2, "mov %cr2, %rax", .text);per these v, the above ^ should be in .noinstr.text> -static noinstr unsigned long pv_native_read_cr2(void) > -static noinstr void pv_native_irq_enable(void) > -static noinstr void pv_native_irq_disable(void)
Possibly Parallel Threads
- [PATCH v2] x86/paravirt: convert simple paravirt functions to asm
- [RFC PATCH 0/3] x86/paravirt: Get rid of paravirt patching
- [RFC PATCH 0/3] x86/paravirt: Get rid of paravirt patching
- [PATCH v4 63/75] x86/sev-es: Handle #DB Events
- [PATCH v4 63/75] x86/sev-es: Handle #DB Events