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:
parent
bd31517508
commit
919340aaa5
|
@ -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
|
||||
#define IPRINTF(x) printf x
|
||||
|
@ -7,7 +7,7 @@
|
|||
#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) 1991 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
|
@ -388,21 +388,33 @@ npxintr(arg)
|
|||
if (p == 0 || npx_type == NPX_NONE) {
|
||||
printf("npxintr: p = %p, curproc = %p, npx_type = %d\n",
|
||||
p, curproc, npx_type);
|
||||
panic("npxintr from nowhere");
|
||||
panic("npxintr: came from nowhere");
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear the interrupt latch.
|
||||
*/
|
||||
outb(0xf0, 0);
|
||||
|
||||
/*
|
||||
* If we're saving, ignore the interrupt. The FPU will happily
|
||||
* generate another one when we restore the state later.
|
||||
* If we're saving, ignore the interrupt. The FPU will generate
|
||||
* another one when we restore the state later.
|
||||
*/
|
||||
if (npx_nointr != 0)
|
||||
return (1);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* Find the address of npxproc's savefpu. This is not necessarily
|
||||
* the one in curpcb.
|
||||
* At this point, npxproc should be curproc. If it wasn't, the TS bit
|
||||
* 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;
|
||||
/*
|
||||
|
@ -428,10 +440,9 @@ npxintr(arg)
|
|||
addr->sv_ex_tw = addr->sv_env.en_tw;
|
||||
|
||||
/*
|
||||
* Pass exception to process. If it's the current process, try to do
|
||||
* it immediately.
|
||||
* Pass exception to process.
|
||||
*/
|
||||
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
|
||||
* the SIGFPE handler (if any) as soon as the interrupt
|
||||
|
@ -456,18 +467,13 @@ npxintr(arg)
|
|||
trapsignal(p, SIGFPE, code);
|
||||
} else {
|
||||
/*
|
||||
* Nested interrupt. These losers occur when:
|
||||
* o an IRQ13 is bogusly generated at a bogus time, e.g.:
|
||||
* o immediately after an fnsave or frstor of an
|
||||
* 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.
|
||||
* This is a nested interrupt. This should only happen when
|
||||
* an IRQ13 occurs at the same time as a 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);
|
||||
}
|
||||
|
@ -476,9 +482,11 @@ npxintr(arg)
|
|||
}
|
||||
|
||||
/*
|
||||
* Wrapper for fnsave instruction to handle h/w bugs. If there is an error
|
||||
* pending, then fnsave generates a bogus IRQ13 on some systems. Force any
|
||||
* IRQ13 to be handled immediately, and then ignore it.
|
||||
* Wrapper for the fnsave instruction. We set the TS bit in the saved CR0 for
|
||||
* this process, so that it will get a DNA exception on the FPU instruction and
|
||||
* 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
|
||||
* interrupt masked, it would be necessary to forcibly unmask the NPX interrupt
|
||||
|
@ -487,14 +495,11 @@ npxintr(arg)
|
|||
static inline void
|
||||
npxsave1()
|
||||
{
|
||||
register struct pcb *pcb;
|
||||
struct proc *p = npxproc;
|
||||
|
||||
npx_nointr = 1;
|
||||
pcb = &npxproc->p_addr->u_pcb;
|
||||
fnsave(&pcb->pcb_savefpu);
|
||||
pcb->pcb_cr0 |= CR0_TS;
|
||||
fnsave(&p->p_addr->u_pcb.pcb_savefpu);
|
||||
p->p_addr->u_pcb.pcb_cr0 |= CR0_TS;
|
||||
fwait();
|
||||
npx_nointr = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -508,7 +513,6 @@ int
|
|||
npxdna(p)
|
||||
struct proc *p;
|
||||
{
|
||||
u_short cw;
|
||||
|
||||
if (npx_type == NPX_NONE) {
|
||||
IPRINTF(("Emul"));
|
||||
|
@ -523,30 +527,27 @@ npxdna(p)
|
|||
p->p_addr->u_pcb.pcb_cr0 &= ~CR0_TS;
|
||||
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"));
|
||||
cw = p->p_addr->u_pcb.pcb_savefpu.sv_env.en_cw;
|
||||
if (npxproc != 0 && npxproc != p)
|
||||
npxsave1();
|
||||
else {
|
||||
npx_nointr = 1;
|
||||
fninit();
|
||||
fwait();
|
||||
npx_nointr = 0;
|
||||
}
|
||||
npxproc = p;
|
||||
fldcw(&cw);
|
||||
fninit();
|
||||
fwait();
|
||||
}
|
||||
npx_nointr = 0;
|
||||
npxproc = p;
|
||||
|
||||
if ((p->p_md.md_flags & MDP_USEDFPU) == 0) {
|
||||
fldcw(&p->p_addr->u_pcb.pcb_savefpu.sv_env.en_cw);
|
||||
p->p_md.md_flags |= MDP_USEDFPU;
|
||||
} 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
|
||||
* restored has a pending error. The error will appear to have
|
||||
|
@ -572,10 +573,11 @@ npxdna(p)
|
|||
void
|
||||
npxdrop()
|
||||
{
|
||||
struct proc *p = npxproc;
|
||||
|
||||
stts();
|
||||
npxproc->p_addr->u_pcb.pcb_cr0 |= CR0_TS;
|
||||
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
|
||||
* 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
|
||||
* called when forking or core dump, so this algorithm at worst forces us to
|
||||
* trap once per fork(), and at best saves us a reload once per fork().
|
||||
* called when forking or core dumping, so the lazy reload at worst forces us
|
||||
* to trap once per fork(), and at best saves us a reload once per fork().
|
||||
*/
|
||||
void
|
||||
npxsave()
|
||||
|
@ -597,7 +599,9 @@ npxsave()
|
|||
#endif
|
||||
IPRINTF(("Fork"));
|
||||
clts();
|
||||
npx_nointr = 1;
|
||||
npxsave1();
|
||||
stts();
|
||||
npx_nointr = 0;
|
||||
npxproc = 0;
|
||||
stts();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue