From 186c803fb9de117fca51aa897f8550bd4e49c030 Mon Sep 17 00:00:00 2001 From: Markus Pfeiffer Date: Wed, 11 Jun 2014 23:09:20 +0100 Subject: [PATCH] kernel/npx: Add detection code for default MXCSR mask As per Intel/AMD manuals the default MXCSR mask can be probed by executing fxstor (if supported) and reading the mask from the stored state. This patch adds detection of the mask when it is supported. Otherwise a default mask of 0xFFBF is used as before. --- sys/cpu/x86_64/include/npx.h | 5 ++++- sys/platform/pc64/x86_64/identcpu.c | 12 ++++++++++ sys/platform/pc64/x86_64/machdep.c | 2 +- sys/platform/pc64/x86_64/mp_machdep.c | 2 +- sys/platform/pc64/x86_64/npx.c | 32 ++++++++++++++++++++++----- 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/sys/cpu/x86_64/include/npx.h b/sys/cpu/x86_64/include/npx.h index 06e33506ea..787c7b8e0e 100644 --- a/sys/cpu/x86_64/include/npx.h +++ b/sys/cpu/x86_64/include/npx.h @@ -164,8 +164,11 @@ union savefpu { struct proc; struct trapframe; +extern uint32_t npx_mxcsr_mask; + +void npxprobemask (void); void npxexit (void); -void npxinit (u_short control); +void npxinit (void); void npxsave (union savefpu *addr); #endif diff --git a/sys/platform/pc64/x86_64/identcpu.c b/sys/platform/pc64/x86_64/identcpu.c index e549810176..bc0825b501 100644 --- a/sys/platform/pc64/x86_64/identcpu.c +++ b/sys/platform/pc64/x86_64/identcpu.c @@ -56,6 +56,7 @@ #include #include #include +#include /* XXX - should be in header file: */ void printcpuinfo(void); @@ -479,6 +480,8 @@ printcpuinfo(void) if (cpu_vendor_id == CPU_VENDOR_AMD) print_AMD_info(); + + kprintf("npx mask: 0x%8.8x\n", npx_mxcsr_mask); } void @@ -596,6 +599,15 @@ identify_cpu(void) if (cpu_feature2 & CPUID2_MON) cpu_mi_feature |= CPU_MI_MONITOR; + + /* + * We do assume that all CPUs have the same + * SSE/FXSR features + */ + if ((cpu_feature & CPUID_XMM) && + (cpu_feature & CPUID_FXSR)) { + npxprobemask(); + } } static u_int diff --git a/sys/platform/pc64/x86_64/machdep.c b/sys/platform/pc64/x86_64/machdep.c index d7c669787e..1e27443aa7 100644 --- a/sys/platform/pc64/x86_64/machdep.c +++ b/sys/platform/pc64/x86_64/machdep.c @@ -1279,7 +1279,7 @@ exec_setregs(u_long entry, u_long stack, u_long ps_strings) wrmsr(MSR_KGSBASE, 0); /* Initialize the npx (if any) for the current process. */ - npxinit(__INITIAL_FPUCW__); + npxinit(); crit_exit(); pcb->pcb_ds = _udatasel; diff --git a/sys/platform/pc64/x86_64/mp_machdep.c b/sys/platform/pc64/x86_64/mp_machdep.c index 589b450bfd..d73156ce6e 100644 --- a/sys/platform/pc64/x86_64/mp_machdep.c +++ b/sys/platform/pc64/x86_64/mp_machdep.c @@ -309,7 +309,7 @@ init_secondary(void) initializecpu(myid); /* set up FPU state on the AP */ - npxinit(__INITIAL_FPUCW__); + npxinit(); /* disable the APIC, just to be SURE */ lapic->svr &= ~APIC_SVR_ENABLE; diff --git a/sys/platform/pc64/x86_64/npx.c b/sys/platform/pc64/x86_64/npx.c index 5c5e735355..5201bd00d6 100644 --- a/sys/platform/pc64/x86_64/npx.c +++ b/sys/platform/pc64/x86_64/npx.c @@ -92,14 +92,32 @@ static struct krate badfprate = { 1 }; static void fpusave (union savefpu *); static void fpurstor (union savefpu *); +uint32_t npx_mxcsr_mask = 0xFFBF; /* this is the default */ + +/* + * Probe the npx_mxcsr_mask + */ +void npxprobemask(void) +{ + /*64-Byte alignment required for xsave*/ + static union savefpu dummy __aligned(64); + + crit_enter(); + stop_emulating(); + fxsave(&dummy); + npx_mxcsr_mask = ((uint32_t *)&dummy)[7]; + start_emulating(); + crit_exit(); +} + /* * Initialize the floating point unit. */ -void -npxinit(u_short control) +void npxinit(void) { /*64-Byte alignment required for xsave*/ static union savefpu dummy __aligned(64); + u_short control; u_int mxcsr; /* @@ -107,9 +125,11 @@ npxinit(u_short control) * fnsave to throw away any junk in the fpu. npxsave() initializes * the fpu and sets npxthread = NULL as important side effects. */ + npxsave(&dummy); crit_enter(); stop_emulating(); + control = __INITIAL_FPUCW__; fldcw(&control); mxcsr = __INITIAL_MXCSR__; @@ -333,7 +353,7 @@ npxdna(void) crit_enter(); if ((td->td_flags & (TDF_USINGFP | TDF_KERNELFP)) == 0) { td->td_flags |= TDF_USINGFP; - npxinit(__INITIAL_FPUCW__); + npxinit(); didinit = 1; } @@ -361,7 +381,7 @@ npxdna(void) * fnsave are broken, so our treatment breaks fnclex if it is the * first FPU instruction after a context switch. */ - if ((td->td_savefpu->sv_xmm.sv_env.en_mxcsr & ~0xFFBF) + if ((td->td_savefpu->sv_xmm.sv_env.en_mxcsr & ~npx_mxcsr_mask) #ifndef CPU_DISABLE_SSE && cpu_fxsr #endif @@ -370,7 +390,7 @@ npxdna(void) "%s: FXRSTR: illegal FP MXCSR %08x didinit = %d\n", td->td_comm, td->td_savefpu->sv_xmm.sv_env.en_mxcsr, didinit); - td->td_savefpu->sv_xmm.sv_env.en_mxcsr &= 0xFFBF; + td->td_savefpu->sv_xmm.sv_env.en_mxcsr &= npx_mxcsr_mask; lwpsignal(curproc, curthread->td_lwp, SIGFPE); } fpurstor(td->td_savefpu); @@ -513,7 +533,7 @@ npxpop(mcontext_t *mctx) npxsave(td->td_savefpu); KKASSERT(sizeof(*td->td_savefpu) <= sizeof(mctx->mc_fpregs)); bcopy(mctx->mc_fpregs, td->td_savefpu, sizeof(*td->td_savefpu)); - if ((td->td_savefpu->sv_xmm.sv_env.en_mxcsr & ~0xFFBF) + if ((td->td_savefpu->sv_xmm.sv_env.en_mxcsr & ~npx_mxcsr_mask) #ifndef CPU_DISABLE_SSE && cpu_fxsr #endif -- 2.41.0