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.
This commit is contained in:
parent
12d5178857
commit
e7c76e51e6
|
@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.12 2004/04/04 17:35:15 matt Exp $");
|
|||
#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 @@ enable_fpu(void)
|
|||
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 @@ enable_fpu(void)
|
|||
"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 @@ save_fpu_lwp(struct lwp *l)
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -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 @@ trap(struct trapframe *frame)
|
|||
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
|
||||
|
|
Loading…
Reference in New Issue