From 1881b4d64700e54ab8706a43c1ad119c3ad653dc Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Mar 2023 08:43:51 +0100 Subject: ARM: 9291/1: decompressor: simplify the path to the top vmlinux With commit 8debed3efe3a ("kbuild: export top-level LDFLAGS_vmlinux only to scripts/Makefile.vmlinux") applied, we no longer see the error message while building the ARM zImage, but we do not have a good reason to complicate the file path either. '$(obj)/../../../../vmlinux' is canonicalized to 'vmlinux'. Signed-off-by: Masahiro Yamada Signed-off-by: Russell King (Oracle) --- arch/arm/boot/compressed/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/arm') diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 2ef651a78fa2..726ecabcef09 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -107,7 +107,7 @@ ccflags-remove-$(CONFIG_FUNCTION_TRACER) += -pg asflags-y := -DZIMAGE # Supply kernel BSS size to the decompressor via a linker symbol. -KBSS_SZ = $(shell echo $$(($$($(NM) $(obj)/../../../../vmlinux | \ +KBSS_SZ = $(shell echo $$(($$($(NM) vmlinux | \ sed -n -e 's/^\([^ ]*\) [ABD] __bss_start$$/-0x\1/p' \ -e 's/^\([^ ]*\) [ABD] __bss_stop$$/+0x\1/p') )) ) LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ) -- cgit v1.2.3 From dae904d96ad6a5fa79bd9d99a3decf93685d398b Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 21 Mar 2023 12:01:02 +0100 Subject: ARM: 9292/1: vfp: Pass thread_info pointer to vfp_support_entry Instead of dereferencing thread_info in do_vfp, pass the thread_info pointer to vfp_support_entry via R1. That way, we only use a single caller save register, which makes it easier to convert do_vfp to C code in a subsequent patch. Note that, unlike the CPU number, which can change due to preemption, passing the thread_info pointer can safely be done with preemption enabled. Signed-off-by: Ard Biesheuvel Reviewed-by: Linus Walleij Tested-by: Guenter Roeck Signed-off-by: Russell King (Oracle) --- arch/arm/vfp/entry.S | 5 +---- arch/arm/vfp/vfphw.S | 10 +++++++--- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 9a89264cdcc0..cfedc2a3dbd6 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -22,15 +22,12 @@ @ IRQs enabled. @ ENTRY(do_vfp) - local_bh_disable r10, r4 + mov r1, r10 ldr r4, .LCvfp - ldr r11, [r10, #TI_CPU] @ CPU number - add r10, r10, #TI_VFPSTATE @ r10 = workspace ldr pc, [r4] @ call VFP entry point ENDPROC(do_vfp) ENTRY(vfp_null_entry) - local_bh_enable_ti r10, r4 ret lr ENDPROC(vfp_null_entry) diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 26c4f61ecfa3..6d056d810e48 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -6,9 +6,9 @@ * Written by Deep Blue Solutions Limited. * * This code is called from the kernel's undefined instruction trap. + * r1 holds the thread_info pointer * r9 holds the return address for successful handling. * lr holds the return address for unrecognised instructions. - * r10 points at the start of the private FP workspace in the thread structure * sp points to a struct pt_regs (as defined in include/asm/proc/ptrace.h) */ #include @@ -69,13 +69,17 @@ @ VFP hardware support entry point. @ @ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) +@ r1 = thread_info pointer @ r2 = PC value to resume execution after successful emulation @ r9 = normal "successful" return address -@ r10 = vfp_state union -@ r11 = CPU number @ lr = unrecognised instruction return address @ IRQs enabled. ENTRY(vfp_support_entry) + local_bh_disable r1, r4 + + ldr r11, [r1, #TI_CPU] @ CPU number + add r10, r1, #TI_VFPSTATE @ r10 = workspace + DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10 .fpu vfpv2 -- cgit v1.2.3 From 3a2bdad0b46649cc73fb3b3f9e2b91ef97a7fa63 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 21 Mar 2023 12:01:51 +0100 Subject: ARM: 9293/1: vfp: Pass successful return address via register R3 In preparation for reimplementing the do_vfp()->vfp_support_entry() handover in C code, switch to using R3 to pass the 'success' return address, rather than R9, as it cannot be used for parameter passing. Signed-off-by: Ard Biesheuvel Reviewed-by: Linus Walleij Tested-by: Guenter Roeck Signed-off-by: Russell King (Oracle) --- arch/arm/vfp/entry.S | 1 + arch/arm/vfp/vfphw.S | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index cfedc2a3dbd6..6dabb4761778 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -23,6 +23,7 @@ @ ENTRY(do_vfp) mov r1, r10 + mov r3, r9 ldr r4, .LCvfp ldr pc, [r4] @ call VFP entry point ENDPROC(do_vfp) diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 6d056d810e48..60acd42e0578 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -7,7 +7,7 @@ * * This code is called from the kernel's undefined instruction trap. * r1 holds the thread_info pointer - * r9 holds the return address for successful handling. + * r3 holds the return address for successful handling. * lr holds the return address for unrecognised instructions. * sp points to a struct pt_regs (as defined in include/asm/proc/ptrace.h) */ @@ -71,7 +71,7 @@ @ r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) @ r1 = thread_info pointer @ r2 = PC value to resume execution after successful emulation -@ r9 = normal "successful" return address +@ r3 = normal "successful" return address @ lr = unrecognised instruction return address @ IRQs enabled. ENTRY(vfp_support_entry) @@ -89,9 +89,9 @@ ENTRY(vfp_support_entry) bne look_for_VFP_exceptions @ VFP is already enabled DBGSTR1 "enable %x", r10 - ldr r3, vfp_current_hw_state_address + ldr r9, vfp_current_hw_state_address orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set - ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer + ldr r4, [r9, r11, lsl #2] @ vfp_current_hw_state pointer bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled cmp r4, r10 @ this thread owns the hw context? #ifndef CONFIG_SMP @@ -150,7 +150,7 @@ vfp_reload_hw: #endif DBGSTR1 "load state %p", r10 - str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer + str r10, [r9, r11, lsl #2] @ update the vfp_current_hw_state pointer @ Load the saved state back into the VFP VFPFLDMIA r10, r5 @ reload the working registers while @ FPEXC is in a safe state @@ -180,7 +180,7 @@ vfp_hw_state_valid: @ always subtract 4 from the following @ instruction address. local_bh_enable_ti r10, r4 - ret r9 @ we think we have handled things + ret r3 @ we think we have handled things look_for_VFP_exceptions: @@ -210,7 +210,7 @@ skip: process_exception: DBGSTR "bounce" mov r2, sp @ nothing stacked - regdump is at TOS - mov lr, r9 @ setup for a return to the user code. + mov lr, r3 @ setup for a return to the user code. @ Now call the C code to package up the bounce to the support code @ r0 holds the trigger instruction -- cgit v1.2.3 From c76c6c4ecbec0deb56a4f9e932b26866024a508f Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 12 Apr 2023 09:50:20 +0100 Subject: ARM: 9294/2: vfp: Fix broken softirq handling with instrumentation enabled Commit 62b95a7b44d1 ("ARM: 9282/1: vfp: Manipulate task VFP state with softirqs disabled") replaced the en/disable preemption calls inside the VFP state handling code with en/disabling of soft IRQs, which is necessary to allow kernel use of the VFP/SIMD unit when handling a soft IRQ. Unfortunately, when lockdep is enabled (or other instrumentation that enables TRACE_IRQFLAGS), the disable path implemented in asm fails to perform the lockdep and RCU related bookkeeping, resulting in spurious warnings and other badness. Set let's rework the VFP entry code a little bit so we can make the local_bh_disable() call from C, with all the instrumentations that happen to have been configured. Calling local_bh_enable() can be done from asm, as it is a simple wrapper around __local_bh_enable_ip(), which is always a callable function. Link: https://lore.kernel.org/all/ZBBYCSZUJOWBg1s8@localhost.localdomain/ Fixes: 62b95a7b44d1 ("ARM: 9282/1: vfp: Manipulate task VFP state with softirqs disabled") Signed-off-by: Ard Biesheuvel Reviewed-by: Linus Walleij Tested-by: Guenter Roeck Signed-off-by: Russell King (Oracle) --- arch/arm/include/asm/assembler.h | 13 ------------- arch/arm/vfp/entry.S | 11 +---------- arch/arm/vfp/vfphw.S | 12 ++++++------ arch/arm/vfp/vfpmodule.c | 27 ++++++++++++++++++++++----- 4 files changed, 29 insertions(+), 34 deletions(-) (limited to 'arch/arm') diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 06b48ce23e1c..505a306e0271 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -244,19 +244,6 @@ THUMB( fpreg .req r7 ) .endm #endif - .macro local_bh_disable, ti, tmp - ldr \tmp, [\ti, #TI_PREEMPT] - add \tmp, \tmp, #SOFTIRQ_DISABLE_OFFSET - str \tmp, [\ti, #TI_PREEMPT] - .endm - - .macro local_bh_enable_ti, ti, tmp - get_thread_info \ti - ldr \tmp, [\ti, #TI_PREEMPT] - sub \tmp, \tmp, #SOFTIRQ_DISABLE_OFFSET - str \tmp, [\ti, #TI_PREEMPT] - .endm - #define USERL(l, x...) \ 9999: x; \ .pushsection __ex_table,"a"; \ diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S index 6dabb4761778..7483ef8bccda 100644 --- a/arch/arm/vfp/entry.S +++ b/arch/arm/vfp/entry.S @@ -24,14 +24,5 @@ ENTRY(do_vfp) mov r1, r10 mov r3, r9 - ldr r4, .LCvfp - ldr pc, [r4] @ call VFP entry point + b vfp_entry ENDPROC(do_vfp) - -ENTRY(vfp_null_entry) - ret lr -ENDPROC(vfp_null_entry) - - .align 2 -.LCvfp: - .word vfp_vector diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S index 60acd42e0578..4d8478264d82 100644 --- a/arch/arm/vfp/vfphw.S +++ b/arch/arm/vfp/vfphw.S @@ -75,8 +75,6 @@ @ lr = unrecognised instruction return address @ IRQs enabled. ENTRY(vfp_support_entry) - local_bh_disable r1, r4 - ldr r11, [r1, #TI_CPU] @ CPU number add r10, r1, #TI_VFPSTATE @ r10 = workspace @@ -179,9 +177,12 @@ vfp_hw_state_valid: @ else it's one 32-bit instruction, so @ always subtract 4 from the following @ instruction address. - local_bh_enable_ti r10, r4 - ret r3 @ we think we have handled things + mov lr, r3 @ we think we have handled things +local_bh_enable_and_ret: + adr r0, . + mov r1, #SOFTIRQ_DISABLE_OFFSET + b __local_bh_enable_ip @ tail call look_for_VFP_exceptions: @ Check for synchronous or asynchronous exception @@ -204,8 +205,7 @@ skip: @ not recognised by VFP DBGSTR "not VFP" - local_bh_enable_ti r10, r4 - ret lr + b local_bh_enable_and_ret process_exception: DBGSTR "bounce" diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c index 01bc48d73847..349dcb944a93 100644 --- a/arch/arm/vfp/vfpmodule.c +++ b/arch/arm/vfp/vfpmodule.c @@ -32,10 +32,9 @@ /* * Our undef handlers (in entry.S) */ -asmlinkage void vfp_support_entry(void); -asmlinkage void vfp_null_entry(void); +asmlinkage void vfp_support_entry(u32, void *, u32, u32); -asmlinkage void (*vfp_vector)(void) = vfp_null_entry; +static bool have_vfp __ro_after_init; /* * Dual-use variable. @@ -645,6 +644,25 @@ static int vfp_starting_cpu(unsigned int unused) return 0; } +/* + * Entered with: + * + * r0 = instruction opcode (32-bit ARM or two 16-bit Thumb) + * r1 = thread_info pointer + * r2 = PC value to resume execution after successful emulation + * r3 = normal "successful" return address + * lr = unrecognised instruction return address + */ +asmlinkage void vfp_entry(u32 trigger, struct thread_info *ti, u32 resume_pc, + u32 resume_return_address) +{ + if (unlikely(!have_vfp)) + return; + + local_bh_disable(); + vfp_support_entry(trigger, ti, resume_pc, resume_return_address); +} + #ifdef CONFIG_KERNEL_MODE_NEON static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr) @@ -798,7 +816,6 @@ static int __init vfp_init(void) vfpsid = fmrx(FPSID); barrier(); unregister_undef_hook(&vfp_detect_hook); - vfp_vector = vfp_null_entry; pr_info("VFP support v0.3: "); if (VFP_arch) { @@ -883,7 +900,7 @@ static int __init vfp_init(void) "arm/vfp:starting", vfp_starting_cpu, vfp_dying_cpu); - vfp_vector = vfp_support_entry; + have_vfp = true; thread_register_notifier(&vfp_notifier_block); vfp_pm_init(); -- cgit v1.2.3