summaryrefslogtreecommitdiffstats
path: root/sys/amd64/isa
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64/isa')
-rw-r--r--sys/amd64/isa/npx.c76
1 files changed, 23 insertions, 53 deletions
diff --git a/sys/amd64/isa/npx.c b/sys/amd64/isa/npx.c
index 477f7ba..60d38c4 100644
--- a/sys/amd64/isa/npx.c
+++ b/sys/amd64/isa/npx.c
@@ -55,6 +55,7 @@
#include <sys/syslog.h>
#endif
#include <sys/signalvar.h>
+#include <sys/user.h>
#ifndef SMP
#include <machine/asmacros.h>
@@ -93,7 +94,6 @@
#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
#define fnclex() __asm("fnclex")
#define fninit() __asm("fninit")
-#define fnop() __asm("fnop")
#define fnsave(addr) __asm __volatile("fnsave %0" : "=m" (*(addr)))
#define fnstcw(addr) __asm __volatile("fnstcw %0" : "=m" (*(addr)))
#define fnstsw(addr) __asm __volatile("fnstsw %0" : "=m" (*(addr)))
@@ -108,7 +108,6 @@
void fldcw __P((caddr_t addr));
void fnclex __P((void));
void fninit __P((void));
-void fnop __P((void));
void fnsave __P((caddr_t addr));
void fnstcw __P((caddr_t addr));
void fnstsw __P((caddr_t addr));
@@ -138,9 +137,6 @@ SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
"Floatingpoint instructions executed in hardware");
#ifndef SMP
-static u_int npx0_imask = 0;
-static struct gate_descriptor npx_idt_probeintr;
-static int npx_intrno;
static volatile u_int npx_intrs_while_probing;
static volatile u_int npx_traps_while_probing;
#endif
@@ -220,6 +216,7 @@ npx_probe(dev)
#else /* SMP */
+ int npx_intrno;
int result;
critical_t savecrit;
u_char save_icu1_mask;
@@ -245,7 +242,6 @@ npx_probe(dev)
outb(IO_ICU2 + 1, ~(1 << (npx_irq - 8)));
setidt(16, probetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
setidt(npx_intrno, probeintr, SDT_SYS386IGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
- npx_idt_probeintr = idt[npx_intrno];
/*
* XXX This looks highly bogus, but it appears that npc_probe1
@@ -368,10 +364,6 @@ npx_probe1(dev)
* Bad, we are stuck with IRQ13.
*/
npx_irq13 = 1;
- /*
- * npxattach would be too late to set npx0_imask
- */
- npx0_imask |= (1 << npx_irq);
/*
* We allocate these resources permanently,
@@ -850,59 +842,37 @@ npxdna()
}
/*
- * 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. This routine is
- * often called at splhigh so it must not use many system services. In
- * particular, it's much easier to install a special handler than to
- * guarantee that it's safe to use npxintr() and its supporting code.
+ * Wrapper for fnsave instruction, partly to handle hardware bugs. When npx
+ * exceptions are reported via IRQ13, spurious IRQ13's may be triggered by
+ * no-wait npx instructions. See the Intel application note AP-578 for
+ * details. This doesn't cause any additional complications here. IRQ13's
+ * are inherently asynchronous unless the CPU is frozen to deliver them --
+ * one that started in userland may be delivered many instructions later,
+ * after the process has entered the kernel. It may even be delivered after
+ * the fnsave here completes. A spurious IRQ13 for the fnsave is handled in
+ * the same way as a very-late-arriving non-spurious IRQ13 from user mode:
+ * it is normally ignored at first because we set npxproc to NULL; it is
+ * normally retriggered in npxdna() after return to user mode.
+ *
+ * npxsave() must be called with interrupts disabled, so that it clears
+ * npxproc atomically with saving the state. We require callers to do the
+ * disabling, since most callers need to disable interrupts anyway to call
+ * npxsave() atomically with checking npxproc.
+ *
+ * A previous version of npxsave() went to great lengths to excecute fnsave
+ * with interrupts enabled in case executing it froze the CPU. This case
+ * can't happen, at least for Intel CPU/NPX's. Spurious IRQ13's don't imply
+ * spurious freezes.
*/
void
npxsave(addr)
struct save87 *addr;
{
-#ifdef SMP
stop_emulating();
fnsave(addr);
- /* fnop(); */
start_emulating();
PCPU_SET(npxproc, NULL);
-
-#else /* SMP */
-
- critical_t savecrit;
- u_char icu1_mask;
- u_char icu2_mask;
- u_char old_icu1_mask;
- u_char old_icu2_mask;
- struct gate_descriptor save_idt_npxintr;
-
- savecrit = critical_enter();
- old_icu1_mask = inb(IO_ICU1 + 1);
- old_icu2_mask = inb(IO_ICU2 + 1);
- save_idt_npxintr = idt[npx_intrno];
- outb(IO_ICU1 + 1, old_icu1_mask & ~(IRQ_SLAVE | npx0_imask));
- outb(IO_ICU2 + 1, old_icu2_mask & ~(npx0_imask >> 8));
- idt[npx_intrno] = npx_idt_probeintr;
- critical_exit(savecrit);
- stop_emulating();
- fnsave(addr);
- fnop();
- start_emulating();
- savecrit = critical_enter();
- PCPU_SET(npxproc, NULL);
- icu1_mask = inb(IO_ICU1 + 1); /* masks may have changed */
- icu2_mask = inb(IO_ICU2 + 1);
- outb(IO_ICU1 + 1,
- (icu1_mask & ~npx0_imask) | (old_icu1_mask & npx0_imask));
- outb(IO_ICU2 + 1,
- (icu2_mask & ~(npx0_imask >> 8))
- | (old_icu2_mask & (npx0_imask >> 8)));
- idt[npx_intrno] = save_idt_npxintr;
- critical_exit(savecrit); /* back to previous state */
-
-#endif /* SMP */
}
#ifdef I586_CPU
OpenPOWER on IntegriCloud