When trying to figure out which code to return, use the exception enable

bits to mask out the undesired exceptions.  (Thanks to Todd Whitesel for
the idea).
This commit is contained in:
matt 2004-04-04 22:20:44 +00:00
parent e5795ee03a
commit 15fc41dbb0

View File

@ -1,4 +1,4 @@
/* $NetBSD: fpu.c,v 1.13 2004/04/04 19:21:36 matt Exp $ */ /* $NetBSD: fpu.c,v 1.14 2004/04/04 22:20:44 matt Exp $ */
/* /*
* Copyright (C) 1996 Wolfgang Solfrank. * Copyright (C) 1996 Wolfgang Solfrank.
@ -32,7 +32,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.13 2004/04/04 19:21:36 matt Exp $"); __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.14 2004/04/04 22:20:44 matt Exp $");
#include "opt_multiprocessor.h" #include "opt_multiprocessor.h"
@ -226,9 +226,9 @@ save_fpu_lwp(struct lwp *l)
} }
#define STICKYBITS (FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX|FPSCR_XX) #define STICKYBITS (FPSCR_VX|FPSCR_OX|FPSCR_UX|FPSCR_ZX|FPSCR_XX)
#if STICKYBITS & (PCB_FE0|PCB_FE1|PCB_VEC|PCB_FPU) #define STICKYSHIFT 25
#error PCB flags overlap FPSCR STICKYBITS #define MASKBITS (FPSCR_VE|FPSCR_OE|FPSCR_UE|FPSCR_ZE|FPSCR_XE)
#endif #define MASKSHIFT 3
int int
get_fpu_fault_code(void) get_fpu_fault_code(void)
@ -236,21 +236,22 @@ get_fpu_fault_code(void)
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
struct cpu_info *ci = curcpu(); struct cpu_info *ci = curcpu();
#endif #endif
struct lwp *l = curlwp; struct pcb *pcb = curpcb;
struct pcb *pcb = &l->l_addr->u_pcb;
register_t msr; register_t msr;
uint64_t tmp; uint64_t tmp, fpscr64;
uint32_t fpscr; uint32_t fpscr, ofpscr;
int code; int code;
KASSERT(pcb->pcb_fpcpu == ci); KASSERT(pcb->pcb_fpcpu == ci);
KASSERT(pcb->pcb_flags & PCB_FPU); KASSERT(pcb->pcb_flags & PCB_FPU);
KASSERT(ci->ci_fpulwp == l); KASSERT(ci->ci_fpulwp == curlwp);
msr = mfmsr(); msr = mfmsr();
mtmsr((msr & ~PSL_EE) | PSL_FP); mtmsr((msr & ~PSL_EE) | PSL_FP);
__asm __volatile ("isync"); __asm __volatile ("isync");
__asm __volatile ( __asm __volatile (
"stfd 0,0(%0)\n" /* save f0 */ "stfd 0,0(%0)\n" /* save f0 */
"mffs 0\n" /* get FPSCR */
"stfd 0,0(%2)\n" /* store a temp copy */
"mtfsb0 0\n" /* clear FPSCR_FX */ "mtfsb0 0\n" /* clear FPSCR_FX */
"mtfsb0 24\n" /* clear FPSCR_VE */ "mtfsb0 24\n" /* clear FPSCR_VE */
"mtfsb0 25\n" /* clear FPSCR_OE */ "mtfsb0 25\n" /* clear FPSCR_OE */
@ -260,29 +261,30 @@ get_fpu_fault_code(void)
"mffs 0\n" /* get FPSCR */ "mffs 0\n" /* get FPSCR */
"stfd 0,0(%1)\n" /* store it */ "stfd 0,0(%1)\n" /* store it */
"lfd 0,0(%0)\n" /* restore f0 */ "lfd 0,0(%0)\n" /* restore f0 */
:: "b"(&tmp), "b"(&pcb->pcb_fpu.fpscr)); :: "b"(&tmp), "b"(&pcb->pcb_fpu.fpscr), "b"(&fpscr64));
mtmsr(msr); mtmsr(msr);
__asm __volatile ("isync"); __asm __volatile ("isync");
/* /*
* Now determine the fault type. First we see if any of the sticky * Now determine the fault type. First we test to see if any of sticky
* bits have changed since the FP exception. If so, we only want * bits correspond to the enabled exceptions. If so, we only test
* to return the code for the new exception. If not, we look at all * those bits. If not, we look at all the bits. (In reality, we only
* the bits. * could get an exception if FPSCR_FEX changed state. So we should
* have at least one bit that corresponds).
*/ */
ofpscr = (uint32_t)fpscr64;
ofpscr &= ofpscr << (STICKYSHIFT - MASKSHIFT);
fpscr = (uint32_t)(*(uint64_t *)&pcb->pcb_fpu.fpscr); fpscr = (uint32_t)(*(uint64_t *)&pcb->pcb_fpu.fpscr);
if ((fpscr & ~pcb->pcb_flags) & STICKYBITS) if (fpscr & ofpscr & STICKYBITS)
fpscr &= ~pcb->pcb_flags; fpscr &= ofpscr;
/*
* Let's determine what the appropriate code is.
*/
if (fpscr & FPSCR_VX) code = FPE_FLTINV; if (fpscr & FPSCR_VX) code = FPE_FLTINV;
else if (fpscr & FPSCR_OX) code = FPE_FLTOVF; else if (fpscr & FPSCR_OX) code = FPE_FLTOVF;
else if (fpscr & FPSCR_UX) code = FPE_FLTUND; else if (fpscr & FPSCR_UX) code = FPE_FLTUND;
else if (fpscr & FPSCR_ZX) code = FPE_FLTDIV; else if (fpscr & FPSCR_ZX) code = FPE_FLTDIV;
else if (fpscr & FPSCR_XX) code = FPE_FLTRES; else if (fpscr & FPSCR_XX) code = FPE_FLTRES;
else code = 0; 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; return code;
} }