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:
parent
e5795ee03a
commit
15fc41dbb0
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user