aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorMaciej W. Rozycki <macro@linux-mips.org>2015-04-03 23:27:06 +0100
committerRalf Baechle <ralf@linux-mips.org>2015-04-08 01:10:15 +0200
commited2d72c1eb3643b7c109bdf387563d9b9a30c279 (patch)
treecd0cc0203cef78f94b60770889f0e996a60387c6 /arch/mips/kernel
parentMIPS: math-emu: Move long fixed-point support into an `ar' library (diff)
downloadlinux-dev-ed2d72c1eb3643b7c109bdf387563d9b9a30c279.tar.xz
linux-dev-ed2d72c1eb3643b7c109bdf387563d9b9a30c279.zip
MIPS: Respect the FCSR exception mask for `si_code'
Respect the FCSR exception mask when interpreting the IEEE 754 exception condition to report with SIGFPE in `si_code', so as not to use one that has been masked where a different one set in parallel caused the FPE hardware exception to trigger. As per the IEEE Std 754 the Inexact exception can happen together with Overflow or Underflow. Signed-off-by: Maciej W. Rozycki <macro@linux-mips.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9703/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/traps.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 88f04f0d2d21..dbfa47cdc8c1 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -12,6 +12,7 @@
* Copyright (C) 2000, 2001, 2012 MIPS Technologies, Inc. All rights reserved.
* Copyright (C) 2014, Imagination Technologies Ltd.
*/
+#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/compiler.h>
#include <linux/context_tracking.h>
@@ -817,7 +818,15 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
process_fpemu_return(sig, fault_addr);
goto out;
- } else if (fcr31 & FPU_CSR_INV_X)
+ }
+
+ /*
+ * Inexact can happen together with Overflow or Underflow.
+ * Respect the mask to deliver the correct exception.
+ */
+ fcr31 &= (fcr31 & FPU_CSR_ALL_E) <<
+ (ffs(FPU_CSR_ALL_X) - ffs(FPU_CSR_ALL_E));
+ if (fcr31 & FPU_CSR_INV_X)
info.si_code = FPE_FLTINV;
else if (fcr31 & FPU_CSR_DIV_X)
info.si_code = FPE_FLTDIV;