summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/fpu.c8
-rw-r--r--sys/amd64/amd64/machdep.c3
-rw-r--r--sys/amd64/ia32/ia32_signal.c1
-rw-r--r--sys/amd64/include/pcb.h1
-rw-r--r--sys/amd64/linux32/linux32_sysvec.c1
-rw-r--r--sys/compat/linux/linux_misc.h5
-rw-r--r--sys/i386/i386/machdep.c3
-rw-r--r--sys/i386/include/pcb.h1
-rw-r--r--sys/i386/isa/npx.c11
-rw-r--r--sys/i386/linux/linux_sysvec.c10
10 files changed, 30 insertions, 14 deletions
diff --git a/sys/amd64/amd64/fpu.c b/sys/amd64/amd64/fpu.c
index 111d6d8..8f16c46 100644
--- a/sys/amd64/amd64/fpu.c
+++ b/sys/amd64/amd64/fpu.c
@@ -390,7 +390,6 @@ fpudna(void)
{
struct pcb *pcb;
register_t s;
- u_short control;
if (PCPU_GET(fpcurthread) == curthread) {
printf("fpudna: fpcurthread == curthread %d times\n",
@@ -421,10 +420,8 @@ fpudna(void)
* explicitly load sanitized registers.
*/
fxrstor(&fpu_cleanstate);
- if (pcb->pcb_flags & PCB_32BIT) {
- control = __INITIAL_FPUCW_I386__;
- fldcw(&control);
- }
+ if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__)
+ fldcw(&pcb->pcb_initial_fpucw);
pcb->pcb_flags |= PCB_FPUINITDONE;
} else
fxrstor(&pcb->pcb_save);
@@ -457,6 +454,7 @@ fpugetregs(struct thread *td, struct savefpu *addr)
if ((td->td_pcb->pcb_flags & PCB_FPUINITDONE) == 0) {
bcopy(&fpu_cleanstate, addr, sizeof(fpu_cleanstate));
+ addr->sv_env.en_cw = td->td_pcb->pcb_initial_fpucw;
return (_MC_FPOWNED_NONE);
}
s = intr_disable();
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 2bfde47..6ba3820 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -716,7 +716,7 @@ SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0,
idle_sysctl, "A", "currently selected idle function");
/*
- * Clear registers on exec
+ * Reset registers to default values on exec.
*/
void
exec_setregs(td, entry, stack, ps_strings)
@@ -743,6 +743,7 @@ exec_setregs(td, entry, stack, ps_strings)
pcb->pcb_es = _udatasel;
pcb->pcb_fs = _udatasel;
pcb->pcb_gs = _udatasel;
+ pcb->pcb_initial_fpucw = __INITIAL_FPUCW__;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_rip = entry;
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index d3b9ae3..019faba 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -729,6 +729,7 @@ ia32_setregs(td, entry, stack, ps_strings)
pcb->pcb_es = _udatasel;
pcb->pcb_fs = _udatasel;
pcb->pcb_gs = _udatasel;
+ pcb->pcb_initial_fpucw = __INITIAL_FPUCW_I386__;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_rip = entry;
diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h
index ac14c55..e6a5add 100644
--- a/sys/amd64/include/pcb.h
+++ b/sys/amd64/include/pcb.h
@@ -74,6 +74,7 @@ struct pcb {
u_int64_t pcb_dr7;
struct savefpu pcb_save;
+ uint16_t pcb_initial_fpucw;
caddr_t pcb_onfault; /* copyin/out fault recovery */
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index 312687a..a834c98 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -841,6 +841,7 @@ exec_linux_setregs(td, entry, stack, ps_strings)
pcb->pcb_es = _udatasel;
pcb->pcb_fs = _udatasel;
pcb->pcb_gs = _udatasel;
+ pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
bzero((char *)regs, sizeof(struct trapframe));
regs->tf_rip = entry;
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
index 37991f3..eddcd2c 100644
--- a/sys/compat/linux/linux_misc.h
+++ b/sys/compat/linux/linux_misc.h
@@ -60,4 +60,9 @@ extern const char *linux_platform;
*/
#define LINUX_AT_EXECFN 31 /* filename of program */
+/* Linux sets the i387 to extended precision. */
+#if defined(__i386__) || defined(__amd64__)
+#define __LINUX_NPXCW__ 0x37f
+#endif
+
#endif /* _LINUX_MISC_H_ */
diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c
index 803d8d1..e10217a 100644
--- a/sys/i386/i386/machdep.c
+++ b/sys/i386/i386/machdep.c
@@ -1362,7 +1362,7 @@ SYSCTL_PROC(_machdep, OID_AUTO, idle, CTLTYPE_STRING | CTLFLAG_RW, 0, 0,
idle_sysctl, "A", "currently selected idle function");
/*
- * Clear registers on exec
+ * Reset registers to default values on exec.
*/
void
exec_setregs(td, entry, stack, ps_strings)
@@ -1427,6 +1427,7 @@ exec_setregs(td, entry, stack, ps_strings)
* emulators don't provide an entry point for initialization.
*/
td->td_pcb->pcb_flags &= ~FP_SOFTFP;
+ pcb->pcb_initial_npxcw = __INITIAL_NPXCW__;
/*
* Drop the FP state if we hold it, so that the process gets a
diff --git a/sys/i386/include/pcb.h b/sys/i386/include/pcb.h
index ff6ff5a..17c8486 100644
--- a/sys/i386/include/pcb.h
+++ b/sys/i386/include/pcb.h
@@ -61,6 +61,7 @@ struct pcb {
int pcb_dr7;
union savefpu pcb_save;
+ uint16_t pcb_initial_npxcw;
u_int pcb_flags;
#define FP_SOFTFP 0x01 /* process using software fltng pnt emulator */
#define PCB_DBREGS 0x02 /* process using debug registers */
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();
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index c98fe14..4efd496 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -89,9 +89,6 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
#define LINUX_SYS_linux_rt_sendsig 0
#define LINUX_SYS_linux_sendsig 0
-#define fldcw(addr) __asm("fldcw %0" : : "m" (*(addr)))
-#define __LINUX_NPXCW__ 0x37f
-
extern char linux_sigcode[];
extern int linux_szsigcode;
@@ -930,16 +927,15 @@ static void
exec_linux_setregs(struct thread *td, u_long entry,
u_long stack, u_long ps_strings)
{
- static const u_short control = __LINUX_NPXCW__;
struct pcb *pcb = td->td_pcb;
exec_setregs(td, entry, stack, ps_strings);
/* Linux sets %gs to 0, we default to _udatasel */
- pcb->pcb_gs = 0; load_gs(0);
+ pcb->pcb_gs = 0;
+ load_gs(0);
- /* Linux sets the i387 to extended precision. */
- fldcw(&control);
+ pcb->pcb_initial_npxcw = __LINUX_NPXCW__;
}
static void
OpenPOWER on IntegriCloud