powerpc: fix e500 SPE float SIGFPE generation
authorJoseph Myers <joseph@codesourcery.com>
Mon, 4 Nov 2013 16:55:05 +0000 (16:55 +0000)
committerScott Wood <scottwood@freescale.com>
Wed, 8 Jan 2014 00:43:42 +0000 (18:43 -0600)
The e500 SPE floating-point emulation code is called from
SPEFloatingPointException and SPEFloatingPointRoundException in
arch/powerpc/kernel/traps.c.  Those functions have support for
generating SIGFPE, but do_spe_mathemu and speround_handler don't
generate a return value to indicate that this should be done.  Such a
return value should depend on whether an exception is raised that has
been set via prctl to generate SIGFPE.  This patch adds the relevant
logic in these functions so that SIGFPE is generated as expected by
the glibc testsuite.

Signed-off-by: Joseph Myers <joseph@codesourcery.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
arch/powerpc/math-emu/math_efp.c

index 01a0abb94dd61b21bcd0c39b5ee1ef68c723b107..28337c9709ae60c326bbe9e67364b9fe3c19796e 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/prctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/reg.h>
@@ -691,6 +692,23 @@ update_regs:
        pr_debug("va: %08x  %08x\n", va.wp[0], va.wp[1]);
        pr_debug("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
 
+       if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) {
+               if ((FP_CUR_EXCEPTIONS & FP_EX_DIVZERO)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_DIV))
+                       return 1;
+               if ((FP_CUR_EXCEPTIONS & FP_EX_OVERFLOW)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_OVF))
+                       return 1;
+               if ((FP_CUR_EXCEPTIONS & FP_EX_UNDERFLOW)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_UND))
+                       return 1;
+               if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_RES))
+                       return 1;
+               if ((FP_CUR_EXCEPTIONS & FP_EX_INVALID)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_INV))
+                       return 1;
+       }
        return 0;
 
 illegal:
@@ -867,6 +885,8 @@ int speround_handler(struct pt_regs *regs)
 
        pr_debug("  to fgpr: %08x  %08x\n", fgpr.wp[0], fgpr.wp[1]);
 
+       if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE)
+               return (current->thread.fpexc_mode & PR_FP_EXC_RES) ? 1 : 0;
        return 0;
 }