diff options
| author | Maciej W. Rozycki <macro@linux-mips.org> | 2015-04-03 18:27:10 -0400 |
|---|---|---|
| committer | Ralf Baechle <ralf@linux-mips.org> | 2015-04-07 19:10:17 -0400 |
| commit | 443c44032a54f9acf027a8e688380fddc809bc19 (patch) | |
| tree | 482d477dc139c712bec7f79212408c46e5e79409 /arch/mips/kernel | |
| parent | ed2d72c1eb3643b7c109bdf387563d9b9a30c279 (diff) | |
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.c | 6 | ||||
| -rw-r--r-- | arch/mips/kernel/traps.c | 15 |
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: | |||
| 1170 | &fault_addr); | 1170 | &fault_addr); |
| 1171 | 1171 | ||
| 1172 | /* | 1172 | /* |
| 1173 | * We can't allow the emulated instruction to leave any of | ||
| 1174 | * the cause bits set in $fcr31. | ||
| 1175 | */ | ||
| 1176 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; | ||
| 1177 | |||
| 1178 | /* | ||
| 1173 | * this is a tricky issue - lose_fpu() uses LL/SC atomics | 1179 | * this is a tricky issue - lose_fpu() uses LL/SC atomics |
| 1174 | * if FPU is owned and effectively cancels user level LL/SC. | 1180 | * if FPU is owned and effectively cancels user level LL/SC. |
| 1175 | * So, it could be logical to don't restore FPU ownership here. | 1181 | * 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, | |||
| 761 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, | 761 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, |
| 762 | &fault_addr); | 762 | &fault_addr); |
| 763 | 763 | ||
| 764 | /* | ||
| 765 | * We can't allow the emulated instruction to leave any of | ||
| 766 | * the cause bits set in $fcr31. | ||
| 767 | */ | ||
| 768 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; | ||
| 769 | |||
| 764 | /* If something went wrong, signal */ | 770 | /* If something went wrong, signal */ |
| 765 | process_fpemu_return(sig, fault_addr); | 771 | process_fpemu_return(sig, fault_addr); |
| 766 | 772 | ||
| @@ -807,7 +813,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
| 807 | 813 | ||
| 808 | /* | 814 | /* |
| 809 | * We can't allow the emulated instruction to leave any of | 815 | * We can't allow the emulated instruction to leave any of |
| 810 | * the cause bit set in $fcr31. | 816 | * the cause bits set in $fcr31. |
| 811 | */ | 817 | */ |
| 812 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; | 818 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; |
| 813 | 819 | ||
| @@ -1384,6 +1390,13 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
| 1384 | sig = fpu_emulator_cop1Handler(regs, | 1390 | sig = fpu_emulator_cop1Handler(regs, |
| 1385 | ¤t->thread.fpu, | 1391 | ¤t->thread.fpu, |
| 1386 | 0, &fault_addr); | 1392 | 0, &fault_addr); |
| 1393 | |||
| 1394 | /* | ||
| 1395 | * We can't allow the emulated instruction to leave | ||
| 1396 | * any of the cause bits set in $fcr31. | ||
| 1397 | */ | ||
| 1398 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; | ||
| 1399 | |||
| 1387 | if (!process_fpemu_return(sig, fault_addr) && !err) | 1400 | if (!process_fpemu_return(sig, fault_addr) && !err) |
| 1388 | mt_ase_fp_affinity(); | 1401 | mt_ase_fp_affinity(); |
| 1389 | } | 1402 | } |
