浏览代码

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>
Maciej W. Rozycki 10 年之前
父节点
当前提交
443c44032a
共有 2 个文件被更改,包括 20 次插入1 次删除
  1. 6 0
      arch/mips/kernel/mips-r2-to-r6-emul.c
  2. 14 1
      arch/mips/kernel/traps.c

+ 6 - 0
arch/mips/kernel/mips-r2-to-r6-emul.c

@@ -1169,6 +1169,12 @@ fpu_emul:
 		err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
 		err = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 0,
 					       &fault_addr);
 					       &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
 		 * this is a tricky issue - lose_fpu() uses LL/SC atomics
 		 * if FPU is owned and effectively cancels user level LL/SC.
 		 * if FPU is owned and effectively cancels user level LL/SC.

+ 14 - 1
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,
 	sig = fpu_emulator_cop1Handler(regs, &current->thread.fpu, 1,
 				       &fault_addr);
 				       &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 */
 	/* If something went wrong, signal */
 	process_fpemu_return(sig, fault_addr);
 	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
 		 * 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;
 		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,
 			sig = fpu_emulator_cop1Handler(regs,
 						       &current->thread.fpu,
 						       &current->thread.fpu,
 						       0, &fault_addr);
 						       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)
 			if (!process_fpemu_return(sig, fault_addr) && !err)
 				mt_ase_fp_affinity();
 				mt_ase_fp_affinity();
 		}
 		}