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";