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 Spectre V2 mitigation for certain families ...



details:   https://anonhg.NetBSD.org/src/rev/95f2ee920830
branches:  trunk
changeset: 831170:95f2ee920830
user:      maxv <maxv%NetBSD.org@localhost>
date:      Wed Mar 14 17:40:41 2018 +0000

description:
Spectre V2 mitigation for certain families of AMD CPUs.

A new sysctl is added, machdep.spectreV2.mitigated, that controls whether
Spectre V2 is mitigated. For now it defaults to "false".

The code is written in such a way that there can be several methods. For
now only one method is supported, on AMD Families 10h, 12h and 16h, where
an MSR is available to disable branch prediction entirely.

Compile-tested on Intel, AMD will be tested soon.

diffstat:

 sys/arch/x86/x86/cpu.c         |  176 ++++++++++++++++++++++++++++++++++++++++-
 sys/arch/x86/x86/x86_machdep.c |   28 +++++-
 2 files changed, 197 insertions(+), 7 deletions(-)

diffs (268 lines):

diff -r a6252b500655 -r 95f2ee920830 sys/arch/x86/x86/cpu.c
--- a/sys/arch/x86/x86/cpu.c    Wed Mar 14 15:03:16 2018 +0000
+++ b/sys/arch/x86/x86/cpu.c    Wed Mar 14 17:40:41 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cpu.c,v 1.150 2018/03/11 13:38:02 maxv Exp $   */
+/*     $NetBSD: cpu.c,v 1.151 2018/03/14 17:40:41 maxv Exp $   */
 
 /*
  * Copyright (c) 2000-2012 NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.150 2018/03/11 13:38:02 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.151 2018/03/14 17:40:41 maxv Exp $");
 
 #include "opt_ddb.h"
 #include "opt_mpbios.h"                /* for MPDEBUG */
@@ -82,6 +82,8 @@
 #include <sys/idle.h>
 #include <sys/atomic.h>
 #include <sys/reboot.h>
+#include <sys/sysctl.h>
+#include <sys/xcall.h>
 
 #include <uvm/uvm.h>
 
@@ -104,6 +106,7 @@
 #include <machine/cpu_counter.h>
 
 #include <x86/fpu.h>
+#include <x86/cputypes.h>
 
 #if NLAPIC > 0
 #include <machine/apicvar.h>
@@ -1334,3 +1337,172 @@
 {
        x86_send_ipi(ci, 0);
 }
