Merged from sys/i386/isa/npx.c revision 1.101.
This commit is contained in:
parent
b80875bce6
commit
d7e03ee681
@ -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)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user