summaryrefslogtreecommitdiffstats
path: root/sys/i386/isa/npx.c
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2009-03-05 19:42:11 +0000
committerjhb <jhb@FreeBSD.org>2009-03-05 19:42:11 +0000
commite1b708897ea547f25fbc5fc1f73bb2b0738c5757 (patch)
tree156c16702c286b02c436fdf8c8a1140bab925e8b /sys/i386/isa/npx.c
parent217c09dffc7d5e0d80e98fe648855f9e3c1eee22 (diff)
downloadFreeBSD-src-e1b708897ea547f25fbc5fc1f73bb2b0738c5757.zip
FreeBSD-src-e1b708897ea547f25fbc5fc1f73bb2b0738c5757.tar.gz
A better fix for handling different FPU initial control words for different
ABIs: - Store the FPU initial control word in the pcb for each thread. - When first using the FPU, load the initial control word after restoring the clean state if it is not the standard control word. - Provide a correct control word for Linux/i386 binaries under FreeBSD/amd64. - Adjust the control word returned for fpugetregs()/npxgetregs() when a thread hasn't used the FPU yet to reflect the real initial control word for the current ABI. - The Linux/i386 ABI for FreeBSD/i386 now properly sets the right control word instead of trashing whatever the current state of the FPU is. Reviewed by: bde
Diffstat (limited to 'sys/i386/isa/npx.c')
-rw-r--r--sys/i386/isa/npx.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/sys/i386/isa/npx.c b/sys/i386/isa/npx.c
index aaf2eb5..a4f5b34 100644
--- a/sys/i386/isa/npx.c
+++ b/sys/i386/isa/npx.c
@@ -141,11 +141,19 @@ void stop_emulating(void);
(cpu_fxsr ? \
(thread)->td_pcb->pcb_save.sv_xmm.sv_env.en_sw : \
(thread)->td_pcb->pcb_save.sv_87.sv_env.en_sw)
+#define SET_FPU_CW(savefpu, value) do { \
+ if (cpu_fxsr) \
+ (savefpu)->sv_xmm.sv_env.en_cw = (value); \
+ else \
+ (savefpu)->sv_87.sv_env.en_cw = (value); \
+} while (0)
#else /* CPU_ENABLE_SSE */
#define GET_FPU_CW(thread) \
(thread->td_pcb->pcb_save.sv_87.sv_env.en_cw)
#define GET_FPU_SW(thread) \
(thread->td_pcb->pcb_save.sv_87.sv_env.en_sw)
+#define SET_FPU_CW(savefpu, value) \
+ (savefpu)->sv_87.sv_env.en_cw = (value)
#endif /* CPU_ENABLE_SSE */
typedef u_char bool_t;
@@ -793,6 +801,8 @@ npxdna(void)
* load sanitized registers.
*/
fpurstor(&npx_cleanstate);
+ if (pcb->pcb_initial_npxcw != __INITIAL_NPXCW__)
+ fldcw(&pcb->pcb_initial_npxcw);
pcb->pcb_flags |= PCB_NPXINITDONE;
} else {
/*
@@ -891,6 +901,7 @@ npxgetregs(td, addr)
if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
bcopy(&npx_cleanstate, addr, sizeof(npx_cleanstate));
+ SET_FPU_CW(addr, td->td_pcb->pcb_initial_npxcw);
return (_MC_FPOWNED_NONE);
}
s = intr_disable();
OpenPOWER on IntegriCloud