diff options
-rw-r--r-- | sys/i386/i386/vm_machdep.c | 1 | ||||
-rw-r--r-- | sys/i386/include/npx.h | 4 | ||||
-rw-r--r-- | sys/i386/isa/npx.c | 30 |
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; |