summaryrefslogtreecommitdiffstats
path: root/sys/pc98
diff options
context:
space:
mode:
authornyan <nyan@FreeBSD.org>2001-06-02 05:00:08 +0000
committernyan <nyan@FreeBSD.org>2001-06-02 05:00:08 +0000
commit69fcd429613095182395f09ed46525b4141df150 (patch)
tree849ac6e683b3523b0bad937a9c9a35cee48419c8 /sys/pc98
parent17345a630936bb1a413e4ee478318ce03dba111d (diff)
downloadFreeBSD-src-69fcd429613095182395f09ed46525b4141df150.zip
FreeBSD-src-69fcd429613095182395f09ed46525b4141df150.tar.gz
Merged from sys/i386/isa/npx.c revision 1.101.
Diffstat (limited to 'sys/pc98')
-rw-r--r--sys/pc98/pc98/npx.c164
1 files changed, 85 insertions, 79 deletions
diff --git a/sys/pc98/pc98/npx.c b/sys/pc98/pc98/npx.c
index 9b070a4..5930ff5 100644
--- a/sys/pc98/pc98/npx.c
+++ b/sys/pc98/pc98/npx.c
@@ -126,8 +126,10 @@ void stop_emulating __P((void));
typedef u_char bool_t;
static int npx_attach __P((device_t dev));
- void npx_intr __P((void *));
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_probe1 __P((device_t dev));
#ifdef I586_CPU
@@ -212,6 +214,55 @@ npx_identify(driver, parent)
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
* whether the device exists or not (XXX should be elsewhere). Set flags
@@ -234,12 +285,10 @@ npx_probe(dev)
#else /* SMP */
- int npx_intrno;
int result;
critical_t savecrit;
u_char save_icu1_mask;
u_char save_icu2_mask;
- struct gate_descriptor save_idt_npxintr;
struct gate_descriptor save_idt_npxtrap;
/*
* This routine is now just a wrapper for npxprobe1(), to install
@@ -432,11 +481,20 @@ npx_probe1(dev)
panic("npx: can't get IRQ");
BUS_SETUP_INTR(device_get_parent(dev),
dev, r,
- INTR_TYPE_MISC | INTR_MPSAFE,
+ INTR_TYPE_MISC | INTR_FAST,
npx_intr, 0, &intr);
if (intr == 0)
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);
}
/*
@@ -763,91 +821,39 @@ static char fpetable[128] = {
* destroyed by IRQ13 bugs. Clearing FP exceptions is not an acceptable
* solution for signals other than SIGFPE.
*/
-void
-npx_intr(dummy)
- void *dummy;
+int
+npxtrap()
{
- int code;
- u_short control;
- struct intrframe *frame;
+ critical_t savecrit;
+ u_short control, status;
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);
- panic("npxintr from nowhere");
+ panic("npxtrap from nowhere");
}
-#ifdef PC98
- 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);
+ savecrit = critical_enter();
/*
- * 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);
- frame = (struct intrframe *)&dummy; /* XXX */
- if ((ISPL(frame->if_cs) == SEL_UPL) || (frame->if_eflags & PSL_VM)) {
- /*
- * 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);
+ if (PCPU_GET(npxproc) != curproc) {
+ control = curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_cw;
+ status = curproc->p_addr->u_pcb.pcb_savefpu.sv_env.en_sw;
} 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.
- *
- * Treat them like a true async interrupt.
- */
- PROC_LOCK(curproc);
- psignal(curproc, SIGFPE);
- PROC_UNLOCK(curproc);
+ fnstcw(&control);
+ fnstsw(&status);
}
- 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)]);
}
/*
OpenPOWER on IntegriCloud