In npxdna(), if there was an exception state in the FPU but npxproc was

null, the frstor would fault on a PPro.  I'm pretty sure this is not
how the chip is supposed to behave, but it's easy enough to do a fninit
to throw away the exception state.
Also, some other minor changes to the documentation.
This commit is contained in:
mycroft 1998-03-20 20:15:14 +00:00
parent bd31517508
commit 919340aaa5
1 changed files with 61 additions and 57 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: npx.c,v 1.65 1998/02/10 14:11:26 mrg Exp $ */ /* $NetBSD: npx.c,v 1.66 1998/03/20 20:15:14 mycroft Exp $ */
#if 0 #if 0
#define IPRINTF(x) printf x #define IPRINTF(x) printf x
@ -7,7 +7,7 @@
#endif #endif
/*- /*-
* Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. * Copyright (c) 1994, 1995, 1998 Charles M. Hannum. All rights reserved.
* Copyright (c) 1990 William Jolitz. * Copyright (c) 1990 William Jolitz.
* Copyright (c) 1991 The Regents of the University of California. * Copyright (c) 1991 The Regents of the University of California.
* All rights reserved. * All rights reserved.
@ -388,21 +388,33 @@ npxintr(arg)
if (p == 0 || npx_type == NPX_NONE) { if (p == 0 || npx_type == NPX_NONE) {
printf("npxintr: p = %p, curproc = %p, npx_type = %d\n", printf("npxintr: p = %p, curproc = %p, npx_type = %d\n",
p, curproc, npx_type); p, curproc, npx_type);
panic("npxintr from nowhere"); panic("npxintr: came from nowhere");
} }
/* /*
* Clear the interrupt latch. * Clear the interrupt latch.
*/ */
outb(0xf0, 0); outb(0xf0, 0);
/* /*
* If we're saving, ignore the interrupt. The FPU will happily * If we're saving, ignore the interrupt. The FPU will generate
* generate another one when we restore the state later. * another one when we restore the state later.
*/ */
if (npx_nointr != 0) if (npx_nointr != 0)
return (1); return (1);
#ifdef DIAGNOSTIC
/* /*
* Find the address of npxproc's savefpu. This is not necessarily * At this point, npxproc should be curproc. If it wasn't, the TS bit
* the one in curpcb. * should be set, and we should have gotten a DNA exception.
*/
if (p != curproc)
panic("npxintr: wrong process");
#endif
/*
* Find the address of npxproc's saved FPU state. (Given the invariant
* above, this is always the one in curpcb.)
*/ */
addr = &p->p_addr->u_pcb.pcb_savefpu; addr = &p->p_addr->u_pcb.pcb_savefpu;
/* /*
@ -428,10 +440,9 @@ npxintr(arg)
addr->sv_ex_tw = addr->sv_env.en_tw; addr->sv_ex_tw = addr->sv_env.en_tw;
/* /*
* Pass exception to process. If it's the current process, try to do * Pass exception to process.
* it immediately.
*/ */
if (p == curproc && USERMODE(frame->if_cs, frame->if_eflags)) { if (USERMODE(frame->if_cs, frame->if_eflags)) {
/* /*
* Interrupt is essentially a trap, so we can afford to call * Interrupt is essentially a trap, so we can afford to call
* the SIGFPE handler (if any) as soon as the interrupt * the SIGFPE handler (if any) as soon as the interrupt
@ -456,18 +467,13 @@ npxintr(arg)
trapsignal(p, SIGFPE, code); trapsignal(p, SIGFPE, code);
} else { } else {
/* /*
* Nested interrupt. These losers occur when: * This is a nested interrupt. This should only happen when
* o an IRQ13 is bogusly generated at a bogus time, e.g.: * an IRQ13 occurs at the same time as a higher-priority
* o immediately after an fnsave or frstor of an * interrupt.
* error state.
* o a couple of 386 instructions after
* "fstpl _memvar" causes a stack overflow.
* These are especially nasty when combined with a
* trace trap.
* o an IRQ13 occurs at the same time as another higher-
* priority interrupt.
* *
* Treat them like a true async interrupt. * XXX
* Currently, we treat this like an asynchronous interrupt, but
* this has disadvantages.
*/ */
psignal(p, SIGFPE); psignal(p, SIGFPE);
} }
@ -476,9 +482,11 @@ npxintr(arg)
} }
/* /*
* Wrapper for fnsave instruction to handle h/w bugs. If there is an error * Wrapper for the fnsave instruction. We set the TS bit in the saved CR0 for
* pending, then fnsave generates a bogus IRQ13 on some systems. Force any * this process, so that it will get a DNA exception on the FPU instruction and
* IRQ13 to be handled immediately, and then ignore it. * force a reload. This routine is always called with npx_nointr set, so that
* any pending exception will be thrown away. (It will be caught again if/when
* the FPU state is restored.)
* *
* This routine is always called at spl0. If it might called with the NPX * This routine is always called at spl0. If it might called with the NPX
* interrupt masked, it would be necessary to forcibly unmask the NPX interrupt * interrupt masked, it would be necessary to forcibly unmask the NPX interrupt
@ -487,14 +495,11 @@ npxintr(arg)
static inline void static inline void
npxsave1() npxsave1()
{ {
register struct pcb *pcb; struct proc *p = npxproc;
npx_nointr = 1; fnsave(&p->p_addr->u_pcb.pcb_savefpu);
pcb = &npxproc->p_addr->u_pcb; p->p_addr->u_pcb.pcb_cr0 |= CR0_TS;
fnsave(&pcb->pcb_savefpu);
pcb->pcb_cr0 |= CR0_TS;
fwait(); fwait();
npx_nointr = 0;
} }
/* /*
@ -508,7 +513,6 @@ int
npxdna(p) npxdna(p)
struct proc *p; struct proc *p;
{ {
u_short cw;
if (npx_type == NPX_NONE) { if (npx_type == NPX_NONE) {
IPRINTF(("Emul")); IPRINTF(("Emul"));
@ -523,30 +527,27 @@ npxdna(p)
p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS; p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS;
clts(); clts();
if ((p->p_md.md_flags & MDP_USEDFPU) == 0) { /*
* Initialize the FPU state to clear any exceptions. If someone else
* was using the FPU, save their state (which does an implicit
* initialization).
*/
npx_nointr = 1;
if (npxproc != 0 && npxproc != p) {
IPRINTF(("Save"));
npxsave1();
} else {
IPRINTF(("Init")); IPRINTF(("Init"));
cw = p->p_addr->u_pcb.pcb_savefpu.sv_env.en_cw; fninit();
if (npxproc != 0 && npxproc != p) fwait();
npxsave1(); }
else { npx_nointr = 0;
npx_nointr = 1; npxproc = p;
fninit();
fwait(); if ((p->p_md.md_flags & MDP_USEDFPU) == 0) {
npx_nointr = 0; fldcw(&p->p_addr->u_pcb.pcb_savefpu.sv_env.en_cw);
}
npxproc = p;
fldcw(&cw);
p->p_md.md_flags |= MDP_USEDFPU; p->p_md.md_flags |= MDP_USEDFPU;
} else { } else {
if (npxproc != 0) {
#ifdef DIAGNOSTIC
if (npxproc == p)
panic("npxdna: same process");
#endif
IPRINTF(("Save"));
npxsave1();
}
npxproc = p;
/* /*
* The following frstor may cause an IRQ13 when the state being * The following frstor may cause an IRQ13 when the state being
* restored has a pending error. The error will appear to have * restored has a pending error. The error will appear to have
@ -572,10 +573,11 @@ npxdna(p)
void void
npxdrop() npxdrop()
{ {
struct proc *p = npxproc;
stts();
npxproc->p_addr->u_pcb.pcb_cr0 |= CR0_TS;
npxproc = 0; npxproc = 0;
stts();
p->p_addr->u_pcb.pcb_cr0 |= CR0_TS;
} }
/* /*
@ -584,8 +586,8 @@ npxdrop()
* The FNSAVE instruction clears the FPU state. Rather than reloading the FPU * The FNSAVE instruction clears the FPU state. Rather than reloading the FPU
* immediately, we clear npxproc and turn on CR0_TS to force a DNA and a reload * immediately, we clear npxproc and turn on CR0_TS to force a DNA and a reload
* of the FPU state the next time we try to use it. This routine is only * of the FPU state the next time we try to use it. This routine is only
* called when forking or core dump, so this algorithm at worst forces us to * called when forking or core dumping, so the lazy reload at worst forces us
* trap once per fork(), and at best saves us a reload once per fork(). * to trap once per fork(), and at best saves us a reload once per fork().
*/ */
void void
npxsave() npxsave()
@ -597,7 +599,9 @@ npxsave()
#endif #endif
IPRINTF(("Fork")); IPRINTF(("Fork"));
clts(); clts();
npx_nointr = 1;
npxsave1(); npxsave1();
stts(); npx_nointr = 0;
npxproc = 0; npxproc = 0;
stts();
} }