summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/i386/i386/vm_machdep.c1
-rw-r--r--sys/i386/include/npx.h4
-rw-r--r--sys/i386/isa/npx.c30
3 files changed, 35 insertions, 0 deletions
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index 26ed735..8ddc0a3 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -394,6 +394,7 @@ cpu_set_upcall(struct thread *td, struct thread *td0)
*/
bcopy(td0->td_pcb, pcb2, sizeof(*pcb2));
pcb2->pcb_flags &= ~(PCB_NPXTRAP|PCB_NPXINITDONE);
+ npx_fork_thread(td0, td);
/*
* Create a new fresh stack for the new thread.
diff --git a/sys/i386/include/npx.h b/sys/i386/include/npx.h
index 894b06d..792f75a 100644
--- a/sys/i386/include/npx.h
+++ b/sys/i386/include/npx.h
@@ -138,6 +138,8 @@ union savefpu {
#ifdef _KERNEL
+struct thread;
+
#define IO_NPX 0x0F0 /* Numeric Coprocessor */
#define IO_NPXSIZE 16 /* 80387/80487 NPX registers */
@@ -155,6 +157,8 @@ void npxinit(u_short control);
void npxsave(union savefpu *addr);
void npxsetregs(struct thread *td, union savefpu *addr);
int npxtrap(void);
+void npx_fork_thread(struct thread *td, struct thread *newtd);
+
#endif
#endif /* !_MACHINE_NPX_H_ */
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index bc39629..7b7f3a5 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -942,6 +942,36 @@ npxsetregs(td, addr)
curthread->td_pcb->pcb_flags |= PCB_NPXINITDONE;
}
+/*
+ * POSIX requires new thread to inherit floating-point environment.
+ */
+void
+npx_fork_thread(struct thread *td, struct thread *newtd)
+{
+ union savefpu *state;
+ u_int32_t mxcsr;
+ u_int32_t cw;
+
+ state = &newtd->td_pcb->pcb_save;
+ /* get control word */
+ if (npxgetregs(td, &newtd->td_pcb->pcb_save))
+ return;
+ if (cpu_fxsr) {
+ mxcsr = state->sv_xmm.sv_env.en_mxcsr;
+ cw = state->sv_xmm.sv_env.en_cw;
+ } else {
+ cw = state->sv_87.sv_env.en_cw;
+ mxcsr = 0;
+ }
+ bcopy(&npx_cleanstate, state, sizeof(*state));
+ if (cpu_fxsr) {
+ state->sv_xmm.sv_env.en_cw = cw;
+ state->sv_xmm.sv_env.en_mxcsr = mxcsr;
+ } else
+ state->sv_87.sv_env.en_cw = cw;
+ newtd->td_pcb->pcb_flags |= PCB_NPXINITDONE;
+}
+
static void
fpusave(addr)
union savefpu *addr;
OpenPOWER on IntegriCloud