The great s/npx/fpu/gi
This commit is contained in:
parent
d0ff2e64ac
commit
bf2f09ee97
@ -131,7 +131,7 @@ ENTRY(cpu_switch)
|
||||
pushq %rsi
|
||||
addq $PCB_SAVEFPU,%r8 /* h/w bugs make saving complicated */
|
||||
movq %r8, %rdi
|
||||
call npxsave /* do it in a big C function */
|
||||
call fpusave /* do it in a big C function */
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
1:
|
||||
@ -301,16 +301,16 @@ ENTRY(savectx)
|
||||
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
|
||||
* 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).
|
||||
*
|
||||
* 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
|
||||
* requested pcb and reload. Copying is easier because we would
|
||||
* 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
|
||||
cli
|
||||
@ -322,7 +322,7 @@ ENTRY(savectx)
|
||||
pushq %rax
|
||||
movq TD_PCB(%rax),%rdi
|
||||
leaq PCB_SAVEFPU(%rdi),%rdi
|
||||
call npxsave
|
||||
call fpusave
|
||||
popq %rax
|
||||
popq %rcx
|
||||
|
||||
|
@ -37,7 +37,6 @@
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_debug_npx.h"
|
||||
#include "opt_isa.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -53,9 +52,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sysctl.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/rman.h>
|
||||
#ifdef NPX_DEBUG
|
||||
#include <sys/syslog.h>
|
||||
#endif
|
||||
#include <sys/signalvar.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
@ -75,7 +71,7 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 387 and 287 Numeric Coprocessor Extension (NPX) Driver.
|
||||
* Floating point support.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && !defined(lint)
|
||||
@ -110,59 +106,50 @@ void stop_emulating(void);
|
||||
|
||||
typedef u_char bool_t;
|
||||
|
||||
static int npx_attach(device_t dev);
|
||||
static void npx_identify(driver_t *driver, device_t parent);
|
||||
static int npx_probe(device_t dev);
|
||||
static int fpu_attach(device_t dev);
|
||||
static void fpu_identify(driver_t *driver, device_t parent);
|
||||
static int fpu_probe(device_t dev);
|
||||
|
||||
int hw_float = 1;
|
||||
SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
|
||||
CTLFLAG_RD, &hw_float, 0,
|
||||
"Floatingpoint instructions executed in hardware");
|
||||
|
||||
static struct savefpu npx_cleanstate;
|
||||
static bool_t npx_cleanstate_ready;
|
||||
static struct savefpu fpu_cleanstate;
|
||||
static bool_t fpu_cleanstate_ready;
|
||||
|
||||
/*
|
||||
* Identify routine. Create a connection point on our parent for probing.
|
||||
*/
|
||||
static void
|
||||
npx_identify(driver, parent)
|
||||
driver_t *driver;
|
||||
device_t parent;
|
||||
fpu_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
device_t child;
|
||||
|
||||
child = BUS_ADD_CHILD(parent, 0, "npx", 0);
|
||||
child = BUS_ADD_CHILD(parent, 0, "fpu", 0);
|
||||
if (child == NULL)
|
||||
panic("npx_identify");
|
||||
panic("fpu_identify");
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe routine. Initialize cr0 to give correct behaviour for [f]wait
|
||||
* 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.
|
||||
*/
|
||||
static int
|
||||
npx_probe(dev)
|
||||
device_t dev;
|
||||
fpu_probe(device_t dev)
|
||||
{
|
||||
|
||||
/*
|
||||
* Partially reset the coprocessor, if any. Some BIOS's don't reset
|
||||
* 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
|
||||
* Prepare to trap all ESC (i.e., FPU) instructions and all WAIT
|
||||
* 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
|
||||
* not cause WAIT instructions to trap. It's important to trap
|
||||
* WAIT instructions - otherwise the "wait" variants of no-wait
|
||||
* control instructions would degenerate to the "no-wait" variants
|
||||
* 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.
|
||||
*
|
||||
* Try setting CR0_NE to get correct error reporting on 486DX's.
|
||||
@ -179,6 +166,7 @@ npx_probe(dev)
|
||||
fninit();
|
||||
|
||||
device_set_desc(dev, "math processor");
|
||||
device_quiet(dev);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -187,19 +175,18 @@ npx_probe(dev)
|
||||
* Attach routine - announce which it is, and wire into system
|
||||
*/
|
||||
static int
|
||||
npx_attach(dev)
|
||||
device_t dev;
|
||||
fpu_attach(device_t dev)
|
||||
{
|
||||
register_t s;
|
||||
|
||||
npxinit(__INITIAL_NPXCW__);
|
||||
fpuinit(__INITIAL_FPUCW__);
|
||||
|
||||
if (npx_cleanstate_ready == 0) {
|
||||
if (fpu_cleanstate_ready == 0) {
|
||||
s = intr_disable();
|
||||
stop_emulating();
|
||||
fxsave(&npx_cleanstate);
|
||||
fxsave(&fpu_cleanstate);
|
||||
start_emulating();
|
||||
npx_cleanstate_ready = 1;
|
||||
fpu_cleanstate_ready = 1;
|
||||
intr_restore(s);
|
||||
}
|
||||
return (0); /* XXX unused */
|
||||
@ -209,21 +196,20 @@ npx_attach(dev)
|
||||
* Initialize floating point unit.
|
||||
*/
|
||||
void
|
||||
npxinit(control)
|
||||
u_short control;
|
||||
fpuinit(u_short control)
|
||||
{
|
||||
static struct savefpu dummy;
|
||||
register_t savecrit;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
savecrit = intr_disable();
|
||||
npxsave(&dummy);
|
||||
fpusave(&dummy);
|
||||
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();
|
||||
fldcw(&control);
|
||||
start_emulating();
|
||||
@ -234,34 +220,18 @@ npxinit(control)
|
||||
* Free coprocessor (if we have it).
|
||||
*/
|
||||
void
|
||||
npxexit(td)
|
||||
struct thread *td;
|
||||
fpuexit(struct thread *td)
|
||||
{
|
||||
#ifdef NPX_DEBUG
|
||||
u_int masked_exceptions;
|
||||
#endif
|
||||
register_t savecrit;
|
||||
|
||||
savecrit = intr_disable();
|
||||
if (curthread == PCPU_GET(fpcurthread))
|
||||
npxsave(&PCPU_GET(curpcb)->pcb_save);
|
||||
fpusave(&PCPU_GET(curpcb)->pcb_save);
|
||||
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
|
||||
npxformat()
|
||||
fpuformat()
|
||||
{
|
||||
|
||||
return (_MC_FPFMT_XMM);
|
||||
@ -456,7 +426,7 @@ static char fpetable[128] = {
|
||||
* solution for signals other than SIGFPE.
|
||||
*/
|
||||
int
|
||||
npxtrap()
|
||||
fputrap()
|
||||
{
|
||||
register_t savecrit;
|
||||
u_short control, status;
|
||||
@ -493,48 +463,48 @@ npxtrap()
|
||||
static int err_count = 0;
|
||||
|
||||
int
|
||||
npxdna()
|
||||
fpudna()
|
||||
{
|
||||
struct pcb *pcb;
|
||||
register_t s;
|
||||
u_short control;
|
||||
|
||||
if (PCPU_GET(fpcurthread) == curthread) {
|
||||
printf("npxdna: fpcurthread == curthread %d times\n",
|
||||
printf("fpudna: fpcurthread == curthread %d times\n",
|
||||
++err_count);
|
||||
stop_emulating();
|
||||
return (1);
|
||||
}
|
||||
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)->td_proc->p_pid,
|
||||
curthread, curthread->td_proc->p_pid);
|
||||
panic("npxdna");
|
||||
panic("fpudna");
|
||||
}
|
||||
s = intr_disable();
|
||||
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);
|
||||
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
|
||||
* the PCB doesn't contain a clean FPU state. Explicitly
|
||||
* initialize the FPU and load the default control word.
|
||||
*/
|
||||
fninit();
|
||||
control = __INITIAL_NPXCW__;
|
||||
control = __INITIAL_FPUCW__;
|
||||
fldcw(&control);
|
||||
pcb->pcb_flags |= PCB_NPXINITDONE;
|
||||
pcb->pcb_flags |= PCB_FPUINITDONE;
|
||||
} else {
|
||||
/*
|
||||
* The following frstor may cause a trap when the state
|
||||
* 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 that should not trigger an error (e.g.,
|
||||
* 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
|
||||
* 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.
|
||||
* Wrapper for fnsave instruction.
|
||||
*
|
||||
* 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
|
||||
* disabling, since most callers need to disable interrupts anyway to call
|
||||
* npxsave() 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.
|
||||
* fpusave() atomically with checking fpcurthread.
|
||||
*/
|
||||
void
|
||||
npxsave(addr)
|
||||
struct savefpu *addr;
|
||||
fpusave(struct savefpu *addr)
|
||||
{
|
||||
|
||||
stop_emulating();
|
||||
fxsave(addr);
|
||||
|
||||
start_emulating();
|
||||
PCPU_SET(fpcurthread, NULL);
|
||||
}
|
||||
@ -587,13 +540,13 @@ npxsave(addr)
|
||||
* FPU thread is non-null.
|
||||
*/
|
||||
void
|
||||
npxdrop()
|
||||
fpudrop()
|
||||
{
|
||||
struct thread *td;
|
||||
|
||||
td = PCPU_GET(fpcurthread);
|
||||
PCPU_SET(fpcurthread, NULL);
|
||||
td->td_pcb->pcb_flags &= ~PCB_NPXINITDONE;
|
||||
td->td_pcb->pcb_flags &= ~PCB_FPUINITDONE;
|
||||
start_emulating();
|
||||
}
|
||||
|
||||
@ -602,15 +555,13 @@ npxdrop()
|
||||
* It returns the FPU ownership status.
|
||||
*/
|
||||
int
|
||||
npxgetregs(td, addr)
|
||||
struct thread *td;
|
||||
struct savefpu *addr;
|
||||
fpugetregs(struct thread *td, struct savefpu *addr)
|
||||
{
|
||||
register_t s;
|
||||
|
||||
if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
|
||||
if (npx_cleanstate_ready)
|
||||
bcopy(&npx_cleanstate, addr, sizeof(npx_cleanstate));
|
||||
if ((td->td_pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
|
||||
if (fpu_cleanstate_ready)
|
||||
bcopy(&fpu_cleanstate, addr, sizeof(fpu_cleanstate));
|
||||
else
|
||||
bzero(addr, sizeof(*addr));
|
||||
return (_MC_FPOWNED_NONE);
|
||||
@ -631,9 +582,7 @@ npxgetregs(td, addr)
|
||||
* Set the state of the FPU.
|
||||
*/
|
||||
void
|
||||
npxsetregs(td, addr)
|
||||
struct thread *td;
|
||||
struct savefpu *addr;
|
||||
fpusetregs(struct thread *td, struct savefpu *addr)
|
||||
{
|
||||
register_t s;
|
||||
|
||||
@ -645,14 +594,14 @@ npxsetregs(td, addr)
|
||||
intr_restore(s);
|
||||
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 */
|
||||
DEVMETHOD(device_identify, npx_identify),
|
||||
DEVMETHOD(device_probe, npx_probe),
|
||||
DEVMETHOD(device_attach, npx_attach),
|
||||
DEVMETHOD(device_identify, fpu_identify),
|
||||
DEVMETHOD(device_probe, fpu_probe),
|
||||
DEVMETHOD(device_attach, fpu_attach),
|
||||
DEVMETHOD(device_detach, bus_generic_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
@ -661,49 +610,51 @@ static device_method_t npx_methods[] = {
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t npx_driver = {
|
||||
"npx",
|
||||
npx_methods,
|
||||
static driver_t fpu_driver = {
|
||||
"fpu",
|
||||
fpu_methods,
|
||||
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)
|
||||
* 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
|
||||
/*
|
||||
* 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 */
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static int
|
||||
npxisa_probe(device_t dev)
|
||||
fpuisa_probe(device_t dev)
|
||||
{
|
||||
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);
|
||||
}
|
||||
return(result);
|
||||
return (result);
|
||||
}
|
||||
|
||||
static int
|
||||
npxisa_attach(device_t dev)
|
||||
fpuisa_attach(device_t dev)
|
||||
{
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static device_method_t npxisa_methods[] = {
|
||||
static device_method_t fpuisa_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, npxisa_probe),
|
||||
DEVMETHOD(device_attach, npxisa_attach),
|
||||
DEVMETHOD(device_probe, fpuisa_probe),
|
||||
DEVMETHOD(device_attach, fpuisa_attach),
|
||||
DEVMETHOD(device_detach, bus_generic_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
@ -712,14 +663,14 @@ static device_method_t npxisa_methods[] = {
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t npxisa_driver = {
|
||||
"npxisa",
|
||||
npxisa_methods,
|
||||
static driver_t fpuisa_driver = {
|
||||
"fpuisa",
|
||||
fpuisa_methods,
|
||||
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(npxisa, acpi, npxisa_driver, npxisa_devclass, 0, 0);
|
||||
DRIVER_MODULE(fpuisa, isa, fpuisa_driver, fpuisa_devclass, 0, 0);
|
||||
DRIVER_MODULE(fpuisa, acpi, fpuisa_driver, fpuisa_devclass, 0, 0);
|
||||
#endif /* DEV_ISA */
|
||||
|
@ -516,7 +516,6 @@ exec_setregs(td, entry, stack, ps_strings)
|
||||
|
||||
bzero((char *)regs, sizeof(struct trapframe));
|
||||
regs->tf_rip = entry;
|
||||
/* This strangeness is to ensure alignment after the implied return address */
|
||||
regs->tf_rsp = ((stack - 8) & ~0xF) + 8;
|
||||
regs->tf_rdi = stack; /* argv */
|
||||
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;
|
||||
|
||||
/*
|
||||
* Arrange to trap the next npx or `fwait' instruction (see npx.c
|
||||
* for why fwait must be trapped at least if there is an npx or an
|
||||
* Arrange to trap the next fpu or `fwait' instruction (see fpu.c
|
||||
* 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
|
||||
* 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
|
||||
* here allows modifying `npx_exists' for testing the emulator on
|
||||
* systems with an npx.
|
||||
* here allows modifying `fpu_exists' for testing the emulator on
|
||||
* systems with an fpu.
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
* to force the state to the pcb, and checked the invariant
|
||||
* (CR0_TS clear) if and only if PCPU_GET(fpcurthread) != NULL).
|
||||
@ -555,7 +554,7 @@ cpu_setregs(void)
|
||||
register_t cr0;
|
||||
|
||||
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_WP | CR0_AM;
|
||||
load_cr0(cr0);
|
||||
@ -1525,8 +1524,8 @@ static void
|
||||
get_fpcontext(struct thread *td, mcontext_t *mcp)
|
||||
{
|
||||
|
||||
mcp->mc_ownedfp = npxgetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
||||
mcp->mc_fpformat = npxformat();
|
||||
mcp->mc_ownedfp = fpugetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
||||
mcp->mc_fpformat = fpuformat();
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1543,11 +1542,11 @@ set_fpcontext(struct thread *td, const mcontext_t *mcp)
|
||||
else if (mcp->mc_ownedfp == _MC_FPOWNED_FPU ||
|
||||
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.
|
||||
* XXX obsolete on trap-16 systems?
|
||||
*/
|
||||
npxsetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
||||
fpusetregs(td, (struct savefpu *)&mcp->mc_fpstate);
|
||||
} else
|
||||
return (EINVAL);
|
||||
return (0);
|
||||
@ -1560,18 +1559,18 @@ fpstate_drop(struct thread *td)
|
||||
|
||||
s = intr_disable();
|
||||
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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
curthread->td_pcb->pcb_flags &= ~PCB_NPXINITDONE;
|
||||
curthread->td_pcb->pcb_flags &= ~PCB_FPUINITDONE;
|
||||
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
|
||||
* child of one of our descendants, not a direct child of nexus0.
|
||||
* (Exceptions include npx.)
|
||||
*/
|
||||
static struct resource *
|
||||
nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
|
||||
|
@ -244,7 +244,7 @@ trap(frame)
|
||||
break;
|
||||
|
||||
case T_ARITHTRAP: /* arithmetic trap */
|
||||
ucode = npxtrap();
|
||||
ucode = fputrap();
|
||||
if (ucode == -1)
|
||||
goto userout;
|
||||
i = SIGFPE;
|
||||
@ -310,7 +310,7 @@ trap(frame)
|
||||
|
||||
case T_DNA:
|
||||
/* transparent fault (due to context switch "late") */
|
||||
if (npxdna())
|
||||
if (fpudna())
|
||||
goto userout;
|
||||
i = SIGFPE;
|
||||
ucode = FPE_FPU_NP_TRAP;
|
||||
@ -338,12 +338,12 @@ trap(frame)
|
||||
|
||||
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
|
||||
* registered such use.
|
||||
*/
|
||||
if (npxdna()) {
|
||||
printf("npxdna in kernel mode!\n");
|
||||
if (fpudna()) {
|
||||
printf("fpudna in kernel mode!\n");
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
@ -118,7 +118,7 @@ cpu_fork(td1, p2, td2, flags)
|
||||
/* Ensure that p1's pcb is up to date. */
|
||||
savecrit = intr_disable();
|
||||
if (PCPU_GET(fpcurthread) == td1)
|
||||
npxsave(&td1->td_pcb->pcb_save);
|
||||
fpusave(&td1->td_pcb->pcb_save);
|
||||
intr_restore(savecrit);
|
||||
|
||||
/* Point the pcb to the top of the stack */
|
||||
@ -206,7 +206,7 @@ cpu_thread_exit(struct thread *td)
|
||||
{
|
||||
|
||||
if (td == PCPU_GET(fpcurthread))
|
||||
npxdrop();
|
||||
fpudrop();
|
||||
}
|
||||
|
||||
void
|
||||
@ -266,7 +266,7 @@ cpu_set_upcall(struct thread *td, struct thread *td0)
|
||||
* more analysis) (need a good safe default).
|
||||
*/
|
||||
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.
|
||||
|
@ -91,7 +91,6 @@
|
||||
sub ("IO_LPT3", "0x3BC", val);
|
||||
sub ("IO_MDA", "0x3B0", val);
|
||||
sub ("IO_NMI", "0x070", val);
|
||||
sub ("IO_NPX", "0x0F0", val);
|
||||
sub ("IO_PMP1", "0x026", val);
|
||||
sub ("IO_PMP2", "0x178", 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
|
||||
* called, although this requires knowing too much about
|
||||
* npxgetregs()'s internals.
|
||||
* fpugetregs()'s internals.
|
||||
*/
|
||||
addr = (struct savefpu *)&mcp->mc_fpstate;
|
||||
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);
|
||||
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) {
|
||||
bcopy(addr, &mcp->mc_fpstate, sizeof(mcp->mc_fpstate));
|
||||
bzero(&mcp->mc_spare2, sizeof(mcp->mc_spare2));
|
||||
}
|
||||
mcp->mc_fpformat = npxformat();
|
||||
mcp->mc_fpformat = fpuformat();
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
/*
|
||||
* XXX we violate the dubious requirement that npxsetregs()
|
||||
* XXX we violate the dubious requirement that fpusetregs()
|
||||
* be called with interrupts disabled.
|
||||
*/
|
||||
npxsetregs(td, addr);
|
||||
fpusetregs(td, addr);
|
||||
/*
|
||||
* Don't bother putting things back where they were in the
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef _MACHINE_NPX_H_
|
||||
#define _MACHINE_NPX_H_
|
||||
#ifndef _MACHINE_FPU_H_
|
||||
#define _MACHINE_FPU_H_
|
||||
|
||||
/* Contents of each x87 floating point accumulator */
|
||||
struct fpacc87 {
|
||||
@ -95,20 +95,20 @@ struct savefpu {
|
||||
* This is mostly academic for AMD64, because the ABI prefers the use
|
||||
* 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_MASK__ 0xFFBF
|
||||
|
||||
#ifdef _KERNEL
|
||||
int npxdna(void);
|
||||
void npxdrop(void);
|
||||
void npxexit(struct thread *td);
|
||||
int npxformat(void);
|
||||
int npxgetregs(struct thread *td, struct savefpu *addr);
|
||||
void npxinit(u_short control);
|
||||
void npxsave(struct savefpu *addr);
|
||||
void npxsetregs(struct thread *td, struct savefpu *addr);
|
||||
int npxtrap(void);
|
||||
int fpudna(void);
|
||||
void fpudrop(void);
|
||||
void fpuexit(struct thread *td);
|
||||
int fpuformat(void);
|
||||
int fpugetregs(struct thread *td, struct savefpu *addr);
|
||||
void fpuinit(u_short control);
|
||||
void fpusave(struct savefpu *addr);
|
||||
void fpusetregs(struct thread *td, struct savefpu *addr);
|
||||
int fputrap(void);
|
||||
#endif
|
||||
|
||||
#endif /* !_MACHINE_NPX_H_ */
|
||||
#endif /* !_MACHINE_FPU_H_ */
|
||||
|
@ -66,7 +66,7 @@ struct pcb {
|
||||
|
||||
struct savefpu pcb_save;
|
||||
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 */
|
||||
|
||||
caddr_t pcb_onfault; /* copyin/out fault recovery */
|
||||
|
@ -41,12 +41,9 @@
|
||||
* Bits in 386 special registers:
|
||||
*/
|
||||
#define CR0_PE 0x00000001 /* Protected mode Enable */
|
||||
#define CR0_MP 0x00000002 /* "Math" Present (NPX or NPX emulator) */
|
||||
#define CR0_EM 0x00000004 /* EMulate non-NPX coproc. (trap ESC only) */
|
||||
#define CR0_MP 0x00000002 /* "Math" (fpu) Present */
|
||||
#define CR0_EM 0x00000004 /* EMulate FPU instructions. (trap ESC only) */
|
||||
#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 */
|
||||
|
||||
/*
|
||||
|
@ -33,7 +33,7 @@ eintrnames:
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
@ -42,7 +42,7 @@ eintrnames:
|
||||
* costs are making the driver interface nonuniform so unpending of
|
||||
* interrupts is more complicated and slower (call_driver(unit) would
|
||||
* 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
|
||||
* instead of frames.
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user