aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2015-04-03 18:27:15 -0400
committerRalf Baechle <ralf@linux-mips.org>2015-04-07 19:10:19 -0400
commit304acb717e5b67cf56f05bc5b21123758e1f7ea0 (patch)
tree031d9969f99864c02701d9df056f92c894a56116 /arch/mips/kernel
parent443c44032a54f9acf027a8e688380fddc809bc19 (diff)
MIPS: Set `si_code' for SIGFPE signals sent from emulation too
Rework `process_fpemu_return' and move IEEE 754 exception interpretation there, from `do_fpe'. Record the cause bits set in FCSR before they are cleared and pass them through to `process_fpemu_return' so as to set `si_code' correctly too for SIGFPE signals sent from emulation rather than those issued by hardware with the FPE processor exception only. For simplicity `mipsr2_decoder' assumes `*fcr31' has been preinitialised and only sets it to anything if an FPU instruction has been emulated, which in turn is the only case SIGFPE can be issued for here. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9705/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/mips-r2-to-r6-emul.c4
-rw-r--r--arch/mips/kernel/traps.c150
-rw-r--r--arch/mips/kernel/unaligned.c4
3 files changed, 88 insertions, 70 deletions
diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c
index 6633fa97d431..f2977f00911b 100644
--- a/arch/mips/kernel/mips-r2-to-r6-emul.c
+++ b/arch/mips/kernel/mips-r2-to-r6-emul.c
@@ -898,8 +898,9 @@ static inline int mipsr2_find_op_func(struct pt_regs *regs, u32 inst,
898 * mipsr2_decoder: Decode and emulate a MIPS R2 instruction 898 * mipsr2_decoder: Decode and emulate a MIPS R2 instruction
899 * @regs: Process register set 899 * @regs: Process register set
900 * @inst: Instruction to decode and emulate 900 * @inst: Instruction to decode and emulate
901 * @fcr31: Floating Point Control and Status Register returned
901 */ 902 */
902int mipsr2_decoder(struct pt_regs *regs, u32 inst) 903int mipsr2_decoder(struct pt_regs *regs, u32 inst, unsigned long *fcr31)
903{ 904{
904 int err = 0; 905 int err = 0;
905 unsigned long vaddr; 906 unsigned long vaddr;
@@ -1168,6 +1169,7 @@ fpu_emul:
1168 1169
1169 err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0, 1170 err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
1170 &fault_addr); 1171 &fault_addr);
1172 *fcr31 = current->thread.fpu.fcr31;
1171 1173
1172 /* 1174 /*
1173 * We can't allow the emulated instruction to leave any of 1175 * We can't allow the emulated instruction to leave any of
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 4a0552dbcf4a..7d5532adc890 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -700,29 +700,60 @@ asmlinkage void do_ov(struct pt_regs *regs)
700 exception_exit(prev_state); 700 exception_exit(prev_state);
701} 701}
702 702
703int process_fpemu_return(int sig, void __user *fault_addr) 703int process_fpemu_return(int sig, void __user *fault_addr, unsigned long fcr31)
704{ 704{
705 if (sig == SIGSEGV || sig == SIGBUS) { 705 struct siginfo si = { 0 };
706 struct siginfo si = {0}; 706
707 switch (sig) {
708 case 0:
709 return 0;
710
711 case SIGFPE:
707 si.si_addr = fault_addr; 712 si.si_addr = fault_addr;
708 si.si_signo = sig; 713 si.si_signo = sig;
709 if (sig == SIGSEGV) { 714 /*
710 down_read(&current->mm->mmap_sem); 715 * Inexact can happen together with Overflow or Underflow.
711 if (find_vma(current->mm, (unsigned long)fault_addr)) 716 * Respect the mask to deliver the correct exception.
712 si.si_code = SEGV_ACCERR; 717 */
713 else 718 fcr31 &= (fcr31 & FPU_CSR_ALL_E) <<
714 si.si_code = SEGV_MAPERR; 719 (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E));
715 up_read(&current->mm->mmap_sem); 720 if (fcr31 & FPU_CSR_INV_X)
716 } else { 721 si.si_code = FPE_FLTINV;
717 si.si_code = BUS_ADRERR; 722 else if (fcr31 & FPU_CSR_DIV_X)
718 } 723 si.si_code = FPE_FLTDIV;
724 else if (fcr31 & FPU_CSR_OVF_X)
725 si.si_code = FPE_FLTOVF;
726 else if (fcr31 & FPU_CSR_UDF_X)
727 si.si_code = FPE_FLTUND;
728 else if (fcr31 & FPU_CSR_INE_X)
729 si.si_code = FPE_FLTRES;
730 else
731 si.si_code = __SI_FAULT;
719 force_sig_info(sig, &si, current); 732 force_sig_info(sig, &si, current);
720 return 1; 733 return 1;
721 } else if (sig) { 734
735 case SIGBUS:
736 si.si_addr = fault_addr;
737 si.si_signo = sig;
738 si.si_code = BUS_ADRERR;
739 force_sig_info(sig, &si, current);
740 return 1;
741
742 case SIGSEGV:
743 si.si_addr = fault_addr;
744 si.si_signo = sig;
745 down_read(&current->mm->mmap_sem);
746 if (find_vma(current->mm, (unsigned long)fault_addr))
747 si.si_code = SEGV_ACCERR;
748 else
749 si.si_code = SEGV_MAPERR;
750 up_read(&current->mm->mmap_sem);
751 force_sig_info(sig, &si, current);
752 return 1;
753
754 default:
722 force_sig(sig, current); 755 force_sig(sig, current);
723 return 1; 756 return 1;
724 } else {
725 return 0;
726 } 757 }
727} 758}
728 759
@@ -730,7 +761,8 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
730 unsigned long old_epc, unsigned long old_ra) 761 unsigned long old_epc, unsigned long old_ra)
731{ 762{
732 union mips_instruction inst = { .word = opcode }; 763 union mips_instruction inst = { .word = opcode };
733 void __user *fault_addr = NULL; 764 void __user *fault_addr;
765 unsigned long fcr31;
734 int sig; 766 int sig;
735 767
736 /* If it's obviously not an FP instruction, skip it */ 768 /* If it's obviously not an FP instruction, skip it */
@@ -760,6 +792,7 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
760 /* Run the emulator */ 792 /* Run the emulator */
761 sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1, 793 sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
762 &fault_addr); 794 &fault_addr);
795 fcr31 = current->thread.fpu.fcr31;
763 796
764 /* 797 /*
765 * We can't allow the emulated instruction to leave any of 798 * We can't allow the emulated instruction to leave any of
@@ -767,12 +800,12 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
767 */ 800 */
768 current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; 801 current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
769 802
770 /* If something went wrong, signal */
771 process_fpemu_return(sig, fault_addr);
772
773 /* Restore the hardware register state */ 803 /* Restore the hardware register state */
774 own_fpu(1); 804 own_fpu(1);
775 805
806 /* Send a signal if required. */
807 process_fpemu_return(sig, fault_addr, fcr31);
808
776 return 0; 809 return 0;
777} 810}
778 811
@@ -782,7 +815,8 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
782asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) 815asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
783{ 816{
784 enum ctx_state prev_state; 817 enum ctx_state prev_state;
785 siginfo_t info = {0}; 818 void __user *fault_addr;
819 int sig;
786 820
787 prev_state = exception_enter(); 821 prev_state = exception_enter();
788 if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), 822 if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs),
@@ -791,9 +825,6 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
791 die_if_kernel("FP exception in kernel code", regs); 825 die_if_kernel("FP exception in kernel code", regs);
792 826
793 if (fcr31 & FPU_CSR_UNI_X) { 827 if (fcr31 & FPU_CSR_UNI_X) {
794 int sig;
795 void __user *fault_addr = NULL;
796
797 /* 828 /*
798 * Unimplemented operation exception. If we've got the full 829 * Unimplemented operation exception. If we've got the full
799 * software emulator on-board, let's use it... 830 * software emulator on-board, let's use it...
@@ -810,6 +841,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
810 /* Run the emulator */ 841 /* Run the emulator */
811 sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1, 842 sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
812 &fault_addr); 843 &fault_addr);
844 fcr31 = current->thread.fpu.fcr31;
813 845
814 /* 846 /*
815 * We can't allow the emulated instruction to leave any of 847 * We can't allow the emulated instruction to leave any of
@@ -819,35 +851,13 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
819 851
820 /* Restore the hardware register state */ 852 /* Restore the hardware register state */
821 own_fpu(1); /* Using the FPU again. */ 853 own_fpu(1); /* Using the FPU again. */
822 854 } else {
823 /* If something went wrong, signal */ 855 sig = SIGFPE;
824 process_fpemu_return(sig, fault_addr); 856 fault_addr = (void __user *) regs->cp0_epc;
825
826 goto out;
827 } 857 }
828 858
829 /* 859 /* Send a signal if required. */
830 * Inexact can happen together with Overflow or Underflow. 860 process_fpemu_return(sig, fault_addr, fcr31);
831 * Respect the mask to deliver the correct exception.
832 */
833 fcr31 &= (fcr31 & FPU_CSR_ALL_E) <<
834 (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E));
835 if (fcr31 & FPU_CSR_INV_X)
836 info.si_code = FPE_FLTINV;
837 else if (fcr31 & FPU_CSR_DIV_X)
838 info.si_code = FPE_FLTDIV;
839 else if (fcr31 & FPU_CSR_OVF_X)
840 info.si_code = FPE_FLTOVF;
841 else if (fcr31 & FPU_CSR_UDF_X)
842 info.si_code = FPE_FLTUND;
843 else if (fcr31 & FPU_CSR_INE_X)
844 info.si_code = FPE_FLTRES;
845 else
846 info.si_code = __SI_FAULT;
847 info.si_signo = SIGFPE;
848 info.si_errno = 0;
849 info.si_addr = (void __user *) regs->cp0_epc;
850 force_sig_info(SIGFPE, &info, current);
851 861
852out: 862out:
853 exception_exit(prev_state); 863 exception_exit(prev_state);
@@ -1050,7 +1060,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
1050 if (mipsr2_emulation && cpu_has_mips_r6 && 1060 if (mipsr2_emulation && cpu_has_mips_r6 &&
1051 likely(user_mode(regs)) && 1061 likely(user_mode(regs)) &&
1052 likely(get_user(opcode, epc) >= 0)) { 1062 likely(get_user(opcode, epc) >= 0)) {
1053 status = mipsr2_decoder(regs, opcode); 1063 unsigned long fcr31 = 0;
1064
1065 status = mipsr2_decoder(regs, opcode, &fcr31);
1054 switch (status) { 1066 switch (status) {
1055 case 0: 1067 case 0:
1056 case SIGEMT: 1068 case SIGEMT:
@@ -1060,7 +1072,8 @@ asmlinkage void do_ri(struct pt_regs *regs)
1060 goto no_r2_instr; 1072 goto no_r2_instr;
1061 default: 1073 default:
1062 process_fpemu_return(status, 1074 process_fpemu_return(status,
1063 &current->thread.cp0_baduaddr); 1075 &current->thread.cp0_baduaddr,
1076 fcr31);
1064 task_thread_info(current)->r2_emul_return = 1; 1077 task_thread_info(current)->r2_emul_return = 1;
1065 return; 1078 return;
1066 } 1079 }
@@ -1307,10 +1320,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1307 enum ctx_state prev_state; 1320 enum ctx_state prev_state;
1308 unsigned int __user *epc; 1321 unsigned int __user *epc;
1309 unsigned long old_epc, old31; 1322 unsigned long old_epc, old31;
1323 void __user *fault_addr;
1310 unsigned int opcode; 1324 unsigned int opcode;
1325 unsigned long fcr31;
1311 unsigned int cpid; 1326 unsigned int cpid;
1312 int status, err; 1327 int status, err;
1313 unsigned long __maybe_unused flags; 1328 unsigned long __maybe_unused flags;
1329 int sig;
1314 1330
1315 prev_state = exception_enter(); 1331 prev_state = exception_enter();
1316 cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; 1332 cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
@@ -1384,22 +1400,22 @@ asmlinkage void do_cpu(struct pt_regs *regs)
1384 case 1: 1400 case 1:
1385 err = enable_restore_fp_context(0); 1401 err = enable_restore_fp_context(0);
1386 1402
1387 if (!raw_cpu_has_fpu || err) { 1403 if (raw_cpu_has_fpu && !err)
1388 int sig; 1404 break;
1389 void __user *fault_addr = NULL;
1390 sig = fpu_emulator_cop1Handler(regs,
1391 &current->thread.fpu,
1392 0, &fault_addr);
1393 1405
1394 /* 1406 sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
1395 * We can't allow the emulated instruction to leave 1407 &fault_addr);
1396 * any of the cause bits set in $fcr31. 1408 fcr31 = current->thread.fpu.fcr31;
1397 */
1398 current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
1399 1409
1400 if (!process_fpemu_return(sig, fault_addr) && !err) 1410 /*
1401 mt_ase_fp_affinity(); 1411 * We can't allow the emulated instruction to leave
1402 } 1412 * any of the cause bits set in $fcr31.
1413 */
1414 current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
1415
1416 /* Send a signal if required. */
1417 if (!process_fpemu_return(sig, fault_addr, fcr31) && !err)
1418 mt_ase_fp_affinity();
1403 1419
1404 break; 1420 break;
1405 1421
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index bbb69695a0a1..cf51ad36f213 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -1076,7 +1076,7 @@ static void emulate_load_store_insn(struct pt_regs *regs,
1076 own_fpu(1); /* Restore FPU state. */ 1076 own_fpu(1); /* Restore FPU state. */
1077 1077
1078 /* Signal if something went wrong. */ 1078 /* Signal if something went wrong. */
1079 process_fpemu_return(res, fault_addr); 1079 process_fpemu_return(res, fault_addr, 0);
1080 1080
1081 if (res == 0) 1081 if (res == 0)
1082 break; 1082 break;
@@ -1511,7 +1511,7 @@ fpu_emul:
1511 own_fpu(1); /* restore FPU state */ 1511 own_fpu(1); /* restore FPU state */
1512 1512
1513 /* If something went wrong, signal */ 1513 /* If something went wrong, signal */
1514 process_fpemu_return(res, fault_addr); 1514 process_fpemu_return(res, fault_addr, 0);
1515 1515
1516 if (res == 0) 1516 if (res == 0)
1517 goto success; 1517 goto success;