svn commit: r190418 - in stable/7/sys: . amd64/amd64 amd64/ia32
amd64/include amd64/linux32 compat/linux contrib/pf
dev/ath/ath_hal dev/cxgb i386/i386 i386/include i386/isa i386/linux
John Baldwin
jhb at FreeBSD.org
Wed Mar 25 10:22:20 PDT 2009
Author: jhb
Date: Wed Mar 25 17:22:15 2009
New Revision: 190418
URL: http://svn.freebsd.org/changeset/base/190418
Log:
Allow different ABIs to use different initial control words for the FPU on
amd64 and i386. This fixes a bug were 32-bit binaries would run with a
different floating point exception mask under FreeBSD/amd64 vs FreeBSD/i386.
This commit also includes a few other minor changes to keep the code in
sync with 8.
Approved by: re (kib)
Modified:
stable/7/sys/ (props changed)
stable/7/sys/amd64/amd64/fpu.c
stable/7/sys/amd64/amd64/machdep.c
stable/7/sys/amd64/amd64/trap.c
stable/7/sys/amd64/ia32/ia32_signal.c
stable/7/sys/amd64/include/fpu.h
stable/7/sys/amd64/include/pcb.h
stable/7/sys/amd64/linux32/linux32_sysvec.c
stable/7/sys/compat/linux/linux_misc.h
stable/7/sys/contrib/pf/ (props changed)
stable/7/sys/dev/ath/ath_hal/ (props changed)
stable/7/sys/dev/cxgb/ (props changed)
stable/7/sys/i386/i386/machdep.c
stable/7/sys/i386/i386/mp_machdep.c
stable/7/sys/i386/include/npx.h
stable/7/sys/i386/include/pcb.h
stable/7/sys/i386/isa/npx.c
stable/7/sys/i386/linux/linux_sysvec.c
Modified: stable/7/sys/amd64/amd64/fpu.c
==============================================================================
--- stable/7/sys/amd64/amd64/fpu.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/amd64/amd64/fpu.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -98,16 +98,15 @@ typedef u_char bool_t;
static void fpu_clean_state(void);
-int hw_float = 1;
-SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
- CTLFLAG_RD, &hw_float, 0,
- "Floatingpoint instructions executed in hardware");
+SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
+ NULL, 1, "Floating point instructions executed in hardware");
static struct savefpu fpu_cleanstate;
-static bool_t fpu_cleanstate_ready;
/*
- * Initialize floating point unit.
+ * Initialize the floating point unit. On the boot CPU we generate a
+ * clean state that is used to initialize the floating point unit when
+ * it is first used by a process.
*/
void
fpuinit(void)
@@ -117,22 +116,22 @@ fpuinit(void)
u_short control;
savecrit = intr_disable();
- PCPU_SET(fpcurthread, 0);
stop_emulating();
fninit();
control = __INITIAL_FPUCW__;
fldcw(&control);
mxcsr = __INITIAL_MXCSR__;
ldmxcsr(mxcsr);
- fxsave(&fpu_cleanstate);
- if (fpu_cleanstate.sv_env.en_mxcsr_mask)
- cpu_mxcsr_mask = fpu_cleanstate.sv_env.en_mxcsr_mask;
- else
- cpu_mxcsr_mask = 0xFFBF;
+ if (PCPU_GET(cpuid) == 0) {
+ fxsave(&fpu_cleanstate);
+ if (fpu_cleanstate.sv_env.en_mxcsr_mask)
+ cpu_mxcsr_mask = fpu_cleanstate.sv_env.en_mxcsr_mask;
+ else
+ cpu_mxcsr_mask = 0xFFBF;
+ bzero(fpu_cleanstate.sv_fp, sizeof(fpu_cleanstate.sv_fp));
+ bzero(fpu_cleanstate.sv_xmm, sizeof(fpu_cleanstate.sv_xmm));
+ }
start_emulating();
- bzero(fpu_cleanstate.sv_fp, sizeof(fpu_cleanstate.sv_fp));
- bzero(fpu_cleanstate.sv_xmm, sizeof(fpu_cleanstate.sv_xmm));
- fpu_cleanstate_ready = 1;
intr_restore(savecrit);
}
@@ -386,8 +385,8 @@ fputrap()
static int err_count = 0;
-int
-fpudna()
+void
+fpudna(void)
{
struct pcb *pcb;
register_t s;
@@ -396,7 +395,7 @@ fpudna()
printf("fpudna: fpcurthread == curthread %d times\n",
++err_count);
stop_emulating();
- return (1);
+ return;
}
if (PCPU_GET(fpcurthread) != NULL) {
printf("fpudna: fpcurthread = %p (%d), curthread = %p (%d)\n",
@@ -421,12 +420,12 @@ fpudna()
* explicitly load sanitized registers.
*/
fxrstor(&fpu_cleanstate);
+ if (pcb->pcb_initial_fpucw != __INITIAL_FPUCW__)
+ fldcw(&pcb->pcb_initial_fpucw);
pcb->pcb_flags |= PCB_FPUINITDONE;
} else
fxrstor(&pcb->pcb_save);
intr_restore(s);
-
- return (1);
}
/*
@@ -454,10 +453,8 @@ fpugetregs(struct thread *td, struct sav
register_t s;
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));
+ 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();
Modified: stable/7/sys/amd64/amd64/machdep.c
==============================================================================
--- stable/7/sys/amd64/amd64/machdep.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/amd64/amd64/machdep.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -586,7 +586,7 @@ cpu_idle(void)
void (*cpu_idle_hook)(void) = cpu_idle_default;
/*
- * Clear registers on exec
+ * Reset registers to default values on exec.
*/
void
exec_setregs(td, entry, stack, ps_strings)
@@ -613,6 +613,7 @@ exec_setregs(td, entry, stack, ps_string
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;
Modified: stable/7/sys/amd64/amd64/trap.c
==============================================================================
--- stable/7/sys/amd64/amd64/trap.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/amd64/amd64/trap.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -421,13 +421,8 @@ trap(struct trapframe *frame)
case T_DNA:
/* transparent fault (due to context switch "late") */
- if (fpudna())
- goto userout;
- printf("pid %d killed due to lack of floating point\n",
- p->p_pid);
- i = SIGKILL;
- ucode = 0;
- break;
+ fpudna();
+ goto userout;
case T_FPOPFLT: /* FPU operand fetch fault */
ucode = ILL_COPROC;
@@ -455,11 +450,9 @@ trap(struct trapframe *frame)
* XXX this should be fatal unless the kernel has
* registered such use.
*/
- if (fpudna()) {
- printf("fpudna in kernel mode!\n");
- goto out;
- }
- break;
+ fpudna();
+ printf("fpudna in kernel mode!\n");
+ goto out;
case T_STKFLT: /* stack fault */
break;
Modified: stable/7/sys/amd64/ia32/ia32_signal.c
==============================================================================
--- stable/7/sys/amd64/ia32/ia32_signal.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/amd64/ia32/ia32_signal.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -727,6 +727,7 @@ ia32_setregs(td, entry, stack, ps_string
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;
Modified: stable/7/sys/amd64/include/fpu.h
==============================================================================
--- stable/7/sys/amd64/include/fpu.h Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/amd64/include/fpu.h Wed Mar 25 17:22:15 2009 (r190418)
@@ -92,11 +92,12 @@ struct savefpu {
* SSE2 based math. For FreeBSD/amd64, we go with the default settings.
*/
#define __INITIAL_FPUCW__ 0x037F
+#define __INITIAL_FPUCW_I386__ 0x127F
#define __INITIAL_MXCSR__ 0x1F80
#define __INITIAL_MXCSR_MASK__ 0xFFBF
#ifdef _KERNEL
-int fpudna(void);
+void fpudna(void);
void fpudrop(void);
void fpuexit(struct thread *td);
int fpuformat(void);
Modified: stable/7/sys/amd64/include/pcb.h
==============================================================================
--- stable/7/sys/amd64/include/pcb.h Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/amd64/include/pcb.h Wed Mar 25 17:22:15 2009 (r190418)
@@ -55,6 +55,13 @@ struct pcb {
register_t pcb_rip;
register_t pcb_fsbase;
register_t pcb_gsbase;
+ u_long pcb_flags;
+#define PCB_DBREGS 0x02 /* process using debug registers */
+#define PCB_FPUINITDONE 0x08 /* fpu state is initialized */
+#define PCB_GS32BIT 0x20 /* linux gs switch */
+#define PCB_32BIT 0x40 /* process has 32 bit context (segs etc) */
+#define PCB_FULLCTX 0x80 /* full context restore on sysret */
+
u_int32_t pcb_ds;
u_int32_t pcb_es;
u_int32_t pcb_fs;
@@ -67,12 +74,7 @@ struct pcb {
u_int64_t pcb_dr7;
struct savefpu pcb_save;
- u_long pcb_flags;
-#define PCB_DBREGS 0x02 /* process using debug registers */
-#define PCB_FPUINITDONE 0x08 /* fpu state is initialized */
-#define PCB_GS32BIT 0x20 /* linux gs switch */
-#define PCB_32BIT 0x40 /* process has 32 bit context (segs etc) */
-#define PCB_FULLCTX 0x80 /* full context restore on sysret */
+ uint16_t pcb_initial_fpucw;
caddr_t pcb_onfault; /* copyin/out fault recovery */
Modified: stable/7/sys/amd64/linux32/linux32_sysvec.c
==============================================================================
--- stable/7/sys/amd64/linux32/linux32_sysvec.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/amd64/linux32/linux32_sysvec.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -832,6 +832,7 @@ exec_linux_setregs(td, entry, stack, ps_
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;
Modified: stable/7/sys/compat/linux/linux_misc.h
==============================================================================
--- stable/7/sys/compat/linux/linux_misc.h Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/compat/linux/linux_misc.h Wed Mar 25 17:22:15 2009 (r190418)
@@ -45,4 +45,9 @@
#define LINUX_MREMAP_MAYMOVE 1
#define LINUX_MREMAP_FIXED 2
+/* Linux sets the i387 to extended precision. */
+#if defined(__i386__) || defined(__amd64__)
+#define __LINUX_NPXCW__ 0x37f
+#endif
+
#endif /* _LINUX_MISC_H_ */
Modified: stable/7/sys/i386/i386/machdep.c
==============================================================================
--- stable/7/sys/i386/i386/machdep.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/i386/i386/machdep.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -1188,7 +1188,7 @@ cpu_idle(void)
void (*cpu_idle_hook)(void) = cpu_idle_default;
/*
- * Clear registers on exec
+ * Reset registers to default values on exec.
*/
void
exec_setregs(td, entry, stack, ps_strings)
@@ -1253,6 +1253,7 @@ exec_setregs(td, entry, stack, ps_string
* 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
Modified: stable/7/sys/i386/i386/mp_machdep.c
==============================================================================
--- stable/7/sys/i386/i386/mp_machdep.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/i386/i386/mp_machdep.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -575,7 +575,7 @@ init_secondary(void)
cpu_setregs();
/* set up FPU state on the AP */
- npxinit(__INITIAL_NPXCW__);
+ npxinit();
/* set up SSE registers */
enable_sse();
Modified: stable/7/sys/i386/include/npx.h
==============================================================================
--- stable/7/sys/i386/include/npx.h Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/i386/include/npx.h Wed Mar 25 17:22:15 2009 (r190418)
@@ -151,7 +151,7 @@ void npxdrop(void);
void npxexit(struct thread *td);
int npxformat(void);
int npxgetregs(struct thread *td, union savefpu *addr);
-void npxinit(u_short control);
+void npxinit(void);
void npxsave(union savefpu *addr);
void npxsetregs(struct thread *td, union savefpu *addr);
int npxtrap(void);
Modified: stable/7/sys/i386/include/pcb.h
==============================================================================
--- stable/7/sys/i386/include/pcb.h Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/i386/include/pcb.h Wed Mar 25 17:22:15 2009 (r190418)
@@ -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 */
Modified: stable/7/sys/i386/isa/npx.c
==============================================================================
--- stable/7/sys/i386/isa/npx.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/i386/isa/npx.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -132,11 +132,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;
@@ -158,15 +166,13 @@ static long timezero(const char *funcnam
int hw_float; /* XXX currently just alias for npx_exists */
-SYSCTL_INT(_hw,HW_FLOATINGPT, floatingpoint,
- CTLFLAG_RD, &hw_float, 0,
- "Floatingpoint instructions executed in hardware");
+SYSCTL_INT(_hw, HW_FLOATINGPT, floatingpoint, CTLFLAG_RD,
+ &hw_float, 0, "Floating point instructions executed in hardware");
static volatile u_int npx_intrs_while_probing;
static volatile u_int npx_traps_while_probing;
static union savefpu npx_cleanstate;
-static bool_t npx_cleanstate_ready;
static bool_t npx_ex16;
static bool_t npx_exists;
static bool_t npx_irq13;
@@ -368,19 +374,14 @@ npx_probe(dev)
return (0);
}
/*
- * Worse, even IRQ13 is broken. Use emulator.
+ * Worse, even IRQ13 is broken.
*/
}
}
- /*
- * Probe failed, but we want to get to npxattach to initialize the
- * emulator and say that it has been installed. XXX handle devices
- * that aren't really devices better.
- */
-#ifdef SMP
- if (mp_ncpus > 1)
- panic("npx0 cannot be emulated on an SMP system");
-#endif
+
+ /* Probe failed. Floating point simply won't work. */
+ device_printf(dev, "WARNING: no FPU!\n");
+
/* FALLTHROUGH */
no_irq13:
idt[IDT_MF] = save_idt_npxtrap;
@@ -389,7 +390,7 @@ no_irq13:
bus_release_resource(dev, SYS_RES_IRQ, irq_rid, irq_res);
}
bus_release_resource(dev, SYS_RES_IOPORT, ioport_rid, ioport_res);
- return (0);
+ return (npx_exists ? 0 : ENXIO);
}
/*
@@ -406,32 +407,34 @@ npx_attach(dev)
if (npx_irq13)
device_printf(dev, "IRQ 13 interface\n");
- else if (!npx_ex16)
- device_printf(dev, "WARNING: no FPU!\n");
else if (!device_is_quiet(dev) || bootverbose)
device_printf(dev, "INT 16 interface\n");
- npxinit(__INITIAL_NPXCW__);
+ npxinit();
- if (npx_cleanstate_ready == 0) {
- s = intr_disable();
- stop_emulating();
- fpusave(&npx_cleanstate);
- start_emulating();
+ s = intr_disable();
+ stop_emulating();
+ fpusave(&npx_cleanstate);
+ start_emulating();
#ifdef CPU_ENABLE_SSE
- if (cpu_fxsr) {
- if (npx_cleanstate.sv_xmm.sv_env.en_mxcsr_mask)
- cpu_mxcsr_mask =
- npx_cleanstate.sv_xmm.sv_env.en_mxcsr_mask;
- else
- cpu_mxcsr_mask = 0xFFBF;
- }
+ if (cpu_fxsr) {
+ if (npx_cleanstate.sv_xmm.sv_env.en_mxcsr_mask)
+ cpu_mxcsr_mask =
+ npx_cleanstate.sv_xmm.sv_env.en_mxcsr_mask;
+ else
+ cpu_mxcsr_mask = 0xFFBF;
+ bzero(npx_cleanstate.sv_xmm.sv_fp,
+ sizeof(npx_cleanstate.sv_xmm.sv_fp));
+ bzero(npx_cleanstate.sv_xmm.sv_xmm,
+ sizeof(npx_cleanstate.sv_xmm.sv_xmm));
+ /* XXX might need even more zeroing. */
+ } else
#endif
- npx_cleanstate_ready = 1;
- intr_restore(s);
- }
+ bzero(npx_cleanstate.sv_87.sv_ac,
+ sizeof(npx_cleanstate.sv_87.sv_ac));
+ intr_restore(s);
#ifdef I586_CPU_XXX
- if (cpu_class == CPUCLASS_586 && npx_ex16 && npx_exists &&
+ if (cpu_class == CPUCLASS_586 && npx_ex16 &&
timezero("i586_bzero()", i586_bzero) <
timezero("bzero()", bzero) * 4 / 5) {
if (!(flags & NPX_DISABLE_I586_OPTIMIZED_BCOPY))
@@ -452,10 +455,11 @@ npx_attach(dev)
* Initialize floating point unit.
*/
void
-npxinit(u_short control)
+npxinit(void)
{
static union savefpu dummy;
register_t savecrit;
+ u_short control;
if (!npx_exists)
return;
@@ -472,6 +476,7 @@ npxinit(u_short control)
if (cpu_fxsr)
fninit();
#endif
+ control = __INITIAL_NPXCW__;
fldcw(&control);
start_emulating();
intr_restore(savecrit);
@@ -752,14 +757,10 @@ npxtrap()
static int err_count = 0;
int
-npxdna()
+npxdna(void)
{
struct pcb *pcb;
register_t s;
-#ifdef CPU_ENABLE_SSE
- int mxcsr;
-#endif
- u_short control;
if (!npx_exists)
return (0);
@@ -788,22 +789,16 @@ npxdna()
/*
* 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.
+ * load sanitized registers.
*/
- fninit();
- control = __INITIAL_NPXCW__;
- fldcw(&control);
-#ifdef CPU_ENABLE_SSE
- if (cpu_fxsr) {
- mxcsr = __INITIAL_MXCSR__;
- ldmxcsr(mxcsr);
- }
-#endif
+ fpurstor(&npx_cleanstate);
+ if (pcb->pcb_initial_npxcw != __INITIAL_NPXCW__)
+ fldcw(&pcb->pcb_initial_npxcw);
pcb->pcb_flags |= PCB_NPXINITDONE;
} else {
/*
- * The following frstor may cause an IRQ13 when the state
- * being restored has a pending error. The error will
+ * The following fpurstor() may cause an IRQ13 when the
+ * state being restored has a pending error. The error will
* appear to have been triggered by the current (npx) user
* instruction even when that instruction is a no-wait
* instruction that should not trigger an error (e.g.,
@@ -896,10 +891,8 @@ npxgetregs(td, addr)
return (_MC_FPOWNED_NONE);
if ((td->td_pcb->pcb_flags & PCB_NPXINITDONE) == 0) {
- if (npx_cleanstate_ready)
- bcopy(&npx_cleanstate, addr, sizeof(npx_cleanstate));
- else
- bzero(addr, sizeof(*addr));
+ bcopy(&npx_cleanstate, addr, sizeof(npx_cleanstate));
+ SET_FPU_CW(addr, td->td_pcb->pcb_initial_npxcw);
return (_MC_FPOWNED_NONE);
}
s = intr_disable();
Modified: stable/7/sys/i386/linux/linux_sysvec.c
==============================================================================
--- stable/7/sys/i386/linux/linux_sysvec.c Wed Mar 25 17:02:05 2009 (r190417)
+++ stable/7/sys/i386/linux/linux_sysvec.c Wed Mar 25 17:22:15 2009 (r190418)
@@ -86,9 +86,6 @@ MALLOC_DEFINE(M_LINUX, "linux", "Linux m
#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;
@@ -800,16 +797,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__;
}
struct sysentvec linux_sysvec = {
More information about the svn-src-stable
mailing list