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
|
#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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue