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@xxxxxxxxxxxxxx> --- linux-mips-fpe-emu-fcsr-cause.diff Index: linux/arch/mips/kernel/mips-r2-to-r6-emul.c =================================================================== --- linux.orig/arch/mips/kernel/mips-r2-to-r6-emul.c 2015-04-02 20:27:53.338178000 +0100 +++ linux/arch/mips/kernel/mips-r2-to-r6-emul.c 2015-04-02 20:27:58.241225000 +0100 @@ -1170,6 +1170,12 @@ int mipsr2_decoder(struct pt_regs *regs, &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. Index: linux/arch/mips/kernel/traps.c =================================================================== --- linux.orig/arch/mips/kernel/traps.c 2015-04-02 20:27:58.065226000 +0100 +++ linux/arch/mips/kernel/traps.c 2015-04-02 20:27:58.244233000 +0100 @@ -761,6 +761,12 @@ static int simulate_fp(struct pt_regs *r sig = fpu_emulator_cop1Handler(regs, ¤t->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 *r /* * 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 *r sig = fpu_emulator_cop1Handler(regs, ¤t->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(); }