Module Name:    src
Committed By:   maxv
Date:           Wed Mar 14 17:40:41 UTC 2018

Modified Files:
        src/sys/arch/x86/x86: cpu.c x86_machdep.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.150 -r1.151 src/sys/arch/x86/x86/cpu.c
cvs rdiff -u -r1.108 -r1.109 src/sys/arch/x86/x86/x86_machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/x86/cpu.c
diff -u src/sys/arch/x86/x86/cpu.c:1.150 src/sys/arch/x86/x86/cpu.c:1.151
--- src/sys/arch/x86/x86/cpu.c:1.150	Sun Mar 11 13:38:02 2018
+++ src/sys/arch/x86/x86/cpu.c	Wed Mar 14 17:40:41 2018
@@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.15
 #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 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.15
 #include <machine/cpu_counter.h>
 
 #include <x86/fpu.h>
+#include <x86/cputypes.h>
 
 #if NLAPIC > 0
 #include <machine/apicvar.h>
@@ -1334,3 +1337,172 @@ cpu_kick(struct cpu_info *ci)
 {
 	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

Index: src/sys/arch/x86/x86/x86_machdep.c
diff -u src/sys/arch/x86/x86/x86_machdep.c:1.108 src/sys/arch/x86/x86/x86_machdep.c:1.109
--- src/sys/arch/x86/x86/x86_machdep.c:1.108	Fri Feb 23 09:57:20 2018
+++ src/sys/arch/x86/x86/x86_machdep.c	Wed Mar 14 17:40:41 2018
@@ -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 @@ SYSCTL_SETUP(sysctl_machdep_setup, "sysc
 #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 @@ SYSCTL_SETUP(sysctl_machdep_setup, "sysc
 		       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);

Reply via email to