Merged from sys/i386/isa/npx.c revision 1.101.

This commit is contained in:
Yoshihiro Takahashi 2001-06-02 05:00:08 +00:00
parent b80875bce6
commit d7e03ee681

View File

@ -126,8 +126,10 @@ void stop_emulating __P((void));
typedef u_char bool_t; typedef u_char bool_t;
static int npx_attach __P((device_t dev)); static int npx_attach __P((device_t dev));
void npx_intr __P((void *));
static void npx_identify __P((driver_t *driver, device_t parent)); static void npx_identify __P((driver_t *driver, device_t parent));
#ifndef SMP
static void npx_intr __P((void *));
#endif
static int npx_probe __P((device_t dev)); static int npx_probe __P((device_t dev));
static int npx_probe1 __P((device_t dev)); static int npx_probe1 __P((device_t dev));
#ifdef I586_CPU #ifdef I586_CPU
@ -212,6 +214,55 @@ npx_identify(driver, parent)
panic("npx_identify"); panic("npx_identify");
} }
#ifndef SMP
/*
* Do minimal handling of npx interrupts to convert them to traps.
*/
static void
npx_intr(dummy)
void *dummy;
{
struct proc *p;
/*
* The BUSY# latch must be cleared in all cases so that the next
* unmasked npx exception causes an interrupt.
*/
#ifdef PC98
outb(0xf8, 0);
#else
outb(0xf0, 0);
#endif
/*
* npxproc is normally non-null here. In that case, schedule an
* AST to finish the exception handling in the correct context
* (this interrupt may occur after the process has entered the
* kernel via a syscall or an interrupt). Otherwise, the npx
* state of the process that caused this interrupt must have been
* pushed to the process' pcb, and clearing of the busy latch
* above has finished the (essentially null) handling of this
* interrupt. Control will eventually return to the instruction
* that caused it and it will repeat. We will eventually (usually
* soon) win the race to handle the interrupt properly.
*/
p = PCPU_GET(npxproc);
if (p != NULL) {
p->p_addr->u_pcb.pcb_flags |= PCB_NPXTRAP;
mtx_lock_spin(&sched_lock);
aston(p);
mtx_unlock_spin(&sched_lock);
}
}
/*
* XXX these "local" variables of npx_probe() are non-local so that
* npxprobe1() can abuse them.
*/
static int npx_intrno;
static struct gate_descriptor save_idt_npxintr;
#endif /* !SMP */
/* /*
* Probe routine. Initialize cr0 to give correct behaviour for [f]wait * Probe routine. Initialize cr0 to give correct behaviour for [f]wait
* whether the device exists or not (XXX should be elsewhere). Set flags * whether the device exists or not (XXX should be elsewhere). Set flags
@ -234,12 +285,10 @@ npx_probe(dev)
#else /* SMP */ #else /* SMP */
int npx_intrno;
int result; int result;
critical_t savecrit; critical_t savecrit;
u_char save_icu1_mask; u_char save_icu1_mask;
u_char save_icu2_mask; u_char save_icu2_mask;
struct gate_descriptor save_idt_npxintr;
struct gate_descriptor save_idt_npxtrap; struct gate_descriptor save_idt_npxtrap;
/* /*
* This routine is now just a wrapper for npxprobe1(), to install * This routine is now just a wrapper for npxprobe1(), to install
@ -432,11 +481,20 @@ npx_probe1(dev)
panic("npx: can't get IRQ"); panic("npx: can't get IRQ");
BUS_SETUP_INTR(device_get_parent(dev), BUS_SETUP_INTR(device_get_parent(dev),
dev, r, dev, r,
INTR_TYPE_MISC | INTR_MPSAFE, INTR_TYPE_MISC | INTR_FAST,
npx_intr, 0, &intr); npx_intr, 0, &intr);
if (intr == 0) if (intr == 0)
panic("npx: can't create intr"); panic("npx: can't create intr");
/*
* XXX BUS_SETUP_INTR() has changed
* idt[npx_intrno] to point to Xfastintr0
* instead of Xfastintr0. Adjust
* save_idt_npxintr so that npxprobe()
* doesn't undo this.
*/
save_idt_npxintr = idt[npx_intrno];
return (0); return (0);
} }
/* /*
@ -763,91 +821,39 @@ static char fpetable[128] = {
* destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable * destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable
* solution for signals other than SIGFPE. * solution for signals other than SIGFPE.
*/ */
void int
npx_intr(dummy) npxtrap()
void *dummy;
{ {
int code; critical_t savecrit;
u_short control; u_short control, status;
struct intrframe *frame;
if (!npx_exists) { if (!npx_exists) {
printf("npxintr: npxproc = %p, curproc = %p, npx_exists = %d\n", printf("npxtrap: npxproc = %p, curproc = %p, npx_exists = %d\n",
PCPU_GET(npxproc), curproc, npx_exists); PCPU_GET(npxproc), curproc, npx_exists);
panic("npxintr from nowhere"); panic("npxtrap from nowhere");
} }
#ifdef PC98 savecrit = critical_enter();
outb(0xf8, 0);
#else
outb(0xf0, 0);
#endif
mtx_lock_spin(&sched_lock);
if (PCPU_GET(npxproc) != curproc) {
/*
* Interrupt handling (for this or another interrupt) has
* switched npxproc from underneath us before we managed
* to handle this interrupt. Just ignore this interrupt.
* Control will eventually return to the instruction that
* caused it and it will repeat. In the npx_ex16 case,
* then we will eventually (usually soon) win the race.
* In the npx_irq13 case, we will always lose the race
* because we have switched to the IRQ13 thread. This will
* be fixed later.
*/
mtx_unlock_spin(&sched_lock);
return;
}
fnstsw(&PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw);
fnstcw(&control);
fnclex();
mtx_unlock_spin(&sched_lock);
/* /*
* Pass exception to process. * Interrupt handling (for another interrupt) may have pushed the
* state to memory. Fetch the relevant parts of the state from
* wherever they are.
*/ */
mtx_lock(&Giant); if (PCPU_GET(npxproc) != curproc) {
frame = (struct intrframe *)&dummy; /* XXX */ control = curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_cw;
if ((ISPL(frame->if_cs) == SEL_UPL) || (frame->if_eflags & PSL_VM)) { status = curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_sw;
/*
* Interrupt is essentially a trap, so we can afford to call
* the SIGFPE handler (if any) as soon as the interrupt
* returns.
*
* XXX little or nothing is gained from this, and plenty is
* lost - the interrupt frame has to contain the trap frame
* (this is otherwise only necessary for the rescheduling trap
* in doreti, and the frame for that could easily be set up
* just before it is used).
*/
curproc->p_md.md_regs = INTR_TO_TRAPFRAME(frame);
/*
* Encode the appropriate code for detailed information on
* this exception.
*/
code =
fpetable[(PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw & ~control & 0x3f) |
(PCPU_GET(curpcb)->pcb_savefpu.sv_ex_sw & 0x40)];
trapsignal(curproc, SIGFPE, code);
} else { } else {
/* fnstcw(&control);
* Nested interrupt. These losers occur when: fnstsw(&status);
* 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.
*
* Treat them like a true async interrupt.
*/
PROC_LOCK(curproc);
psignal(curproc, SIGFPE);
PROC_UNLOCK(curproc);
} }
mtx_unlock(&Giant);
curproc->p_addr->u_pcb.pcb_savefpu.sv_ex_sw = status;
if (PCPU_GET(npxproc) != curproc)
curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_sw &= ~0x80bf;
else
fnclex();
critical_exit(savecrit);
return (fpetable[status & ((~control & 0x3f) | 0x40)]);
} }
/* /*