The great s/npx/fpu/gi
This commit is contained in:
parent
d0ff2e64ac
commit
bf2f09ee97
@ -131,7 +131,7 @@ ENTRY(cpu_switch)
|
|||||||
pushq %rsi
|
pushq %rsi
|
||||||
addq $PCB_SAVEFPU,%r8 /* h/w bugs make saving complicated */
|
addq $PCB_SAVEFPU,%r8 /* h/w bugs make saving complicated */
|
||||||
movq %r8, %rdi
|
movq %r8, %rdi
|
||||||
call npxsave /* do it in a big C function */
|
call fpusave /* do it in a big C function */
|
||||||
popq %rsi
|
popq %rsi
|
||||||
popq %rdi
|
popq %rdi
|
||||||
1:
|
1:
|
||||||
@ -301,16 +301,16 @@ ENTRY(savectx)
|
|||||||
popq PCB_RFLAGS(%rcx)
|
popq PCB_RFLAGS(%rcx)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If fpcurthread == NULL, then the npx h/w state is irrelevant and the
|
* If fpcurthread == NULL, then the fpu h/w state is irrelevant and the
|
||||||
* state had better already be in the pcb. This is true for forks
|
* state had better already be in the pcb. This is true for forks
|
||||||
* but not for dumps (the old book-keeping with FP flags in the pcb
|
* but not for dumps (the old book-keeping with FP flags in the pcb
|
||||||
* always lost for dumps because the dump pcb has 0 flags).
|
* always lost for dumps because the dump pcb has 0 flags).
|
||||||
*
|
*
|
||||||
* If fpcurthread != NULL, then we have to save the npx h/w state to
|
* If fpcurthread != NULL, then we have to save the fpu h/w state to
|
||||||
* fpcurthread's pcb and copy it to the requested pcb, or save to the
|
* fpcurthread's pcb and copy it to the requested pcb, or save to the
|
||||||
* requested pcb and reload. Copying is easier because we would
|
* requested pcb and reload. Copying is easier because we would
|
||||||
* have to handle h/w bugs for reloading. We used to lose the
|
* have to handle h/w bugs for reloading. We used to lose the
|
||||||
* parent's npx state for forks by forgetting to reload.
|
* parent's fpu state for forks by forgetting to reload.
|
||||||
*/
|
*/
|
||||||
pushfq
|
pushfq
|
||||||
cli
|
cli
|
||||||
@ -322,7 +322,7 @@ ENTRY(savectx)
|
|||||||
pushq %rax
|
pushq %rax
|
||||||
movq TD_PCB(%rax),%rdi
|
movq TD_PCB(%rax),%rdi
|
||||||
leaq PCB_SAVEFPU(%rdi),%rdi
|
leaq PCB_SAVEFPU(%rdi),%rdi
|
||||||
call npxsave
|
call fpusave
|
||||||
popq %rax
|
popq %rax
|
||||||
popq %rcx
|
popq %rcx
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
#include "opt_debug_npx.h"
|
|
||||||
#include "opt_isa.h"
|
#include "opt_isa.h"
|
||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
@ -53,9 +52,6 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <machine/bus.h>
|
#include <machine/bus.h>
|
||||||
#include <sys/rman.h>
|
#include <sys/rman.h>
|
||||||
#ifdef NPX_DEBUG
|
|
||||||
#include <sys/syslog.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/signalvar.h>
|
#include <sys/signalvar.h>
|
||||||
#include <sys/user.h>
|
#include <sys/user.h>
|
||||||
|
|
||||||
@ -75,7 +71,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
|
* Floating point support.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(lint)
|
#if defined(__GNUC__) && !defined(lint)
|
||||||
@ -110,59 +106,50 @@ void stop_emulating(void);
|
|||||||
|
|
||||||
typedef u_char bool_t;
|
typedef u_char bool_t;
|
||||||
|
|
||||||
static int npx_attach(device_t dev);
|
static int fpu_attach(device_t dev);
|
||||||
static void npx_identify(driver_t *driver, device_t parent);
|
static void fpu_identify(driver_t *driver, device_t parent);
|
||||||
static int npx_probe(device_t dev);
|
static int fpu_probe(device_t dev);
|
||||||
|
|
||||||
int hw_float = 1;
|
int hw_float = 1;
|
||||||
SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
|
SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
|
||||||
CTLFLAG_RD, &hw_float, 0,
|
CTLFLAG_RD, &hw_float, 0,
|
||||||
"Floatingpoint instructions executed in hardware");
|
"Floatingpoint instructions executed in hardware");
|
||||||
|
|
||||||
static struct savefpu npx_cleanstate;
|
static struct savefpu fpu_cleanstate;
|
||||||
static bool_t npx_cleanstate_ready;
|
static bool_t fpu_cleanstate_ready;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Identify routine. Create a connection point on our parent for probing.
|
* Identify routine. Create a connection point on our parent for probing.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
npx_identify(driver, parent)
|
fpu_identify(driver_t *driver, device_t parent)
|
||||||
driver_t *driver;
|
|
||||||
device_t parent;
|
|
||||||
{
|
{
|
||||||
device_t child;
|
device_t child;
|
||||||
|
|
||||||
child = BUS_ADD_CHILD(parent, 0, "npx", 0);
|
child = BUS_ADD_CHILD(parent, 0, "fpu", 0);
|
||||||
if (child == NULL)
|
if (child == NULL)
|
||||||
panic("npx_identify");
|
panic("fpu_identify");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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).
|
* whether the device exists or not (XXX should be elsewhere).
|
||||||
* Modify device struct if npx doesn't need to use interrupts.
|
* Modify device struct if fpu doesn't need to use interrupts.
|
||||||
* Return 0 if device exists.
|
* Return 0 if device exists.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
npx_probe(dev)
|
fpu_probe(device_t dev)
|
||||||
device_t dev;
|
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Partially reset the coprocessor, if any. Some BIOS's don't reset
|
* Prepare to trap all ESC (i.e., FPU) instructions and all WAIT
|
||||||
* it after a warm boot.
|
|
||||||
*/
|
|
||||||
outb(0xf1, 0); /* full reset on some systems, NOP on others */
|
|
||||||
outb(0xf0, 0); /* clear BUSY# latch */
|
|
||||||
/*
|
|
||||||
* Prepare to trap all ESC (i.e., NPX) instructions and all WAIT
|
|
||||||
* instructions. We must set the CR0_MP bit and use the CR0_TS
|
* instructions. We must set the CR0_MP bit and use the CR0_TS
|
||||||
* bit to control the trap, because setting the CR0_EM bit does
|
* bit to control the trap, because setting the CR0_EM bit does
|
||||||
* not cause WAIT instructions to trap. It's important to trap
|
* not cause WAIT instructions to trap. It's important to trap
|
||||||
* WAIT instructions - otherwise the "wait" variants of no-wait
|
* WAIT instructions - otherwise the "wait" variants of no-wait
|
||||||
* control instructions would degenerate to the "no-wait" variants
|
* control instructions would degenerate to the "no-wait" variants
|
||||||
* after FP context switches but work correctly otherwise. It's
|
* after FP context switches but work correctly otherwise. It's
|
||||||
* particularly important to trap WAITs when there is no NPX -
|
* particularly important to trap WAITs when there is no FPU -
|
||||||
* otherwise the "wait" variants would always degenerate.
|
* otherwise the "wait" variants would always degenerate.
|
||||||
*
|
*
|
||||||
* Try setting CR0_NE to get correct error reporting on 486DX's.
|
* Try setting CR0_NE to get correct error reporting on 486DX's.
|
||||||
@ -179,6 +166,7 @@ npx_probe(dev)
|
|||||||
fninit();
|
fninit();
|
||||||
|
|
||||||
device_set_desc(dev, "math processor");
|
device_set_desc(dev, "math processor");
|
||||||
|
device_quiet(dev);
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -187,19 +175,18 @@ npx_probe(dev)
|
|||||||
* Attach routine - announce which it is, and wire into system
|
* Attach routine - announce which it is, and wire into system
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
npx_attach(dev)
|
fpu_attach(device_t dev)
|
||||||
device_t dev;
|
|
||||||
{
|
{
|
||||||
register_t s;
|
register_t s;
|
||||||
|
|
||||||
npxinit(__INITIAL_NPXCW__);
|
fpuinit(__INITIAL_FPUCW__);
|
||||||
|
|
||||||
if (npx_cleanstate_ready == 0) {
|
if (fpu_cleanstate_ready == 0) {
|
||||||
s = intr_disable();
|
s = intr_disable();
|
||||||
stop_emulating();
|
stop_emulating();
|
||||||
fxsave(&npx_cleanstate);
|
fxsave(&fpu_cleanstate);
|
||||||
start_emulating();
|
start_emulating();
|
||||||
npx_cleanstate_ready = 1;
|
fpu_cleanstate_ready = 1;
|
||||||
intr_restore(s);
|
intr_restore(s);
|
||||||
}
|
}
|
||||||
return (0); /* XXX unused */
|
return (0); /* XXX unused */
|
||||||
@ -209,21 +196,20 @@ npx_attach(dev)
|
|||||||
* Initialize floating point unit.
|
* Initialize floating point unit.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
npxinit(control)
|
fpuinit(u_short control)
|
||||||
u_short control;
|
|
||||||
{
|
{
|
||||||
static struct savefpu dummy;
|
static struct savefpu dummy;
|
||||||
register_t savecrit;
|
register_t savecrit;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* fninit has the same h/w bugs as fnsave. Use the detoxified
|
* fninit has the same h/w bugs as fnsave. Use the detoxified
|
||||||
* fnsave to throw away any junk in the fpu. npxsave() initializes
|
* fnsave to throw away any junk in the fpu. fpusave() initializes
|
||||||
* the fpu and sets fpcurthread = NULL as important side effects.
|
* the fpu and sets fpcurthread = NULL as important side effects.
|
||||||
*/
|
*/
|
||||||
savecrit = intr_disable();
|
savecrit = intr_disable();
|
||||||
npxsave(&dummy);
|
fpusave(&dummy);
|
||||||
stop_emulating();
|
stop_emulating();
|
||||||
/* XXX npxsave() doesn't actually initialize the fpu in the SSE case. */
|
/* XXX fpusave() doesn't actually initialize the fpu in the SSE case. */
|
||||||
fninit();
|
fninit();
|
||||||
fldcw(&control);
|
fldcw(&control);
|
||||||
start_emulating();
|
start_emulating();
|
||||||
@ -234,34 +220,18 @@ npxinit(control)
|
|||||||
* Free coprocessor (if we have it).
|
* Free coprocessor (if we have it).
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
npxexit(td)
|
fpuexit(struct thread *td)
|
||||||
struct thread *td;
|
|
||||||
{
|
{
|
||||||
#ifdef NPX_DEBUG
|
|
||||||
u_int masked_exceptions;
|
|
||||||
#endif
|
|
||||||
register_t savecrit;
|
register_t savecrit;
|
||||||
|
|
||||||
savecrit = intr_disable();
|
savecrit = intr_disable();
|
||||||
if (curthread == PCPU_GET(fpcurthread))
|
if (curthread == PCPU_GET(fpcurthread))
|
||||||
npxsave(&PCPU_GET(curpcb)->pcb_save);
|
fpusave(&PCPU_GET(curpcb)->pcb_save);
|
||||||
intr_restore(savecrit);
|
intr_restore(savecrit);
|
||||||
#ifdef NPX_DEBUG
|
|
||||||
masked_exceptions = GET_FPU_CW(td) & GET_FPU_SW(td) & 0x7f;
|
|
||||||
/*
|
|
||||||
* Log exceptions that would have trapped with the old
|
|
||||||
* control word (overflow, divide by 0, and invalid operand).
|
|
||||||
*/
|
|
||||||
if (masked_exceptions & 0x0d)
|
|
||||||
log(LOG_ERR,
|
|
||||||
"pid %d (%s) exited with masked floating point exceptions 0x%02x\n",
|
|
||||||
td->td_proc->p_pid, td->td_proc->p_comm,
|
|
||||||
masked_exceptions);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
npxformat()
|
fpuformat()
|
||||||
{
|
{
|
||||||
|
|
||||||
return (_MC_FPFMT_XMM);
|
return (_MC_FPFMT_XMM);
|
||||||
@ -456,7 +426,7 @@ static char fpetable[128] = {
|
|||||||
* solution for signals other than SIGFPE.
|
* solution for signals other than SIGFPE.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
npxtrap()
|
fputrap()
|
||||||
{
|
{
|
||||||
register_t savecrit;
|
register_t savecrit;
|
||||||
u_short control, status;
|
u_short control, status;
|
||||||
@ -493,48 +463,48 @@ npxtrap()
|
|||||||
static int err_count = 0;
|
static int err_count = 0;
|
||||||
|
|
||||||
int
|
int
|
||||||
npxdna()
|
fpudna()
|
||||||
{
|
{
|
||||||
struct pcb *pcb;
|
struct pcb *pcb;
|
||||||
register_t s;
|
register_t s;
|
||||||
u_short control;
|
u_short control;
|
||||||
|
|
||||||
if (PCPU_GET(fpcurthread) == curthread) {
|
if (PCPU_GET(fpcurthread) == curthread) {
|
||||||
printf("npxdna: fpcurthread == curthread %d times\n",
|
printf("fpudna: fpcurthread == curthread %d times\n",
|
||||||
++err_count);
|
++err_count);
|
||||||
stop_emulating();
|
stop_emulating();
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
if (PCPU_GET(fpcurthread) != NULL) {
|
if (PCPU_GET(fpcurthread) != NULL) {
|
||||||
printf("npxdna: fpcurthread = %p (%d), curthread = %p (%d)\n",
|
printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n",
|
||||||
PCPU_GET(fpcurthread),
|
PCPU_GET(fpcurthread),
|
||||||
PCPU_GET(fpcurthread)->td_proc->p_pid,
|
PCPU_GET(fpcurthread)->td_proc->p_pid,
|
||||||
curthread, curthread->td_proc->p_pid);
|
curthread, curthread->td_proc->p_pid);
|
||||||
panic("npxdna");
|
panic("fpudna");
|
||||||
}
|
}
|
||||||
s = intr_disable();
|
s = intr_disable();
|
||||||
stop_emulating();
|
stop_emulating();
|
||||||
/*
|
/*
|
||||||
* Record new context early in case frstor causes an IRQ13.
|
* Record new context early in case frstor causes a trap.
|
||||||
*/
|
*/
|
||||||
PCPU_SET(fpcurthread, curthread);
|
PCPU_SET(fpcurthread, curthread);
|
||||||
pcb = PCPU_GET(curpcb);
|
pcb = PCPU_GET(curpcb);
|
||||||
|
|
||||||
if ((pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
|
if ((pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
|
||||||
/*
|
/*
|
||||||
* This is the first time this thread has used the FPU or
|
* This is the first time this thread has used the FPU or
|
||||||
* the PCB doesn't contain a clean FPU state. Explicitly
|
* the PCB doesn't contain a clean FPU state. Explicitly
|
||||||
* initialize the FPU and load the default control word.
|
* initialize the FPU and load the default control word.
|
||||||
*/
|
*/
|
||||||
fninit();
|
fninit();
|
||||||
control = __INITIAL_NPXCW__;
|
control = __INITIAL_FPUCW__;
|
||||||
fldcw(&control);
|
fldcw(&control);
|
||||||
pcb->pcb_flags |= PCB_NPXINITDONE;
|
pcb->pcb_flags |= PCB_FPUINITDONE;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* The following frstor may cause a trap when the state
|
* The following frstor may cause a trap when the state
|
||||||
* being restored has a pending error. The error will
|
* being restored has a pending error. The error will
|
||||||
* appear to have been triggered by the current (npx) user
|
* appear to have been triggered by the current (fpu) user
|
||||||
* instruction even when that instruction is a no-wait
|
* instruction even when that instruction is a no-wait
|
||||||
* instruction that should not trigger an error (e.g.,
|
* instruction that should not trigger an error (e.g.,
|
||||||
* instructions are broken the same as frstor, so our
|
* instructions are broken the same as frstor, so our
|
||||||
@ -548,36 +518,19 @@ npxdna()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wrapper for fnsave instruction, partly to handle hardware bugs. When npx
|
* Wrapper for fnsave instruction.
|
||||||
* 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 fpcurthread to NULL; it is
|
|
||||||
* normally retriggered in npxdna() after return to user mode.
|
|
||||||
*
|
*
|
||||||
* npxsave() must be called with interrupts disabled, so that it clears
|
* fpusave() must be called with interrupts disabled, so that it clears
|
||||||
* fpcurthread atomically with saving the state. We require callers to do the
|
* fpcurthread atomically with saving the state. We require callers to do the
|
||||||
* disabling, since most callers need to disable interrupts anyway to call
|
* disabling, since most callers need to disable interrupts anyway to call
|
||||||
* npxsave() atomically with checking fpcurthread.
|
* fpusave() atomically with checking fpcurthread.
|
||||||
*
|
|
||||||
* 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
|
void
|
||||||
npxsave(addr)
|
fpusave(struct savefpu *addr)
|
||||||
struct savefpu *addr;
|
|
||||||
{
|
{
|
||||||
|
|
||||||
stop_emulating();
|
stop_emulating();
|
||||||
fxsave(addr);
|
fxsave(addr);
|
||||||
|
|
||||||
start_emulating();
|
start_emulating();
|
||||||
PCPU_SET(fpcurthread, NULL);
|
PCPU_SET(fpcurthread, NULL);
|
||||||
}
|
}
|
||||||
@ -587,13 +540,13 @@ npxsave(addr)
|
|||||||
* FPU thread is non-null.
|
* FPU thread is non-null.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
npxdrop()
|
fpudrop()
|
||||||
{
|
{
|
||||||
struct thread *td;
|
struct thread *td;
|
||||||
|
|
||||||
td = PCPU_GET(fpcurthread);
|
td = PCPU_GET(fpcurthread);
|
||||||
PCPU_SET(fpcurthread, NULL);
|
PCPU_SET(fpcurthread, NULL);
|
||||||
td->td_pcb->pcb_flags &= ~PCB_NPXINITDONE;
|
td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE;
|
||||||
start_emulating();
|
start_emulating();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,15 +555,13 @@ npxdrop()
|
|||||||
* It returns the FPU ownership status.
|
* It returns the FPU ownership status.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
npxgetregs(td, addr)
|
fpugetregs(struct thread *td, struct savefpu *addr)
|
||||||
struct thread *td;
|
|
||||||
struct savefpu *addr;
|
|
||||||
{
|
{
|
||||||
register_t s;
|
register_t s;
|
||||||
|
|
||||||
if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
|
if ((td->td_pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
|
||||||
if (npx_cleanstate_ready)
|
if (fpu_cleanstate_ready)
|
||||||
bcopy(&npx_cleanstate, addr, sizeof(npx_cleanstate));
|
bcopy(&fpu_cleanstate, addr, sizeof(fpu_cleanstate));
|
||||||
else
|
else
|
||||||
bzero(addr, sizeof(*addr));
|
bzero(addr, sizeof(*addr));
|
||||||
return (_MC_FPOWNED_NONE);
|
return (_MC_FPOWNED_NONE);
|
||||||
@ -631,9 +582,7 @@ npxgetregs(td, addr)
|
|||||||
* Set the state of the FPU.
|
* Set the state of the FPU.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
npxsetregs(td, addr)
|
fpusetregs(struct thread *td, struct savefpu *addr)
|
||||||
struct thread *td;
|
|
||||||
struct savefpu *addr;
|
|
||||||
{
|
{
|
||||||
register_t s;
|
register_t s;
|
||||||
|
|
||||||
@ -645,14 +594,14 @@ npxsetregs(td, addr)
|
|||||||
intr_restore(s);
|
intr_restore(s);
|
||||||
bcopy(addr, &td->td_pcb->pcb_save, sizeof(*addr));
|
bcopy(addr, &td->td_pcb->pcb_save, sizeof(*addr));
|
||||||
}
|
}
|
||||||
curthread->td_pcb->pcb_flags |= PCB_NPXINITDONE;
|
curthread->td_pcb->pcb_flags |= PCB_FPUINITDONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static device_method_t npx_methods[] = {
|
static device_method_t fpu_methods[] = {
|
||||||
/* Device interface */
|
/* Device interface */
|
||||||
DEVMETHOD(device_identify, npx_identify),
|
DEVMETHOD(device_identify, fpu_identify),
|
||||||
DEVMETHOD(device_probe, npx_probe),
|
DEVMETHOD(device_probe, fpu_probe),
|
||||||
DEVMETHOD(device_attach, npx_attach),
|
DEVMETHOD(device_attach, fpu_attach),
|
||||||
DEVMETHOD(device_detach, bus_generic_detach),
|
DEVMETHOD(device_detach, bus_generic_detach),
|
||||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||||
@ -661,49 +610,51 @@ static device_method_t npx_methods[] = {
|
|||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static driver_t npx_driver = {
|
static driver_t fpu_driver = {
|
||||||
"npx",
|
"fpu",
|
||||||
npx_methods,
|
fpu_methods,
|
||||||
1, /* no softc */
|
1, /* no softc */
|
||||||
};
|
};
|
||||||
|
|
||||||
static devclass_t npx_devclass;
|
static devclass_t fpu_devclass;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We prefer to attach to the root nexus so that the usual case (exception 16)
|
* We prefer to attach to the root nexus so that the usual case (exception 16)
|
||||||
* doesn't describe the processor as being `on isa'.
|
* doesn't describe the processor as being `on isa'.
|
||||||
*/
|
*/
|
||||||
DRIVER_MODULE(npx, nexus, npx_driver, npx_devclass, 0, 0);
|
DRIVER_MODULE(fpu, nexus, fpu_driver, fpu_devclass, 0, 0);
|
||||||
|
|
||||||
#ifdef DEV_ISA
|
#ifdef DEV_ISA
|
||||||
/*
|
/*
|
||||||
* This sucks up the legacy ISA support assignments from PNPBIOS/ACPI.
|
* This sucks up the legacy ISA support assignments from PNPBIOS/ACPI.
|
||||||
*/
|
*/
|
||||||
static struct isa_pnp_id npxisa_ids[] = {
|
static struct isa_pnp_id fpuisa_ids[] = {
|
||||||
{ 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */
|
{ 0x040cd041, "Legacy ISA coprocessor support" }, /* PNP0C04 */
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
npxisa_probe(device_t dev)
|
fpuisa_probe(device_t dev)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, npxisa_ids)) <= 0) {
|
|
||||||
|
result = ISA_PNP_PROBE(device_get_parent(dev), dev, fpuisa_ids);
|
||||||
|
if (result <= 0)
|
||||||
device_quiet(dev);
|
device_quiet(dev);
|
||||||
}
|
return (result);
|
||||||
return(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
npxisa_attach(device_t dev)
|
fpuisa_attach(device_t dev)
|
||||||
{
|
{
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static device_method_t npxisa_methods[] = {
|
static device_method_t fpuisa_methods[] = {
|
||||||
/* Device interface */
|
/* Device interface */
|
||||||
DEVMETHOD(device_probe, npxisa_probe),
|
DEVMETHOD(device_probe, fpuisa_probe),
|
||||||
DEVMETHOD(device_attach, npxisa_attach),
|
DEVMETHOD(device_attach, fpuisa_attach),
|
||||||
DEVMETHOD(device_detach, bus_generic_detach),
|
DEVMETHOD(device_detach, bus_generic_detach),
|
||||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||||
@ -712,14 +663,14 @@ static device_method_t npxisa_methods[] = {
|
|||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static driver_t npxisa_driver = {
|
static driver_t fpuisa_driver = {
|
||||||
"npxisa",
|
"fpuisa",
|
||||||
npxisa_methods,
|
fpuisa_methods,
|
||||||
1, /* no softc */
|
1, /* no softc */
|
||||||
};
|
};
|
||||||
|
|
||||||
static devclass_t npxisa_devclass;
|
static devclass_t fpuisa_devclass;
|
||||||
|
|
||||||
DRIVER_MODULE(npxisa, isa, npxisa_driver, npxisa_devclass, 0, 0);
|
DRIVER_MODULE(fpuisa, isa, fpuisa_driver, fpuisa_devclass, 0, 0);
|
||||||
DRIVER_MODULE(npxisa, acpi, npxisa_driver, npxisa_devclass, 0, 0);
|
DRIVER_MODULE(fpuisa, acpi, fpuisa_driver, fpuisa_devclass, 0, 0);
|
||||||
#endif /* DEV_ISA */
|
#endif /* DEV_ISA */
|
||||||
|
@ -516,7 +516,6 @@ exec_setregs(td, entry, stack, ps_strings)
|
|||||||
|
|
||||||
bzero((char *)regs, sizeof(struct trapframe));
|
bzero((char *)regs, sizeof(struct trapframe));
|
||||||
regs->tf_rip = entry;
|
regs->tf_rip = entry;
|
||||||
/* This strangeness is to ensure alignment after the implied return address */
|
|
||||||
regs->tf_rsp = ((stack - 8) & ~0xF) + 8;
|
regs->tf_rsp = ((stack - 8) & ~0xF) + 8;
|
||||||
regs->tf_rdi = stack; /* argv */
|
regs->tf_rdi = stack; /* argv */
|
||||||
regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
|
regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
|
||||||
@ -524,20 +523,20 @@ exec_setregs(td, entry, stack, ps_strings)
|
|||||||
regs->tf_cs = _ucodesel;
|
regs->tf_cs = _ucodesel;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Arrange to trap the next npx or `fwait' instruction (see npx.c
|
* Arrange to trap the next fpu or `fwait' instruction (see fpu.c
|
||||||
* for why fwait must be trapped at least if there is an npx or an
|
* for why fwait must be trapped at least if there is an fpu or an
|
||||||
* emulator). This is mainly to handle the case where npx0 is not
|
* emulator). This is mainly to handle the case where npx0 is not
|
||||||
* configured, since the npx routines normally set up the trap
|
* configured, since the fpu routines normally set up the trap
|
||||||
* otherwise. It should be done only at boot time, but doing it
|
* otherwise. It should be done only at boot time, but doing it
|
||||||
* here allows modifying `npx_exists' for testing the emulator on
|
* here allows modifying `fpu_exists' for testing the emulator on
|
||||||
* systems with an npx.
|
* systems with an fpu.
|
||||||
*/
|
*/
|
||||||
load_cr0(rcr0() | CR0_MP | CR0_TS);
|
load_cr0(rcr0() | CR0_MP | CR0_TS);
|
||||||
|
|
||||||
/* Initialize the npx (if any) for the current process. */
|
/* Initialize the fpu (if any) for the current process. */
|
||||||
/*
|
/*
|
||||||
* XXX the above load_cr0() also initializes it and is a layering
|
* XXX the above load_cr0() also initializes it and is a layering
|
||||||
* violation if NPX is configured. It drops the npx partially
|
* violation. It drops the fpu state partially
|
||||||
* and this would be fatal if we were interrupted now, and decided
|
* and this would be fatal if we were interrupted now, and decided
|
||||||
* to force the state to the pcb, and checked the invariant
|
* to force the state to the pcb, and checked the invariant
|
||||||
* (CR0_TS clear) if and only if PCPU_GET(fpcurthread) != NULL).
|
* (CR0_TS clear) if and only if PCPU_GET(fpcurthread) != NULL).
|
||||||
@ -555,7 +554,7 @@ cpu_setregs(void)
|
|||||||
register_t cr0;
|
register_t cr0;
|
||||||
|
|
||||||
cr0 = rcr0();
|
cr0 = rcr0();
|
||||||
cr0 |= CR0_NE; /* Done by npxinit() */
|
cr0 |= CR0_NE; /* Done by fpuinit() */
|
||||||
cr0 |= CR0_MP | CR0_TS; /* Done at every execve() too. */
|
cr0 |= CR0_MP | CR0_TS; /* Done at every execve() too. */
|
||||||
cr0 |= CR0_WP | CR0_AM;
|
cr0 |= CR0_WP | CR0_AM;
|
||||||
load_cr0(cr0);
|
load_cr0(cr0);
|
||||||
@ -1525,8 +1524,8 @@ static void
|
|||||||
get_fpcontext(struct thread *td, mcontext_t *mcp)
|
get_fpcontext(struct thread *td, mcontext_t *mcp)
|
||||||
{
|
{
|
||||||
|
|
||||||
mcp->mc_ownedfp = npxgetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
mcp->mc_ownedfp = fpugetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
||||||
mcp->mc_fpformat = npxformat();
|
mcp->mc_fpformat = fpuformat();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1543,11 +1542,11 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp)
|
|||||||
else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
|
else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
|
||||||
mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
|
mcp->mc_ownedfp == _MC_FPOWNED_PCB) {
|
||||||
/*
|
/*
|
||||||
* XXX we violate the dubious requirement that npxsetregs()
|
* XXX we violate the dubious requirement that fpusetregs()
|
||||||
* be called with interrupts disabled.
|
* be called with interrupts disabled.
|
||||||
* XXX obsolete on trap-16 systems?
|
* XXX obsolete on trap-16 systems?
|
||||||
*/
|
*/
|
||||||
npxsetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
fpusetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
||||||
} else
|
} else
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
return (0);
|
return (0);
|
||||||
@ -1560,18 +1559,18 @@ fpstate_drop(struct thread *td)
|
|||||||
|
|
||||||
s = intr_disable();
|
s = intr_disable();
|
||||||
if (PCPU_GET(fpcurthread) == td)
|
if (PCPU_GET(fpcurthread) == td)
|
||||||
npxdrop();
|
fpudrop();
|
||||||
/*
|
/*
|
||||||
* XXX force a full drop of the npx. The above only drops it if we
|
* XXX force a full drop of the fpu. The above only drops it if we
|
||||||
* owned it.
|
* owned it.
|
||||||
*
|
*
|
||||||
* XXX I don't much like npxgetregs()'s semantics of doing a full
|
* XXX I don't much like fpugetregs()'s semantics of doing a full
|
||||||
* drop. Dropping only to the pcb matches fnsave's behaviour.
|
* drop. Dropping only to the pcb matches fnsave's behaviour.
|
||||||
* We only need to drop to !PCB_INITDONE in sendsig(). But
|
* We only need to drop to !PCB_INITDONE in sendsig(). But
|
||||||
* sendsig() is the only caller of npxgetregs()... perhaps we just
|
* sendsig() is the only caller of fpugetregs()... perhaps we just
|
||||||
* have too many layers.
|
* have too many layers.
|
||||||
*/
|
*/
|
||||||
curthread->td_pcb->pcb_flags &= ~PCB_NPXINITDONE;
|
curthread->td_pcb->pcb_flags &= ~PCB_FPUINITDONE;
|
||||||
intr_restore(s);
|
intr_restore(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,7 +268,6 @@ nexus_add_child(device_t bus, int order, const char *name, int unit)
|
|||||||
/*
|
/*
|
||||||
* Allocate a resource on behalf of child. NB: child is usually going to be a
|
* Allocate a resource on behalf of child. NB: child is usually going to be a
|
||||||
* child of one of our descendants, not a direct child of nexus0.
|
* child of one of our descendants, not a direct child of nexus0.
|
||||||
* (Exceptions include npx.)
|
|
||||||
*/
|
*/
|
||||||
static struct resource *
|
static struct resource *
|
||||||
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||||
|
@ -244,7 +244,7 @@ trap(frame)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_ARITHTRAP: /* arithmetic trap */
|
case T_ARITHTRAP: /* arithmetic trap */
|
||||||
ucode = npxtrap();
|
ucode = fputrap();
|
||||||
if (ucode == -1)
|
if (ucode == -1)
|
||||||
goto userout;
|
goto userout;
|
||||||
i = SIGFPE;
|
i = SIGFPE;
|
||||||
@ -310,7 +310,7 @@ trap(frame)
|
|||||||
|
|
||||||
case T_DNA:
|
case T_DNA:
|
||||||
/* transparent fault (due to context switch "late") */
|
/* transparent fault (due to context switch "late") */
|
||||||
if (npxdna())
|
if (fpudna())
|
||||||
goto userout;
|
goto userout;
|
||||||
i = SIGFPE;
|
i = SIGFPE;
|
||||||
ucode = FPE_FPU_NP_TRAP;
|
ucode = FPE_FPU_NP_TRAP;
|
||||||
@ -338,12 +338,12 @@ trap(frame)
|
|||||||
|
|
||||||
case T_DNA:
|
case T_DNA:
|
||||||
/*
|
/*
|
||||||
* The kernel is apparently using npx for copying.
|
* The kernel is apparently using fpu for copying.
|
||||||
* XXX this should be fatal unless the kernel has
|
* XXX this should be fatal unless the kernel has
|
||||||
* registered such use.
|
* registered such use.
|
||||||
*/
|
*/
|
||||||
if (npxdna()) {
|
if (fpudna()) {
|
||||||
printf("npxdna in kernel mode!\n");
|
printf("fpudna in kernel mode!\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -118,7 +118,7 @@ cpu_fork(td1, p2, td2, flags)
|
|||||||
/* Ensure that p1's pcb is up to date. */
|
/* Ensure that p1's pcb is up to date. */
|
||||||
savecrit = intr_disable();
|
savecrit = intr_disable();
|
||||||
if (PCPU_GET(fpcurthread) == td1)
|
if (PCPU_GET(fpcurthread) == td1)
|
||||||
npxsave(&td1->td_pcb->pcb_save);
|
fpusave(&td1->td_pcb->pcb_save);
|
||||||
intr_restore(savecrit);
|
intr_restore(savecrit);
|
||||||
|
|
||||||
/* Point the pcb to the top of the stack */
|
/* Point the pcb to the top of the stack */
|
||||||
@ -206,7 +206,7 @@ cpu_thread_exit(struct thread *td)
|
|||||||
{
|
{
|
||||||
|
|
||||||
if (td == PCPU_GET(fpcurthread))
|
if (td == PCPU_GET(fpcurthread))
|
||||||
npxdrop();
|
fpudrop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -266,7 +266,7 @@ cpu_set_upcall(struct thread *td, struct thread *td0)
|
|||||||
* more analysis) (need a good safe default).
|
* more analysis) (need a good safe default).
|
||||||
*/
|
*/
|
||||||
bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
|
bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
|
||||||
pcb2->pcb_flags &= ~PCB_NPXINITDONE;
|
pcb2->pcb_flags &= ~PCB_FPUINITDONE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new fresh stack for the new thread.
|
* Create a new fresh stack for the new thread.
|
||||||
|
@ -91,7 +91,6 @@
|
|||||||
sub ("IO_LPT3", "0x3BC", val);
|
sub ("IO_LPT3", "0x3BC", val);
|
||||||
sub ("IO_MDA", "0x3B0", val);
|
sub ("IO_MDA", "0x3B0", val);
|
||||||
sub ("IO_NMI", "0x070", val);
|
sub ("IO_NMI", "0x070", val);
|
||||||
sub ("IO_NPX", "0x0F0", val);
|
|
||||||
sub ("IO_PMP1", "0x026", val);
|
sub ("IO_PMP1", "0x026", val);
|
||||||
sub ("IO_PMP2", "0x178", val);
|
sub ("IO_PMP2", "0x178", val);
|
||||||
sub ("IO_PPI", "0x061", val);
|
sub ("IO_PPI", "0x061", val);
|
||||||
|
@ -108,7 +108,7 @@ ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp)
|
|||||||
*
|
*
|
||||||
* XXX unpessimize most cases by only aligning when fxsave might be
|
* XXX unpessimize most cases by only aligning when fxsave might be
|
||||||
* called, although this requires knowing too much about
|
* called, although this requires knowing too much about
|
||||||
* npxgetregs()'s internals.
|
* fpugetregs()'s internals.
|
||||||
*/
|
*/
|
||||||
addr = (struct savefpu *)&mcp->mc_fpstate;
|
addr = (struct savefpu *)&mcp->mc_fpstate;
|
||||||
if (td == PCPU_GET(fpcurthread) && ((uintptr_t)(void *)addr & 0xF)) {
|
if (td == PCPU_GET(fpcurthread) && ((uintptr_t)(void *)addr & 0xF)) {
|
||||||
@ -116,12 +116,12 @@ ia32_get_fpcontext(struct thread *td, struct ia32_mcontext *mcp)
|
|||||||
addr = (void *)((char *)addr + 4);
|
addr = (void *)((char *)addr + 4);
|
||||||
while ((uintptr_t)(void *)addr & 0xF);
|
while ((uintptr_t)(void *)addr & 0xF);
|
||||||
}
|
}
|
||||||
mcp->mc_ownedfp = npxgetregs(td, addr);
|
mcp->mc_ownedfp = fpugetregs(td, addr);
|
||||||
if (addr != (struct savefpu *)&mcp->mc_fpstate) {
|
if (addr != (struct savefpu *)&mcp->mc_fpstate) {
|
||||||
bcopy(addr, &mcp->mc_fpstate, sizeof(mcp->mc_fpstate));
|
bcopy(addr, &mcp->mc_fpstate, sizeof(mcp->mc_fpstate));
|
||||||
bzero(&mcp->mc_spare2, sizeof(mcp->mc_spare2));
|
bzero(&mcp->mc_spare2, sizeof(mcp->mc_spare2));
|
||||||
}
|
}
|
||||||
mcp->mc_fpformat = npxformat();
|
mcp->mc_fpformat = fpuformat();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -148,10 +148,10 @@ ia32_set_fpcontext(struct thread *td, const struct ia32_mcontext *mcp)
|
|||||||
bcopy(&mcp->mc_fpstate, addr, sizeof(mcp->mc_fpstate));
|
bcopy(&mcp->mc_fpstate, addr, sizeof(mcp->mc_fpstate));
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* XXX we violate the dubious requirement that npxsetregs()
|
* XXX we violate the dubious requirement that fpusetregs()
|
||||||
* be called with interrupts disabled.
|
* be called with interrupts disabled.
|
||||||
*/
|
*/
|
||||||
npxsetregs(td, addr);
|
fpusetregs(td, addr);
|
||||||
/*
|
/*
|
||||||
* Don't bother putting things back where they were in the
|
* Don't bother putting things back where they were in the
|
||||||
* misaligned case, since we know that the caller won't use
|
* misaligned case, since we know that the caller won't use
|
||||||
|
@ -38,12 +38,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 287/387 NPX Coprocessor Data Structures and Constants
|
* Floating Point Data Structures and Constants
|
||||||
* W. Jolitz 1/90
|
* W. Jolitz 1/90
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _MACHINE_NPX_H_
|
#ifndef _MACHINE_FPU_H_
|
||||||
#define _MACHINE_NPX_H_
|
#define _MACHINE_FPU_H_
|
||||||
|
|
||||||
/* Contents of each x87 floating point accumulator */
|
/* Contents of each x87 floating point accumulator */
|
||||||
struct fpacc87 {
|
struct fpacc87 {
|
||||||
@ -95,20 +95,20 @@ struct savefpu {
|
|||||||
* This is mostly academic for AMD64, because the ABI prefers the use
|
* This is mostly academic for AMD64, because the ABI prefers the use
|
||||||
* SSE2 based math. For FreeBSD/amd64, we go with the default settings.
|
* SSE2 based math. For FreeBSD/amd64, we go with the default settings.
|
||||||
*/
|
*/
|
||||||
#define __INITIAL_NPXCW__ 0x037F
|
#define __INITIAL_FPUCW__ 0x037F
|
||||||
#define __INITIAL_MXCSR__ 0x1F80
|
#define __INITIAL_MXCSR__ 0x1F80
|
||||||
#define __INITIAL_MXCSR_MASK__ 0xFFBF
|
#define __INITIAL_MXCSR_MASK__ 0xFFBF
|
||||||
|
|
||||||
#ifdef _KERNEL
|
#ifdef _KERNEL
|
||||||
int npxdna(void);
|
int fpudna(void);
|
||||||
void npxdrop(void);
|
void fpudrop(void);
|
||||||
void npxexit(struct thread *td);
|
void fpuexit(struct thread *td);
|
||||||
int npxformat(void);
|
int fpuformat(void);
|
||||||
int npxgetregs(struct thread *td, struct savefpu *addr);
|
int fpugetregs(struct thread *td, struct savefpu *addr);
|
||||||
void npxinit(u_short control);
|
void fpuinit(u_short control);
|
||||||
void npxsave(struct savefpu *addr);
|
void fpusave(struct savefpu *addr);
|
||||||
void npxsetregs(struct thread *td, struct savefpu *addr);
|
void fpusetregs(struct thread *td, struct savefpu *addr);
|
||||||
int npxtrap(void);
|
int fputrap(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* !_MACHINE_NPX_H_ */
|
#endif /* !_MACHINE_FPU_H_ */
|
||||||
|
@ -66,7 +66,7 @@ struct pcb {
|
|||||||
|
|
||||||
struct savefpu pcb_save;
|
struct savefpu pcb_save;
|
||||||
u_long pcb_flags;
|
u_long pcb_flags;
|
||||||
#define PCB_NPXINITDONE 0x01 /* fpu state is initialized */
|
#define PCB_FPUINITDONE 0x01 /* fpu state is initialized */
|
||||||
#define PCB_FULLCTX 0x02 /* full context restore on sysret */
|
#define PCB_FULLCTX 0x02 /* full context restore on sysret */
|
||||||
|
|
||||||
caddr_t pcb_onfault; /* copyin/out fault recovery */
|
caddr_t pcb_onfault; /* copyin/out fault recovery */
|
||||||
|
@ -41,12 +41,9 @@
|
|||||||
* Bits in 386 special registers:
|
* Bits in 386 special registers:
|
||||||
*/
|
*/
|
||||||
#define CR0_PE 0x00000001 /* Protected mode Enable */
|
#define CR0_PE 0x00000001 /* Protected mode Enable */
|
||||||
#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */
|
#define CR0_MP 0x00000002 /* "Math" (fpu) Present */
|
||||||
#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */
|
#define CR0_EM 0x00000004 /* EMulate FPU instructions. (trap ESC only) */
|
||||||
#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */
|
#define CR0_TS 0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */
|
||||||
#ifdef notused
|
|
||||||
#define CR0_ET 0x00000010 /* Extension Type (387 (if set) vs 287) */
|
|
||||||
#endif
|
|
||||||
#define CR0_PG 0x80000000 /* PaGing enable */
|
#define CR0_PG 0x80000000 /* PaGing enable */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -33,7 +33,7 @@ eintrnames:
|
|||||||
*
|
*
|
||||||
* XXX - the interrupt frame is set up to look like a trap frame. This is
|
* XXX - the interrupt frame is set up to look like a trap frame. This is
|
||||||
* usually a waste of time. The only interrupt handlers that want a frame
|
* usually a waste of time. The only interrupt handlers that want a frame
|
||||||
* are the clock handler (it wants a clock frame), the npx handler (it's
|
* are the clock handler (it wants a clock frame), the fpu handler (it's
|
||||||
* easier to do right all in assembler). The interrupt return routine
|
* easier to do right all in assembler). The interrupt return routine
|
||||||
* needs a trap frame for rare AST's (it could easily convert the frame).
|
* needs a trap frame for rare AST's (it could easily convert the frame).
|
||||||
* The direct costs of setting up a trap frame are two pushl's (error
|
* The direct costs of setting up a trap frame are two pushl's (error
|
||||||
@ -42,7 +42,7 @@ eintrnames:
|
|||||||
* costs are making the driver interface nonuniform so unpending of
|
* costs are making the driver interface nonuniform so unpending of
|
||||||
* interrupts is more complicated and slower (call_driver(unit) would
|
* interrupts is more complicated and slower (call_driver(unit) would
|
||||||
* be easier than ensuring an interrupt frame for all handlers. Finally,
|
* be easier than ensuring an interrupt frame for all handlers. Finally,
|
||||||
* there are some struct copies in the npx handler and maybe in the clock
|
* there are some struct copies in the fpu handler and maybe in the clock
|
||||||
* handler that could be avoided by working more with pointers to frames
|
* handler that could be avoided by working more with pointers to frames
|
||||||
* instead of frames.
|
* instead of frames.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user