I was attempting to port software which relies on SIGFPE to macppc
when I discovered that that floating point exceptions don't appear to
work at all there.

After researching powerpc a bit and digging around in the kernel, I
found that the two MSR bits which enable floating point exceptions,
FE0 and FE1, appear to be explicitly disabled during exec and never
enabled anywhere else.

I made a crude attempt to turn those bits on and deliver SIGFPE to
userland when appropriate, however all of userland appears to hang
when the first floating point exception occurs. Is there a more
fundamental, trickier reason that floating point exceptions aren't
enabled on any powerpc platform, or have I just made some trivial
mistake?

Any advice or pointers for where to dig around more carefully are
appreciated, thanks.

Index: arch/powerpc/powerpc/fpu.c
===================================================================
RCS file: /ruby/cvs/openbsd/src/sys/arch/powerpc/powerpc/fpu.c,v
retrieving revision 1.12
diff -u arch/powerpc/powerpc/fpu.c
--- arch/powerpc/powerpc/fpu.c  10 Dec 2009 16:46:09 -0000      1.12
+++ arch/powerpc/powerpc/fpu.c  12 May 2010 02:01:00 -0000
@@ -94,7 +94,7 @@
             "lfd 31,248(%0)" :: "b"(&pcb->pcb_fpu.fpr[0]));
        ci->ci_fpuproc = p;
        pcb->pcb_fpcpu = ci;
-       tf->srr1 |= PSL_FP;
+       tf->srr1 |= PSL_FP | PSL_FE_PREC;
        ppc_mtmsr(msr);
        __asm volatile("isync");
 }
Index: arch/powerpc/powerpc/trap.c
===================================================================
RCS file: /ruby/cvs/openbsd/src/sys/arch/powerpc/powerpc/trap.c,v
retrieving revision 1.83
diff -u arch/powerpc/powerpc/trap.c
--- arch/powerpc/powerpc/trap.c 14 Jun 2008 10:55:20 -0000      1.83
+++ arch/powerpc/powerpc/trap.c 12 May 2010 01:35:56 -0000
@@ -593,12 +593,38 @@
 #if 0
                char *errstr[8];
                int errnum = 0;
+#endif
 
                if (frame->srr1 & (1<<(31-11))) { 
+                       u_int64_t fpscr;
+                       int fpe;
+       
+#if 0
                        /* floating point enabled program exception */
                        errstr[errnum] = "floating point";
                        errnum++;
+#endif
+
+                       save_fpu();
+                       fpscr = *(u_int64_t *)&p->p_addr->u_pcb.pcb_fpu.fpcsr;
+                       fpe = 0;
+                       if ((fpscr & (FPCSR_VX|FPCSR_VE)) == 
(FPCSR_VX|FPCSR_VE))
+                               fpe = FPE_FLTINV;
+                       else if ((fpscr & (FPCSR_ZX|FPCSR_ZE)) == 
(FPCSR_ZX|FPCSR_ZE))
+                               fpe = FPE_FLTDIV;
+                       else if ((fpscr & (FPCSR_OX|FPCSR_OE)) == 
(FPCSR_OX|FPCSR_OE))
+                               fpe = FPE_FLTOVF;
+                       else if ((fpscr & (FPCSR_UX|FPCSR_UE)) == 
(FPCSR_UX|FPCSR_UE))
+                               fpe = FPE_FLTUND;
+                       else if ((fpscr & (FPCSR_XX|FPCSR_XE)) == 
(FPCSR_XX|FPCSR_XE))
+                               fpe = FPE_FLTRES;
+                       sv.sival_int = frame->srr0;
+                       KERNEL_PROC_LOCK(p);
+                       trapsignal(p, SIGFPE, type, fpe, sv);
+                       KERNEL_PROC_UNLOCK(p);
+                       break;
                } 
+#if 0
                if (frame->srr1 & (1<<(31-12))) {
                        /* illegal instruction program exception */
                        errstr[errnum] = "illegal instruction";

Reply via email to