Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/arch/x86/x86 Reduce the noise, reorder and rename some t...
details: https://anonhg.NetBSD.org/src/rev/49e8f8daa42b
branches: trunk
changeset: 993561:49e8f8daa42b
user: maxv <maxv%NetBSD.org@localhost>
date: Mon Sep 17 15:53:06 2018 +0000
description:
Reduce the noise, reorder and rename some things for clarity.
diffstat:
sys/arch/x86/x86/fpu.c | 414 ++++++++++++++++++++++--------------------------
1 files changed, 193 insertions(+), 221 deletions(-)
diffs (truncated from 573 to 300 lines):
diff -r ed2030ad686b -r 49e8f8daa42b sys/arch/x86/x86/fpu.c
--- a/sys/arch/x86/x86/fpu.c Mon Sep 17 15:19:29 2018 +0000
+++ b/sys/arch/x86/x86/fpu.c Mon Sep 17 15:53:06 2018 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: fpu.c,v 1.46 2018/07/01 08:32:41 maxv Exp $ */
+/* $NetBSD: fpu.c,v 1.47 2018/09/17 15:53:06 maxv Exp $ */
/*
* Copyright (c) 2008 The NetBSD Foundation, Inc. All
@@ -96,7 +96,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.46 2018/07/01 08:32:41 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fpu.c,v 1.47 2018/09/17 15:53:06 maxv Exp $");
#include "opt_multiprocessor.h"
@@ -121,9 +121,6 @@
#include <x86/cpu.h>
#include <x86/fpu.h>
-/* Check some duplicate definitions match */
-#include <machine/fenv.h>
-
#ifdef XEN
#define clts() HYPERVISOR_fpu_taskswitch(0)
#define stts() HYPERVISOR_fpu_taskswitch(1)
@@ -134,13 +131,169 @@
static uint32_t x86_fpu_mxcsr_mask __read_mostly = 0;
static inline union savefpu *
-process_fpframe(struct lwp *lwp)
+lwp_fpuarea(struct lwp *l)
{
- struct pcb *pcb = lwp_getpcb(lwp);
+ struct pcb *pcb = lwp_getpcb(l);
return &pcb->pcb_savefpu;
}
+void
+fpuinit(struct cpu_info *ci)
+{
+ /*
+ * This might not be strictly necessary since it will be initialized
+ * for each process. However it does no harm.
+ */
+ clts();
+ fninit();
+ stts();
+}
+
+void
+fpuinit_mxcsr_mask(void)
+{
+#ifndef XEN
+ union savefpu fpusave __aligned(16);
+ u_long psl;
+
+ memset(&fpusave, 0, sizeof(fpusave));
+
+ /* Disable interrupts, and enable FPU */
+ psl = x86_read_psl();
+ x86_disable_intr();
+ clts();
+
+ /* Fill in the FPU area */
+ fxsave(&fpusave);
+
+ /* Restore previous state */
+ stts();
+ x86_write_psl(psl);
+
+ if (fpusave.sv_xmm.fx_mxcsr_mask == 0) {
+ x86_fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__;
+ } else {
+ x86_fpu_mxcsr_mask = fpusave.sv_xmm.fx_mxcsr_mask;
+ }
+#else
+ /*
+ * XXX XXX XXX: On Xen the FXSAVE above faults. That's because
+ * &fpusave is not 16-byte aligned. Stack alignment problem
+ * somewhere, it seems.
+ */
+ x86_fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__;
+#endif
+}
+
+static void
+fpu_clear_amd(void)
+{
+ /*
+ * AMD FPUs do not restore FIP, FDP, and FOP on fxrstor and xrstor
+ * when FSW.ES=0, leaking other threads' execution history.
+ *
+ * Clear them manually by loading a zero (fldummy). We do this
+ * unconditionally, regardless of FSW.ES.
+ *
+ * Before that, clear the ES bit in the x87 status word if it is
+ * currently set, in order to avoid causing a fault in the
+ * upcoming load.
+ *
+ * Newer generations of AMD CPUs have CPUID_Fn80000008_EBX[2],
+ * which indicates that FIP/FDP/FOP are restored (same behavior
+ * as Intel). We're not using it though.
+ */
+ if (fngetsw() & 0x80)
+ fnclex();
+ fldummy();
+}
+
+static void
+fpu_area_save(void *area)
+{
+ clts();
+
+ switch (x86_fpu_save) {
+ case FPU_SAVE_FSAVE:
+ fnsave(area);
+ break;
+ case FPU_SAVE_FXSAVE:
+ fxsave(area);
+ break;
+ case FPU_SAVE_XSAVE:
+ xsave(area, x86_xsave_features);
+ break;
+ case FPU_SAVE_XSAVEOPT:
+ xsaveopt(area, x86_xsave_features);
+ break;
+ }
+}
+
+static void
+fpu_area_restore(void *area)
+{
+ clts();
+
+ switch (x86_fpu_save) {
+ case FPU_SAVE_FSAVE:
+ frstor(area);
+ break;
+ case FPU_SAVE_FXSAVE:
+ if (cpu_vendor == CPUVENDOR_AMD)
+ fpu_clear_amd();
+ fxrstor(area);
+ break;
+ case FPU_SAVE_XSAVE:
+ case FPU_SAVE_XSAVEOPT:
+ if (cpu_vendor == CPUVENDOR_AMD)
+ fpu_clear_amd();
+ xrstor(area, x86_xsave_features);
+ break;
+ }
+}
+
+static void
+fpu_lwp_install(struct lwp *l)
+{
+ struct pcb *pcb = lwp_getpcb(l);
+ struct cpu_info *ci = curcpu();
+
+ KASSERT(ci->ci_fpcurlwp == NULL);
+ KASSERT(pcb->pcb_fpcpu == NULL);
+ ci->ci_fpcurlwp = l;
+ pcb->pcb_fpcpu = ci;
+ fpu_area_restore(&pcb->pcb_savefpu);
+}
+
+void
+fpu_eagerswitch(struct lwp *oldlwp, struct lwp *newlwp)
+{
+ int s;
+
+ s = splhigh();
+#ifdef DIAGNOSTIC
+ if (oldlwp != NULL) {
+ struct pcb *pcb = lwp_getpcb(oldlwp);
+ struct cpu_info *ci = curcpu();
+ if (pcb->pcb_fpcpu == NULL) {
+ KASSERT(ci->ci_fpcurlwp != oldlwp);
+ } else if (pcb->pcb_fpcpu == ci) {
+ KASSERT(ci->ci_fpcurlwp == oldlwp);
+ } else {
+ panic("%s: oldlwp's state installed elsewhere",
+ __func__);
+ }
+ }
+#endif
+ fpusave_cpu(true);
+ if (!(newlwp->l_flag & LW_SYSTEM))
+ fpu_lwp_install(newlwp);
+ splx(s);
+}
+
+/* -------------------------------------------------------------------------- */
+
/*
* The following table is used to ensure that the FPE_... value
* that is passed as a trapcode to the signal handler of the user
@@ -219,202 +372,29 @@
#undef FPE_xxx32
/*
- * Init the FPU.
+ * This is a synchronous trap on either an x87 instruction (due to an unmasked
+ * error on the previous x87 instruction) or on an SSE/SSE2/etc instruction due
+ * to an error on the instruction itself.
*
- * This might not be strictly necessary since it will be initialised
- * for each process. However it does no harm.
- */
-void
-fpuinit(struct cpu_info *ci)
-{
-
- clts();
- fninit();
- stts();
-}
-
-/*
- * Get the value of MXCSR_MASK supported by the CPU.
+ * If trap actually generates a signal, then the fpu state is saved and then
+ * copied onto the lwp's user-stack, and then recovered from there when the
+ * signal returns.
+ *
+ * All this code needs to do is save the reason for the trap. For x87 traps the
+ * status word bits need clearing to stop the trap re-occurring. For SSE traps
+ * the mxcsr bits are 'sticky' and need clearing to not confuse a later trap.
+ *
+ * We come here with interrupts disabled.
*/
void
-fpuinit_mxcsr_mask(void)
-{
-#ifndef XEN
- union savefpu fpusave __aligned(16);
- u_long psl;
-
- memset(&fpusave, 0, sizeof(fpusave));
-
- /* Disable interrupts, and enable FPU */
- psl = x86_read_psl();
- x86_disable_intr();
- clts();
-
- /* Fill in the FPU area */
- fxsave(&fpusave);
-
- /* Restore previous state */
- stts();
- x86_write_psl(psl);
-
- if (fpusave.sv_xmm.fx_mxcsr_mask == 0) {
- x86_fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__;
- } else {
- x86_fpu_mxcsr_mask = fpusave.sv_xmm.fx_mxcsr_mask;
- }
-#else
- /*
- * XXX XXX XXX: On Xen the FXSAVE above faults. That's because
- * &fpusave is not 16-byte aligned. Stack alignment problem
- * somewhere, it seems.
- */
- x86_fpu_mxcsr_mask = __INITIAL_MXCSR_MASK__;
-#endif
-}
-
-static void
-fpu_clear_amd(void)
-{
- /*
- * AMD FPUs do not restore FIP, FDP, and FOP on fxrstor and xrstor
- * when FSW.ES=0, leaking other threads' execution history.
- *
- * Clear them manually by loading a zero (fldummy). We do this
- * unconditionally, regardless of FSW.ES.
- *
- * Before that, clear the ES bit in the x87 status word if it is
- * currently set, in order to avoid causing a fault in the
- * upcoming load.
- *
- * Newer generations of AMD CPUs have CPUID_Fn80000008_EBX[2],
- * which indicates that FIP/FDP/FOP are restored (same behavior
- * as Intel). We're not using it though.
- */
- if (fngetsw() & 0x80)
- fnclex();
- fldummy();
-}
-
-static void
-fpu_save(struct lwp *l)
-{
- struct pcb *pcb = lwp_getpcb(l);
-
- switch (x86_fpu_save) {
- case FPU_SAVE_FSAVE:
- fnsave(&pcb->pcb_savefpu);
Home |
Main Index |
Thread Index |
Old Index