hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/arch/arm/vfp/vfpmodule.c
....@@ -1,12 +1,9 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * linux/arch/arm/vfp/vfpmodule.c
34 *
45 * Copyright (C) 2004 ARM Limited.
56 * Written by Deep Blue Solutions Limited.
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License version 2 as
9
- * published by the Free Software Foundation.
107 */
118 #include <linux/types.h>
129 #include <linux/cpu.h>
....@@ -26,6 +23,7 @@
2623 #include <asm/cputype.h>
2724 #include <asm/system_info.h>
2825 #include <asm/thread_notify.h>
26
+#include <asm/traps.h>
2927 #include <asm/vfp.h>
3028
3129 #include "vfpinstr.h"
....@@ -34,7 +32,6 @@
3432 /*
3533 * Our undef handlers (in entry.S)
3634 */
37
-asmlinkage void vfp_testing_entry(void);
3835 asmlinkage void vfp_support_entry(void);
3936 asmlinkage void vfp_null_entry(void);
4037
....@@ -45,7 +42,7 @@
4542 * Used in startup: set to non-zero if VFP checks fail
4643 * After startup, holds VFP architecture
4744 */
48
-unsigned int VFP_arch;
45
+static unsigned int __initdata VFP_arch;
4946
5047 /*
5148 * The pointer to the vfpstate structure of the thread which currently
....@@ -216,13 +213,6 @@
216213 */
217214 static void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
218215 {
219
- siginfo_t info;
220
-
221
- clear_siginfo(&info);
222
- info.si_signo = SIGFPE;
223
- info.si_code = sicode;
224
- info.si_addr = (void __user *)(instruction_pointer(regs) - 4);
225
-
226216 /*
227217 * This is the same as NWFPE, because it's not clear what
228218 * this is used for
....@@ -230,7 +220,9 @@
230220 current->thread.error_code = 0;
231221 current->thread.trap_no = 6;
232222
233
- send_sig_info(SIGFPE, &info, current);
223
+ send_sig_fault(SIGFPE, sicode,
224
+ (void __user *)(instruction_pointer(regs) - 4),
225
+ current);
234226 }
235227
236228 static void vfp_panic(char *reason, u32 inst)
....@@ -444,7 +436,7 @@
444436 * present on all CPUs within a SMP complex. Needs to be called prior to
445437 * vfp_init().
446438 */
447
-void vfp_disable(void)
439
+void __init vfp_disable(void)
448440 {
449441 if (VFP_arch) {
450442 pr_debug("%s: should be called prior to vfp_init\n", __func__);
....@@ -650,7 +642,9 @@
650642 return 0;
651643 }
652644
653
-void vfp_kmode_exception(void)
645
+#ifdef CONFIG_KERNEL_MODE_NEON
646
+
647
+static int vfp_kmode_exception(struct pt_regs *regs, unsigned int instr)
654648 {
655649 /*
656650 * If we reach this point, a floating point exception has been raised
....@@ -668,9 +662,51 @@
668662 pr_crit("BUG: unsupported FP instruction in kernel mode\n");
669663 else
670664 pr_crit("BUG: FP instruction issued in kernel mode with FP unit disabled\n");
665
+ pr_crit("FPEXC == 0x%08x\n", fmrx(FPEXC));
666
+ return 1;
671667 }
672668
673
-#ifdef CONFIG_KERNEL_MODE_NEON
669
+static struct undef_hook vfp_kmode_exception_hook[] = {{
670
+ .instr_mask = 0xfe000000,
671
+ .instr_val = 0xf2000000,
672
+ .cpsr_mask = MODE_MASK | PSR_T_BIT,
673
+ .cpsr_val = SVC_MODE,
674
+ .fn = vfp_kmode_exception,
675
+}, {
676
+ .instr_mask = 0xff100000,
677
+ .instr_val = 0xf4000000,
678
+ .cpsr_mask = MODE_MASK | PSR_T_BIT,
679
+ .cpsr_val = SVC_MODE,
680
+ .fn = vfp_kmode_exception,
681
+}, {
682
+ .instr_mask = 0xef000000,
683
+ .instr_val = 0xef000000,
684
+ .cpsr_mask = MODE_MASK | PSR_T_BIT,
685
+ .cpsr_val = SVC_MODE | PSR_T_BIT,
686
+ .fn = vfp_kmode_exception,
687
+}, {
688
+ .instr_mask = 0xff100000,
689
+ .instr_val = 0xf9000000,
690
+ .cpsr_mask = MODE_MASK | PSR_T_BIT,
691
+ .cpsr_val = SVC_MODE | PSR_T_BIT,
692
+ .fn = vfp_kmode_exception,
693
+}, {
694
+ .instr_mask = 0x0c000e00,
695
+ .instr_val = 0x0c000a00,
696
+ .cpsr_mask = MODE_MASK,
697
+ .cpsr_val = SVC_MODE,
698
+ .fn = vfp_kmode_exception,
699
+}};
700
+
701
+static int __init vfp_kmode_exception_hook_init(void)
702
+{
703
+ int i;
704
+
705
+ for (i = 0; i < ARRAY_SIZE(vfp_kmode_exception_hook); i++)
706
+ register_undef_hook(&vfp_kmode_exception_hook[i]);
707
+ return 0;
708
+}
709
+subsys_initcall(vfp_kmode_exception_hook_init);
674710
675711 /*
676712 * Kernel-side NEON support functions
....@@ -716,6 +752,21 @@
716752
717753 #endif /* CONFIG_KERNEL_MODE_NEON */
718754
755
+static int __init vfp_detect(struct pt_regs *regs, unsigned int instr)
756
+{
757
+ VFP_arch = UINT_MAX; /* mark as not present */
758
+ regs->ARM_pc += 4;
759
+ return 0;
760
+}
761
+
762
+static struct undef_hook vfp_detect_hook __initdata = {
763
+ .instr_mask = 0x0c000e00,
764
+ .instr_val = 0x0c000a00,
765
+ .cpsr_mask = MODE_MASK,
766
+ .cpsr_val = SVC_MODE,
767
+ .fn = vfp_detect,
768
+};
769
+
719770 /*
720771 * VFP support code initialisation.
721772 */
....@@ -736,10 +787,11 @@
736787 * The handler is already setup to just log calls, so
737788 * we just need to read the VFPSID register.
738789 */
739
- vfp_vector = vfp_testing_entry;
790
+ register_undef_hook(&vfp_detect_hook);
740791 barrier();
741792 vfpsid = fmrx(FPSID);
742793 barrier();
794
+ unregister_undef_hook(&vfp_detect_hook);
743795 vfp_vector = vfp_null_entry;
744796
745797 pr_info("VFP support v0.3: ");