[PATCH] ARM: vfp: use undef hook for VFP support detection

Ard Biesheuvel ardb at kernel.org
Fri Dec 18 11:34:31 EST 2020


On Fri, 18 Dec 2020 at 16:54, Ard Biesheuvel <ardb at kernel.org> wrote:
>
> 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.
>
> Reported-by: "kernelci.org bot" <bot at kernelci.org>
> Signed-off-by: Ard Biesheuvel <ardb at kernel.org>
> ---
>  arch/arm/vfp/entry.S     | 17 -----------------
>  arch/arm/vfp/vfpmodule.c | 23 +++++++++++++++++++----
>  2 files changed, 19 insertions(+), 21 deletions(-)
>
> diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
> index 0186cf9da890..27b0a1f27fbd 100644
> --- 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
> diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
> index c3b6451c18bd..285a1c7e7a3f 100644
> --- 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) = vfp_null_entry;
>   * Used in startup: set to non-zero if VFP checks fail
>   * After startup, holds VFP architecture
>   */
> -unsigned int VFP_arch;
> +static unsigned int VFP_arch;
>
>  /*
>   * The pointer to the vfpstate structure of the thread which currently
> @@ -707,7 +706,7 @@ static int __init vfp_kmode_exception_hook_init(void)
>                 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: ");
> --
> 2.17.1
>

Assuming this patch fixes the issue, and nobody minds, I will fold in
the below before dropping it into the patch system.

diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 285a1c7e7a3f..2cb355c1b5b7 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -42,7 +42,7 @@ asmlinkage void (*vfp_vector)(void) = vfp_null_entry;
  * Used in startup: set to non-zero if VFP checks fail
  * After startup, holds VFP architecture
  */
-static unsigned int VFP_arch;
+static unsigned int __initdata VFP_arch;

 /*
  * The pointer to the vfpstate structure of the thread which currently
@@ -436,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__);



More information about the linux-arm-kernel mailing list