summaryrefslogtreecommitdiff
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2015-04-04 01:27:10 +0300
committerRalf Baechle <ralf@linux-mips.org>2015-04-08 02:10:17 +0300
commit443c44032a54f9acf027a8e688380fddc809bc19 (patch)
tree482d477dc139c712bec7f79212408c46e5e79409 /arch/mips/kernel
parented2d72c1eb3643b7c109bdf387563d9b9a30c279 (diff)
downloadlinux-443c44032a54f9acf027a8e688380fddc809bc19.tar.xz
MIPS: Always clear FCSR cause bits after emulation
Clear any FCSR cause bits recorded in the saved FPU context after emulation in all cases rather than in `do_fpe' only, so that any unmasked IEEE 754 exception left from emulation does not cause a fatal kernel-mode FPE hardware exception with the CTC1 instruction used by the kernel to subsequently restore FCSR hardware from the saved FPU context. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9704/ 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.c6
-rw-r--r--arch/mips/kernel/traps.c15
2 files changed, 20 insertions, 1 deletions
diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c
index f1d1b42d1902..6633fa97d431 100644
--- a/arch/mips/kernel/mips-r2-to-r6-emul.c
+++ b/arch/mips/kernel/mips-r2-to-r6-emul.c
@@ -1170,6 +1170,12 @@ fpu_emul:
&fault_addr);
/*
+ * We can't allow the emulated instruction to leave any of
+ * the cause bits set in $fcr31.
+ */
+ current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+
+ /*
* this is a tricky issue - lose_fpu() uses LL/SC atomics
* if FPU is owned and effectively cancels user level LL/SC.
* So, it could be logical to don't restore FPU ownership here.
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index dbfa47cdc8c1..4a0552dbcf4a 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -761,6 +761,12 @@ static int simulate_fp(struct pt_regs *regs, unsigned int opcode,
sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
&fault_addr);
+ /*
+ * We can't allow the emulated instruction to leave any of
+ * the cause bits set in $fcr31.
+ */
+ current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+
/* If something went wrong, signal */
process_fpemu_return(sig, fault_addr);
@@ -807,7 +813,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
/*
* We can't allow the emulated instruction to leave any of
- * the cause bit set in $fcr31.
+ * the cause bits set in $fcr31.
*/
current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
@@ -1384,6 +1390,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
sig = fpu_emulator_cop1Handler(regs,
&current->thread.fpu,
0, &fault_addr);
+
+ /*
+ * We can't allow the emulated instruction to leave
+ * any of the cause bits set in $fcr31.
+ */
+ current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X;
+
if (!process_fpemu_return(sig, fault_addr) && !err)
mt_ase_fp_affinity();
}