Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: 9044/1: vfp: use undef hook for VFP support detection

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>

authored by

Ard Biesheuvel and committed by
Russell King
3cce9d44 f77ac2e3

+20 -22
-17
arch/arm/vfp/entry.S
··· 37 37 .align 2 38 38 .LCvfp: 39 39 .word vfp_vector 40 - 41 - @ This code is called if the VFP does not exist. It needs to flag the 42 - @ failure to the VFP initialisation code. 43 - 44 - __INIT 45 - ENTRY(vfp_testing_entry) 46 - dec_preempt_count_ti r10, r4 47 - ldr r0, VFP_arch_address 48 - str r0, [r0] @ set to non-zero value 49 - ret r9 @ we have handled the fault 50 - ENDPROC(vfp_testing_entry) 51 - 52 - .align 2 53 - VFP_arch_address: 54 - .word VFP_arch 55 - 56 - __FINIT
+20 -5
arch/arm/vfp/vfpmodule.c
··· 32 32 /* 33 33 * Our undef handlers (in entry.S) 34 34 */ 35 - asmlinkage void vfp_testing_entry(void); 36 35 asmlinkage void vfp_support_entry(void); 37 36 asmlinkage void vfp_null_entry(void); 38 37 ··· 42 43 * Used in startup: set to non-zero if VFP checks fail 43 44 * After startup, holds VFP architecture 44 45 */ 45 - unsigned int VFP_arch; 46 + static unsigned int __initdata VFP_arch; 46 47 47 48 /* 48 49 * The pointer to the vfpstate structure of the thread which currently ··· 436 437 * present on all CPUs within a SMP complex. Needs to be called prior to 437 438 * vfp_init(). 438 439 */ 439 - void vfp_disable(void) 440 + void __init vfp_disable(void) 440 441 { 441 442 if (VFP_arch) { 442 443 pr_debug("%s: should be called prior to vfp_init\n", __func__); ··· 706 707 register_undef_hook(&vfp_kmode_exception_hook[i]); 707 708 return 0; 708 709 } 709 - core_initcall(vfp_kmode_exception_hook_init); 710 + subsys_initcall(vfp_kmode_exception_hook_init); 710 711 711 712 /* 712 713 * Kernel-side NEON support functions ··· 752 753 753 754 #endif /* CONFIG_KERNEL_MODE_NEON */ 754 755 756 + static int __init vfp_detect(struct pt_regs *regs, unsigned int instr) 757 + { 758 + VFP_arch = UINT_MAX; /* mark as not present */ 759 + regs->ARM_pc += 4; 760 + return 0; 761 + } 762 + 763 + static struct undef_hook vfp_detect_hook __initdata = { 764 + .instr_mask = 0x0c000e00, 765 + .instr_val = 0x0c000a00, 766 + .cpsr_mask = MODE_MASK, 767 + .cpsr_val = SVC_MODE, 768 + .fn = vfp_detect, 769 + }; 770 + 755 771 /* 756 772 * VFP support code initialisation. 757 773 */ ··· 787 773 * The handler is already setup to just log calls, so 788 774 * we just need to read the VFPSID register. 789 775 */ 790 - vfp_vector = vfp_testing_entry; 776 + register_undef_hook(&vfp_detect_hook); 791 777 barrier(); 792 778 vfpsid = fmrx(FPSID); 793 779 barrier(); 780 + unregister_undef_hook(&vfp_detect_hook); 794 781 vfp_vector = vfp_null_entry; 795 782 796 783 pr_info("VFP support v0.3: ");