Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/powerpc/powerpc Add SIGFPE handling code. Report t...



details:   https://anonhg.NetBSD.org/src/rev/fad7c4f0551d
branches:  trunk
changeset: 565343:fad7c4f0551d
user:      matt <matt%NetBSD.org@localhost>
date:      Sun Apr 04 19:21:36 2004 +0000

description:
Add SIGFPE handling code.  Report the proper SIGINFO ksi_code when a SIGFPE
happens.  When a SIGFPE occurs, disable the exception enables in the FPSCR.

diffstat:

 sys/arch/powerpc/powerpc/fpu.c  |  76 +++++++++++++++++++++++++++++++++++++++-
 sys/arch/powerpc/powerpc/trap.c |   6 +-
 2 files changed, 76 insertions(+), 6 deletions(-)

diffs (142 lines):

diff -r 4a1a3107b5c4 -r fad7c4f0551d sys/arch/powerpc/powerpc/fpu.c
--- a/sys/arch/powerpc/powerpc/fpu.c    Sun Apr 04 18:54:01 2004 +0000
+++ b/sys/arch/powerpc/powerpc/fpu.c    Sun Apr 04 19:21:36 2004 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: fpu.c,v 1.12 2004/04/04 17:35:15 matt Exp $    */
+/*     $NetBSD: fpu.c,v 1.13 2004/04/04 19:21:36 matt Exp $    */
 
 /*
  * Copyright (C) 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.12 2004/04/04 17:35:15 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.13 2004/04/04 19:21:36 matt Exp $");
 
 #include "opt_multiprocessor.h"
 
@@ -40,6 +40,7 @@
 #include <sys/proc.h>
 #include <sys/systm.h>
 #include <sys/user.h>
+#include <sys/siginfo.h>
 
 #include <machine/fpu.h>
 #include <machine/psl.h>
@@ -58,6 +59,13 @@
                memset(&pcb->pcb_fpu, 0, sizeof pcb->pcb_fpu);
                pcb->pcb_flags |= PCB_FPU;
        }
+       /*
+        * If we own the CPU but FP is disabled, simple enable it and return.
+        */
+       if (ci->ci_fpulwp == l) {
+               tf->srr1 |= PSL_FP | (pcb->pcb_flags & (PCB_FE0|PCB_FE1));
+               return;
+       }
        msr = mfmsr();
         mtmsr((msr & ~PSL_EE) | PSL_FP);
        __asm __volatile ("isync");
@@ -104,7 +112,7 @@
                "lfd    31,248(%0)\n"
            :: "b"(&pcb->pcb_fpu.fpr[0]));
        __asm __volatile ("isync");
-       tf->srr1 |= PSL_FP;
+       tf->srr1 |= PSL_FP | (pcb->pcb_flags & (PCB_FE0|PCB_FE1));
        ci->ci_fpulwp = l;
        pcb->pcb_fpcpu = ci;
        __asm __volatile ("sync");
@@ -216,3 +224,65 @@
        mp_save_fpu_lwp(l);
 #endif
 }
+
+#define        STICKYBITS      (FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX|FPSCR_XX)
+#if STICKYBITS & (PCB_FE0|PCB_FE1|PCB_VEC|PCB_FPU)
+#error PCB flags overlap FPSCR STICKYBITS
+#endif
+
+int
+get_fpu_fault_code(void)
+{
+#ifdef DIAGNOSTIC
+       struct cpu_info *ci = curcpu();
+#endif
+       struct lwp *l = curlwp;
+       struct pcb *pcb = &l->l_addr->u_pcb;
+       register_t msr;
+       uint64_t tmp;
+       uint32_t fpscr;
+       int code;
+
+       KASSERT(pcb->pcb_fpcpu == ci);
+       KASSERT(pcb->pcb_flags & PCB_FPU);
+       KASSERT(ci->ci_fpulwp == l);
+       msr = mfmsr();
+        mtmsr((msr & ~PSL_EE) | PSL_FP);
+       __asm __volatile ("isync");
+       __asm __volatile (
+               "stfd   0,0(%0)\n"      /* save f0 */
+               "mtfsb0 0\n"            /* clear FPSCR_FX */
+               "mtfsb0 24\n"           /* clear FPSCR_VE */
+               "mtfsb0 25\n"           /* clear FPSCR_OE */
+               "mtfsb0 26\n"           /* clear FPSCR_UE */
+               "mtfsb0 27\n"           /* clear FPSCR_ZE */
+               "mtfsb0 28\n"           /* clear FPSCR_XE */
+               "mffs   0\n"            /* get FPSCR */
+               "stfd   0,0(%1)\n"      /* store it */
+               "lfd    0,0(%0)\n"      /* restore f0 */
+           :: "b"(&tmp), "b"(&pcb->pcb_fpu.fpscr));
+        mtmsr(msr);
+       __asm __volatile ("isync");
+       /*
+        * Now determine the fault type.  First we see if any of the sticky
+        * bits have changed since the FP exception.  If so, we only want
+        * to return the code for the new exception.  If not, we look at all
+        * the bits.
+        */
+       fpscr = (uint32_t)(*(uint64_t *)&pcb->pcb_fpu.fpscr);
+       if ((fpscr & ~pcb->pcb_flags) & STICKYBITS)
+               fpscr &= ~pcb->pcb_flags;
+       if (fpscr & FPSCR_VX)           code = FPE_FLTINV;
+       else if (fpscr & FPSCR_OX)      code = FPE_FLTOVF;
+       else if (fpscr & FPSCR_UX)      code = FPE_FLTUND;
+       else if (fpscr & FPSCR_ZX)      code = FPE_FLTDIV;
+       else if (fpscr & FPSCR_XX)      code = FPE_FLTRES;
+       else                            code = 0;
+       /*
+        * Now we save the latest set of sticky bits.  This is so we can see
+        * what's changed on the next SIGFPE.
+        */
+       pcb->pcb_flags &= ~STICKYBITS;
+       pcb->pcb_flags |= fpscr & STICKYBITS;
+       return code;
+}
diff -r 4a1a3107b5c4 -r fad7c4f0551d sys/arch/powerpc/powerpc/trap.c
--- a/sys/arch/powerpc/powerpc/trap.c   Sun Apr 04 18:54:01 2004 +0000
+++ b/sys/arch/powerpc/powerpc/trap.c   Sun Apr 04 19:21:36 2004 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: trap.c,v 1.99 2004/03/25 18:50:50 matt Exp $   */
+/*     $NetBSD: trap.c,v 1.100 2004/04/04 19:21:36 matt Exp $  */
 
 /*
  * Copyright (C) 1995, 1996 Wolfgang Solfrank.
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.99 2004/03/25 18:50:50 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.100 2004/04/04 19:21:36 matt Exp $");
 
 #include "opt_altivec.h"
 #include "opt_ddb.h"
@@ -459,7 +459,7 @@
                        ksi.ksi_addr = (void *)frame->srr0;
                        if (frame->srr1 & 0x100000) {
                                ksi.ksi_signo = SIGFPE;
-                               ksi.ksi_code = 0;
+                               ksi.ksi_code = get_fpu_fault_code();
                        } else if (frame->srr1 & 0x40000) {
                                ksi.ksi_code = ILL_PRVOPC;
                        } else



Home | Main Index | Thread Index | Old Index