+
+#if !defined(XEN)
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Speculation-related mitigations.
+ */
+
+enum spec_mitigation {
+       MITIGATION_NONE,
+       MITIGATION_AMD_DIS_IND,
+       MITIGATION_INTEL_IBRS
+};
+
+bool spec_mitigation_enabled __read_mostly = false;
+static enum spec_mitigation mitigation_method = MITIGATION_NONE;
+
+static void
+speculation_detect_method(void)
+{
+       struct cpu_info *ci = curcpu();
+
+       if (cpu_vendor == CPUVENDOR_INTEL) {
+               /* TODO: detect MITIGATION_INTEL_IBRS */
+               mitigation_method = MITIGATION_NONE;
+       } else if (cpu_vendor == CPUVENDOR_AMD) {
+               switch (CPUID_TO_FAMILY(ci->ci_signature)) {
+               case 0x10:
+               case 0x12:
+               case 0x16:
+                       mitigation_method = MITIGATION_AMD_DIS_IND;
+                       break;
+               default:
+                       mitigation_method = MITIGATION_NONE;
+                       break;
+               }
+       } else {
+               mitigation_method = MITIGATION_NONE;
+       }
+}
+
+static void
+mitigation_disable_cpu(void *arg1, void *arg2)
+{
+       uint64_t msr;
+
+       switch (mitigation_method) {
+       case MITIGATION_NONE:
+               panic("impossible");
+               break;
+       case MITIGATION_AMD_DIS_IND:
+               msr = rdmsr(MSR_IC_CFG);
+               msr &= ~IC_CFG_DIS_IND;
+               wrmsr(MSR_IC_CFG, msr);
+               break;
+       case MITIGATION_INTEL_IBRS:
+               /* ibrs_disable() TODO */
+               break;
+       }
+}
+
+static void
+mitigation_enable_cpu(void *arg1, void *arg2)
+{
+       uint64_t msr;
+
+       switch (mitigation_method) {
+       case MITIGATION_NONE:
+               panic("impossible");
+               break;
+       case MITIGATION_AMD_DIS_IND:
+               msr = rdmsr(MSR_IC_CFG);
+               msr |= IC_CFG_DIS_IND;
+               wrmsr(MSR_IC_CFG, msr);
+               break;
+       case MITIGATION_INTEL_IBRS:
+               /* ibrs_enable() TODO */
+               break;
+       }
+}
+
+static int
+mitigation_disable(void)
+{
+       uint64_t xc;
+
+       speculation_detect_method();
+
+       switch (mitigation_method) {
+       case MITIGATION_NONE:
+               printf("[!] No mitigation available\n");
+               return EOPNOTSUPP;
+       case MITIGATION_AMD_DIS_IND:
+               printf("[+] Disabling SpectreV2 Mitigation...");
+               xc = xc_broadcast(0, mitigation_disable_cpu,
+                   NULL, NULL);
+               xc_wait(xc);
+               printf(" done!\n");
+               spec_mitigation_enabled = false;
+               return 0;
+       case MITIGATION_INTEL_IBRS:
+               /* TODO */
+               return 0;
+       default:
+               panic("impossible");
+       }
+}
+
+static int
+mitigation_enable(void)
+{
+       uint64_t xc;
+
+       speculation_detect_method();
+
+       switch (mitigation_method) {
+       case MITIGATION_NONE:
+               printf("[!] No mitigation available\n");
+               return EOPNOTSUPP;
+       case MITIGATION_AMD_DIS_IND:
+               printf("[+] Enabling SpectreV2 Mitigation...");
+               xc = xc_broadcast(0, mitigation_enable_cpu,
+                   NULL, NULL);
+               xc_wait(xc);
+               printf(" done!\n");
+               spec_mitigation_enabled = true;
+               return 0;
+       case MITIGATION_INTEL_IBRS:
+               /* TODO */
+               return 0;
+       default:
+               panic("impossible");
+       }
+}
+
+int sysctl_machdep_spectreV2_mitigated(SYSCTLFN_ARGS);
+
+int
+sysctl_machdep_spectreV2_mitigated(SYSCTLFN_ARGS)
+{
+       struct sysctlnode node;
+       int error, val;
+
+       val = *(int *)rnode->sysctl_data;
+
+       node = *rnode;
+       node.sysctl_data = &val;
+
+       error = sysctl_lookup(SYSCTLFN_CALL(&node));
+       if (error != 0 || newp == NULL)
+               return error;
+
+       if (val == 0) {
+               if (!spec_mitigation_enabled)
+                       error = 0;
+               else
+                       error = mitigation_disable();
+       } else {
+               if (spec_mitigation_enabled)
+                       error = 0;
+               else
+                       error = mitigation_enable();
+       }
+
+       return error;
+}
+
+#endif
diff -r a6252b500655 -r 95f2ee920830 sys/arch/x86/x86/x86_machdep.c
--- a/sys/arch/x86/x86/x86_machdep.c    Wed Mar 14 15:03:16 2018 +0000
+++ b/sys/arch/x86/x86/x86_machdep.c    Wed Mar 14 17:40:41 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: x86_machdep.c,v 1.108 2018/02/23 09:57:20 maxv Exp $   */
+/*     $NetBSD: x86_machdep.c,v 1.109 2018/03/14 17:40:41 maxv Exp $   */
 
 /*-
  * Copyright (c) 2002, 2006, 2007 YAMAMOTO Takashi,
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.108 2018/02/23 09:57:20 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.109 2018/03/14 17:40:41 maxv Exp $");
 
 #include "opt_modular.h"
 #include "opt_physmem.h"
@@ -1257,13 +1257,13 @@
 #endif
 #ifdef SVS
        int sysctl_machdep_svs_enabled(SYSCTLFN_ARGS);
-       const struct sysctlnode *rnode = NULL;
-       sysctl_createv(clog, 0, NULL, &rnode,
+       const struct sysctlnode *svs_rnode = NULL;
+       sysctl_createv(clog, 0, NULL, &svs_rnode,
                       CTLFLAG_PERMANENT,
                       CTLTYPE_NODE, "svs", NULL,
                       NULL, 0, NULL, 0,
                       CTL_MACHDEP, CTL_CREATE);
-       sysctl_createv(clog, 0, &rnode, &rnode,
+       sysctl_createv(clog, 0, &svs_rnode, &svs_rnode,
                       CTLFLAG_READWRITE,
                       CTLTYPE_BOOL, "enabled",
                       SYSCTL_DESCR("Whether the kernel uses SVS"),
@@ -1271,6 +1271,24 @@
                       CTL_CREATE, CTL_EOL);
 #endif
 
+#ifndef XEN
+       int sysctl_machdep_spectreV2_mitigated(SYSCTLFN_ARGS);
+       extern bool spec_mitigation_enabled;
+       const struct sysctlnode *spec_rnode = NULL;
+       sysctl_createv(clog, 0, NULL, &spec_rnode,
+                      CTLFLAG_PERMANENT,
+                      CTLTYPE_NODE, "spectreV2", NULL,
+                      NULL, 0, NULL, 0,
+                      CTL_MACHDEP, CTL_CREATE);
+       sysctl_createv(clog, 0, &spec_rnode, &spec_rnode,
+                      CTLFLAG_READWRITE,
+                      CTLTYPE_BOOL, "mitigated",
+                      SYSCTL_DESCR("Whether Spectre Variant 2 is mitigated"),
+                      sysctl_machdep_spectreV2_mitigated, 0,
+                      &spec_mitigation_enabled, 0,
+                      CTL_CREATE, CTL_EOL);
+#endif
+
        /* None of these can ever change once the system has booted */
        const_sysctl(clog, "fpu_present", CTLTYPE_INT, i386_fpu_present,
            CPU_FPU_PRESENT);



Home | Main Index | Thread Index | Old Index