@@ -641,22 +641,47 @@ static int vfp_starting_cpu(unsigned int unused)
641
641
return 0 ;
642
642
}
643
643
644
+ static int vfp_kmode_exception (struct pt_regs * regs , unsigned int instr )
645
+ {
646
+ /*
647
+ * If we reach this point, a floating point exception has been raised
648
+ * while running in kernel mode. If the NEON/VFP unit was enabled at the
649
+ * time, it means a VFP instruction has been issued that requires
650
+ * software assistance to complete, something which is not currently
651
+ * supported in kernel mode.
652
+ * If the NEON/VFP unit was disabled, and the location pointed to below
653
+ * is properly preceded by a call to kernel_neon_begin(), something has
654
+ * caused the task to be scheduled out and back in again. In this case,
655
+ * rebuilding and running with CONFIG_DEBUG_ATOMIC_SLEEP enabled should
656
+ * be helpful in localizing the problem.
657
+ */
658
+ if (fmrx (FPEXC ) & FPEXC_EN )
659
+ pr_crit ("BUG: unsupported FP instruction in kernel mode\n" );
660
+ else
661
+ pr_crit ("BUG: FP instruction issued in kernel mode with FP unit disabled\n" );
662
+ pr_crit ("FPEXC == 0x%08x\n" , fmrx (FPEXC ));
663
+ return 1 ;
664
+ }
665
+
644
666
/*
645
- * vfp_support_entry - Handle VFP exception from user mode
667
+ * vfp_support_entry - Handle VFP exception
646
668
*
647
669
* @regs: pt_regs structure holding the register state at exception entry
648
670
* @trigger: The opcode of the instruction that triggered the exception
649
671
*
650
672
* Returns 0 if the exception was handled, or an error code otherwise.
651
673
*/
652
- asmlinkage int vfp_support_entry (struct pt_regs * regs , u32 trigger )
674
+ static int vfp_support_entry (struct pt_regs * regs , u32 trigger )
653
675
{
654
676
struct thread_info * ti = current_thread_info ();
655
677
u32 fpexc ;
656
678
657
679
if (unlikely (!have_vfp ))
658
680
return - ENODEV ;
659
681
682
+ if (!user_mode (regs ))
683
+ return vfp_kmode_exception (regs , trigger );
684
+
660
685
local_bh_disable ();
661
686
fpexc = fmrx (FPEXC );
662
687
@@ -722,7 +747,6 @@ asmlinkage int vfp_support_entry(struct pt_regs *regs, u32 trigger)
722
747
* replay the instruction that trapped.
723
748
*/
724
749
fmxr (FPEXC , fpexc );
725
- regs -> ARM_pc -= 4 ;
726
750
} else {
727
751
/* Check for synchronous or asynchronous exceptions */
728
752
if (!(fpexc & (FPEXC_EX | FPEXC_DEX ))) {
@@ -743,78 +767,47 @@ asmlinkage int vfp_support_entry(struct pt_regs *regs, u32 trigger)
743
767
fpexc |= FPEXC_DEX ;
744
768
}
745
769
}
746
- bounce : VFP_bounce (trigger , fpexc , regs );
770
+ bounce : regs -> ARM_pc += 4 ;
771
+ VFP_bounce (trigger , fpexc , regs );
747
772
}
748
773
749
774
local_bh_enable ();
750
775
return 0 ;
751
776
}
752
777
753
- #ifdef CONFIG_KERNEL_MODE_NEON
754
-
755
- static int vfp_kmode_exception (struct pt_regs * regs , unsigned int instr )
756
- {
757
- /*
758
- * If we reach this point, a floating point exception has been raised
759
- * while running in kernel mode. If the NEON/VFP unit was enabled at the
760
- * time, it means a VFP instruction has been issued that requires
761
- * software assistance to complete, something which is not currently
762
- * supported in kernel mode.
763
- * If the NEON/VFP unit was disabled, and the location pointed to below
764
- * is properly preceded by a call to kernel_neon_begin(), something has
765
- * caused the task to be scheduled out and back in again. In this case,
766
- * rebuilding and running with CONFIG_DEBUG_ATOMIC_SLEEP enabled should
767
- * be helpful in localizing the problem.
768
- */
769
- if (fmrx (FPEXC ) & FPEXC_EN )
770
- pr_crit ("BUG: unsupported FP instruction in kernel mode\n" );
771
- else
772
- pr_crit ("BUG: FP instruction issued in kernel mode with FP unit disabled\n" );
773
- pr_crit ("FPEXC == 0x%08x\n" , fmrx (FPEXC ));
774
- return 1 ;
775
- }
776
-
777
- static struct undef_hook vfp_kmode_exception_hook [] = {{
778
+ static struct undef_hook neon_support_hook [] = {{
778
779
.instr_mask = 0xfe000000 ,
779
780
.instr_val = 0xf2000000 ,
780
- .cpsr_mask = MODE_MASK | PSR_T_BIT ,
781
- .cpsr_val = SVC_MODE ,
782
- .fn = vfp_kmode_exception ,
781
+ .cpsr_mask = PSR_T_BIT ,
782
+ .cpsr_val = 0 ,
783
+ .fn = vfp_support_entry ,
783
784
}, {
784
785
.instr_mask = 0xff100000 ,
785
786
.instr_val = 0xf4000000 ,
786
- .cpsr_mask = MODE_MASK | PSR_T_BIT ,
787
- .cpsr_val = SVC_MODE ,
788
- .fn = vfp_kmode_exception ,
787
+ .cpsr_mask = PSR_T_BIT ,
788
+ .cpsr_val = 0 ,
789
+ .fn = vfp_support_entry ,
789
790
}, {
790
791
.instr_mask = 0xef000000 ,
791
792
.instr_val = 0xef000000 ,
792
- .cpsr_mask = MODE_MASK | PSR_T_BIT ,
793
- .cpsr_val = SVC_MODE | PSR_T_BIT ,
794
- .fn = vfp_kmode_exception ,
793
+ .cpsr_mask = PSR_T_BIT ,
794
+ .cpsr_val = PSR_T_BIT ,
795
+ .fn = vfp_support_entry ,
795
796
}, {
796
797
.instr_mask = 0xff100000 ,
797
798
.instr_val = 0xf9000000 ,
798
- .cpsr_mask = MODE_MASK | PSR_T_BIT ,
799
- .cpsr_val = SVC_MODE | PSR_T_BIT ,
800
- .fn = vfp_kmode_exception ,
801
- }, {
802
- .instr_mask = 0x0c000e00 ,
803
- .instr_val = 0x0c000a00 ,
804
- .cpsr_mask = MODE_MASK ,
805
- .cpsr_val = SVC_MODE ,
806
- .fn = vfp_kmode_exception ,
799
+ .cpsr_mask = PSR_T_BIT ,
800
+ .cpsr_val = PSR_T_BIT ,
801
+ .fn = vfp_support_entry ,
807
802
}};
808
803
809
- static int __init vfp_kmode_exception_hook_init (void )
810
- {
811
- int i ;
804
+ static struct undef_hook vfp_support_hook = {
805
+ .instr_mask = 0x0c000e00 ,
806
+ .instr_val = 0x0c000a00 ,
807
+ .fn = vfp_support_entry ,
808
+ };
812
809
813
- for (i = 0 ; i < ARRAY_SIZE (vfp_kmode_exception_hook ); i ++ )
814
- register_undef_hook (& vfp_kmode_exception_hook [i ]);
815
- return 0 ;
816
- }
817
- subsys_initcall (vfp_kmode_exception_hook_init );
810
+ #ifdef CONFIG_KERNEL_MODE_NEON
818
811
819
812
/*
820
813
* Kernel-side NEON support functions
@@ -919,8 +912,11 @@ static int __init vfp_init(void)
919
912
* for NEON if the hardware has the MVFR registers.
920
913
*/
921
914
if (IS_ENABLED (CONFIG_NEON ) &&
922
- (fmrx (MVFR1 ) & 0x000fff00 ) == 0x00011100 )
915
+ (fmrx (MVFR1 ) & 0x000fff00 ) == 0x00011100 ) {
923
916
elf_hwcap |= HWCAP_NEON ;
917
+ for (int i = 0 ; i < ARRAY_SIZE (neon_support_hook ); i ++ )
918
+ register_undef_hook (& neon_support_hook [i ]);
919
+ }
924
920
925
921
if (IS_ENABLED (CONFIG_VFPv3 )) {
926
922
u32 mvfr0 = fmrx (MVFR0 );
@@ -989,6 +985,7 @@ static int __init vfp_init(void)
989
985
990
986
have_vfp = true;
991
987
988
+ register_undef_hook (& vfp_support_hook );
992
989
thread_register_notifier (& vfp_notifier_block );
993
990
vfp_pm_init ();
994
991
0 commit comments