--- /dev/null
+From foo@baz Sat Mar 20 12:03:58 PM CET 2021
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Mon, 15 Mar 2021 16:19:52 -0700
+Subject: ARM: 9030/1: entry: omit FP emulation for UND exceptions taken in kernel mode
+
+From: Ard Biesheuvel <ardb@kernel.org>
+
+commit f77ac2e378be9dd61eb88728f0840642f045d9d1 upstream.
+
+There are a couple of problems with the exception entry code that deals
+with FP exceptions (which are reported as UND exceptions) when building
+the kernel in Thumb2 mode:
+- the conditional branch to vfp_kmode_exception in vfp_support_entry()
+ may be out of range for its target, depending on how the linker decides
+ to arrange the sections;
+- when the UND exception is taken in kernel mode, the emulation handling
+ logic is entered via the 'call_fpe' label, which means we end up using
+ the wrong value/mask pairs to match and detect the NEON opcodes.
+
+Since UND exceptions in kernel mode are unlikely to occur on a hot path
+(as opposed to the user mode version which is invoked for VFP support
+code and lazy restore), we can use the existing undef hook machinery for
+any kernel mode instruction emulation that is needed, including calling
+the existing vfp_kmode_exception() routine for unexpected cases. So drop
+the call to call_fpe, and instead, install an undef hook that will get
+called for NEON and VFP instructions that trigger an UND exception in
+kernel mode.
+
+While at it, make sure that the PC correction is accurate for the
+execution mode where the exception was taken, by checking the PSR
+Thumb bit.
+
+[nd: fix conflict in arch/arm/vfp/vfphw.S due to missing
+ commit 2cbd1cc3dcd3 ("ARM: 8991/1: use VFP assembler mnemonics if
+ available")]
+
+Fixes: eff8728fe698 ("vmlinux.lds.h: Add PGO and AutoFDO input sections")
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
+Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
+Reviewed-by: Nick Desaulniers <ndesaulniers@google.com>
+Cc: Dmitry Osipenko <digetx@gmail.com>
+Cc: Kees Cook <keescook@chromium.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/kernel/entry-armv.S | 25 +--------------------
+ arch/arm/vfp/vfphw.S | 5 ----
+ arch/arm/vfp/vfpmodule.c | 49 +++++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 49 insertions(+), 30 deletions(-)
+
+--- a/arch/arm/kernel/entry-armv.S
++++ b/arch/arm/kernel/entry-armv.S
+@@ -252,31 +252,10 @@ __und_svc:
+ #else
+ svc_entry
+ #endif
+- @
+- @ call emulation code, which returns using r9 if it has emulated
+- @ the instruction, or the more conventional lr if we are to treat
+- @ this as a real undefined instruction
+- @
+- @ r0 - instruction
+- @
+-#ifndef CONFIG_THUMB2_KERNEL
+- ldr r0, [r4, #-4]
+-#else
+- mov r1, #2
+- ldrh r0, [r4, #-2] @ Thumb instruction at LR - 2
+- cmp r0, #0xe800 @ 32-bit instruction if xx >= 0
+- blo __und_svc_fault
+- ldrh r9, [r4] @ bottom 16 bits
+- add r4, r4, #2
+- str r4, [sp, #S_PC]
+- orr r0, r9, r0, lsl #16
+-#endif
+- badr r9, __und_svc_finish
+- mov r2, r4
+- bl call_fpe
+
+ mov r1, #4 @ PC correction to apply
+-__und_svc_fault:
++ THUMB( tst r5, #PSR_T_BIT ) @ exception taken in Thumb mode?
++ THUMB( movne r1, #2 ) @ if so, fix up PC correction
+ mov r0, sp @ struct pt_regs *regs
+ bl __und_fault
+
+--- a/arch/arm/vfp/vfphw.S
++++ b/arch/arm/vfp/vfphw.S
+@@ -78,11 +78,6 @@
+ ENTRY(vfp_support_entry)
+ DBGSTR3 "instr %08x pc %08x state %p", r0, r2, r10
+
+- ldr r3, [sp, #S_PSR] @ Neither lazy restore nor FP exceptions
+- and r3, r3, #MODE_MASK @ are supported in kernel mode
+- teq r3, #USR_MODE
+- bne vfp_kmode_exception @ Returns through lr
+-
+ VFPFMRX r1, FPEXC @ Is the VFP enabled?
+ DBGSTR1 "fpexc %08x", r1
+ tst r1, #FPEXC_EN
+--- a/arch/arm/vfp/vfpmodule.c
++++ b/arch/arm/vfp/vfpmodule.c
+@@ -23,6 +23,7 @@
+ #include <asm/cputype.h>
+ #include <asm/system_info.h>
+ #include <asm/thread_notify.h>
++#include <asm/traps.h>
+ #include <asm/vfp.h>
+
+ #include "vfpinstr.h"
+@@ -642,7 +643,9 @@ static int vfp_starting_cpu(unsigned int
+ return 0;
+ }
+
+-void vfp_kmode_exception(void)
++#ifdef CONFIG_KERNEL_MODE_NEON
++
++static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr)
+ {
+ /*
+ * If we reach this point, a floating point exception has been raised
+@@ -660,9 +663,51 @@ void vfp_kmode_exception(void)
+ pr_crit("BUG: unsupported FP instruction in kernel mode\n");
+ else
+ pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n");
++ pr_crit("FPEXC == 0x%08x\n", fmrx(FPEXC));
++ return 1;
+ }
+
+-#ifdef CONFIG_KERNEL_MODE_NEON
++static struct undef_hook vfp_kmode_exception_hook[] = {{
++ .instr_mask = 0xfe000000,
++ .instr_val = 0xf2000000,
++ .cpsr_mask = MODE_MASK | PSR_T_BIT,
++ .cpsr_val = SVC_MODE,
++ .fn = vfp_kmode_exception,
++}, {
++ .instr_mask = 0xff100000,
++ .instr_val = 0xf4000000,
++ .cpsr_mask = MODE_MASK | PSR_T_BIT,
++ .cpsr_val = SVC_MODE,
++ .fn = vfp_kmode_exception,
++}, {
++ .instr_mask = 0xef000000,
++ .instr_val = 0xef000000,
++ .cpsr_mask = MODE_MASK | PSR_T_BIT,
++ .cpsr_val = SVC_MODE | PSR_T_BIT,
++ .fn = vfp_kmode_exception,
++}, {
++ .instr_mask = 0xff100000,
++ .instr_val = 0xf9000000,
++ .cpsr_mask = MODE_MASK | PSR_T_BIT,
++ .cpsr_val = SVC_MODE | PSR_T_BIT,
++ .fn = vfp_kmode_exception,
++}, {
++ .instr_mask = 0x0c000e00,
++ .instr_val = 0x0c000a00,
++ .cpsr_mask = MODE_MASK,
++ .cpsr_val = SVC_MODE,
++ .fn = vfp_kmode_exception,
++}};
++
++static int __init vfp_kmode_exception_hook_init(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(vfp_kmode_exception_hook); i++)
++ register_undef_hook(&vfp_kmode_exception_hook[i]);
++ return 0;
++}
++core_initcall(vfp_kmode_exception_hook_init);
+
+ /*
+ * Kernel-side NEON support functions
--- /dev/null
+From foo@baz Sat Mar 20 12:03:58 PM CET 2021
+From: Ard Biesheuvel <ardb@kernel.org>
+Date: Tue, 16 Mar 2021 09:59:18 -0700
+Subject: ARM: 9044/1: vfp: use undef hook for VFP support detection
+
+From: Ard Biesheuvel <ardb@kernel.org>
+
+commit 3cce9d44321e460e7c88cdec4e4537a6e9ad7c0d upstream.
+
+Commit f77ac2e378be9dd6 ("ARM: 9030/1: entry: omit FP emulation for UND
+exceptions taken in kernel mode") failed to take into account that there
+is in fact a case where we relied on this code path: during boot, the
+VFP detection code issues a read of FPSID, which will trigger an undef
+exception on cores that lack VFP support.
+
+So let's reinstate this logic using an undef hook which is registered
+only for the duration of the initcall to vpf_init(), and which sets
+VFP_arch to a non-zero value - as before - if no VFP support is present.
+
+Fixes: f77ac2e378be9dd6 ("ARM: 9030/1: entry: omit FP emulation for UND ...")
+Reported-by: "kernelci.org bot" <bot@kernelci.org>
+Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/arm/vfp/entry.S | 17 -----------------
+ arch/arm/vfp/vfpmodule.c | 25 ++++++++++++++++++++-----
+ 2 files changed, 20 insertions(+), 22 deletions(-)
+
+--- a/arch/arm/vfp/entry.S
++++ b/arch/arm/vfp/entry.S
+@@ -37,20 +37,3 @@ ENDPROC(vfp_null_entry)
+ .align 2
+ .LCvfp:
+ .word vfp_vector
+-
+-@ This code is called if the VFP does not exist. It needs to flag the
+-@ failure to the VFP initialisation code.
+-
+- __INIT
+-ENTRY(vfp_testing_entry)
+- dec_preempt_count_ti r10, r4
+- ldr r0, VFP_arch_address
+- str r0, [r0] @ set to non-zero value
+- ret r9 @ we have handled the fault
+-ENDPROC(vfp_testing_entry)
+-
+- .align 2
+-VFP_arch_address:
+- .word VFP_arch
+-
+- __FINIT
+--- a/arch/arm/vfp/vfpmodule.c
++++ b/arch/arm/vfp/vfpmodule.c
+@@ -32,7 +32,6 @@
+ /*
+ * Our undef handlers (in entry.S)
+ */
+-asmlinkage void vfp_testing_entry(void);
+ asmlinkage void vfp_support_entry(void);
+ asmlinkage void vfp_null_entry(void);
+
+@@ -43,7 +42,7 @@ asmlinkage void (*vfp_vector)(void) = vf
+ * Used in startup: set to non-zero if VFP checks fail
+ * After startup, holds VFP architecture
+ */
+-unsigned int VFP_arch;
++static unsigned int __initdata VFP_arch;
+
+ /*
+ * The pointer to the vfpstate structure of the thread which currently
+@@ -437,7 +436,7 @@ static void vfp_enable(void *unused)
+ * present on all CPUs within a SMP complex. Needs to be called prior to
+ * vfp_init().
+ */
+-void vfp_disable(void)
++void __init vfp_disable(void)
+ {
+ if (VFP_arch) {
+ pr_debug("%s: should be called prior to vfp_init\n", __func__);
+@@ -707,7 +706,7 @@ static int __init vfp_kmode_exception_ho
+ register_undef_hook(&vfp_kmode_exception_hook[i]);
+ return 0;
+ }
+-core_initcall(vfp_kmode_exception_hook_init);
++subsys_initcall(vfp_kmode_exception_hook_init);
+
+ /*
+ * Kernel-side NEON support functions
+@@ -753,6 +752,21 @@ EXPORT_SYMBOL(kernel_neon_end);
+
+ #endif /* CONFIG_KERNEL_MODE_NEON */
+
++static int __init vfp_detect(struct pt_regs *regs, unsigned int instr)
++{
++ VFP_arch = UINT_MAX; /* mark as not present */
++ regs->ARM_pc += 4;
++ return 0;
++}
++
++static struct undef_hook vfp_detect_hook __initdata = {
++ .instr_mask = 0x0c000e00,
++ .instr_val = 0x0c000a00,
++ .cpsr_mask = MODE_MASK,
++ .cpsr_val = SVC_MODE,
++ .fn = vfp_detect,
++};
++
+ /*
+ * VFP support code initialisation.
+ */
+@@ -773,10 +787,11 @@ static int __init vfp_init(void)
+ * The handler is already setup to just log calls, so
+ * we just need to read the VFPSID register.
+ */
+- vfp_vector = vfp_testing_entry;
++ register_undef_hook(&vfp_detect_hook);
+ barrier();
+ vfpsid = fmrx(FPSID);
+ barrier();
++ unregister_undef_hook(&vfp_detect_hook);
+ vfp_vector = vfp_null_entry;
+
+ pr_info("VFP support v0.3: ");