Module Name: src
Committed By: martin
Date: Sat Jun 9 15:12:21 UTC 2018
Modified Files:
src/sys/arch/amd64/amd64 [netbsd-8]: machdep.c
src/sys/arch/amd64/conf [netbsd-8]: GENERIC files.amd64
src/sys/arch/i386/conf [netbsd-8]: GENERIC files.i386
src/sys/arch/i386/i386 [netbsd-8]: machdep.c
src/sys/arch/x86/include [netbsd-8]: cpu.h specialreg.h
src/sys/arch/x86/x86 [netbsd-8]: x86_machdep.c
Added Files:
src/sys/arch/x86/x86 [netbsd-8]: spectre.c
Log Message:
Pullup the following revisions, requested by maxv in ticket #865:
sys/arch/amd64/amd64/machdep.c 1.303 (patch)
sys/arch/amd64/conf/GENERIC 1.492 (patch)
sys/arch/amd64/conf/files.amd64 1.103 (patch)
sys/arch/i386/i386/machdep.c 1.806 (patch)
sys/arch/i386/conf/GENERIC 1.1179 (patch)
sys/arch/i386/conf/files.i386 1.393 (patch)
sys/arch/x86/include/cpu.h 1.91 (patch)
sys/arch/x86/include/specialreg.h upto 1.126 (patch)
sys/arch/x86/x86/x86_machdep.c upto 1.115 (patch, adapted)
sys/arch/x86/x86/spectre.c upto 1.19 (patch, adapted,
no IBRS,
SpectreV2 mitigations not
enabled by default)
Backport the hardware SpectreV2 and SpectreV4 mitigations.
To generate a diff of this commit:
cvs rdiff -u -r1.255.6.6 -r1.255.6.7 src/sys/arch/amd64/amd64/machdep.c
cvs rdiff -u -r1.459.2.9 -r1.459.2.10 src/sys/arch/amd64/conf/GENERIC
cvs rdiff -u -r1.88.8.3 -r1.88.8.4 src/sys/arch/amd64/conf/files.amd64
cvs rdiff -u -r1.1156.2.9 -r1.1156.2.10 src/sys/arch/i386/conf/GENERIC
cvs rdiff -u -r1.378.6.2 -r1.378.6.3 src/sys/arch/i386/conf/files.i386
cvs rdiff -u -r1.782.6.5 -r1.782.6.6 src/sys/arch/i386/i386/machdep.c
cvs rdiff -u -r1.71.2.5 -r1.71.2.6 src/sys/arch/x86/include/cpu.h
cvs rdiff -u -r1.98.2.4 -r1.98.2.5 src/sys/arch/x86/include/specialreg.h
cvs rdiff -u -r0 -r1.19.2.2 src/sys/arch/x86/x86/spectre.c
cvs rdiff -u -r1.91.4.2 -r1.91.4.3 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/amd64/amd64/machdep.c
diff -u src/sys/arch/amd64/amd64/machdep.c:1.255.6.6 src/sys/arch/amd64/amd64/machdep.c:1.255.6.7
--- src/sys/arch/amd64/amd64/machdep.c:1.255.6.6 Thu Mar 22 16:59:03 2018
+++ src/sys/arch/amd64/amd64/machdep.c Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.255.6.6 2018/03/22 16:59:03 martin Exp $ */
+/* $NetBSD: machdep.c,v 1.255.6.7 2018/06/09 15:12:21 martin Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2000, 2006, 2007, 2008, 2011
@@ -111,7 +111,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.255.6.6 2018/03/22 16:59:03 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.255.6.7 2018/06/09 15:12:21 martin Exp $");
/* #define XENDEBUG_LOW */
@@ -1549,6 +1549,9 @@ init_x86_64(paddr_t first_avail)
svs_init();
#endif
cpu_init_msrs(&cpu_info_primary, true);
+#ifndef XEN
+ cpu_speculation_init(&cpu_info_primary);
+#endif
use_pae = 1; /* PAE always enabled in long mode */
Index: src/sys/arch/amd64/conf/GENERIC
diff -u src/sys/arch/amd64/conf/GENERIC:1.459.2.9 src/sys/arch/amd64/conf/GENERIC:1.459.2.10
--- src/sys/arch/amd64/conf/GENERIC:1.459.2.9 Wed Apr 18 14:45:08 2018
+++ src/sys/arch/amd64/conf/GENERIC Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.459.2.9 2018/04/18 14:45:08 martin Exp $
+# $NetBSD: GENERIC,v 1.459.2.10 2018/06/09 15:12:21 martin Exp $
#
# GENERIC machine description file
#
@@ -22,7 +22,7 @@ include "arch/amd64/conf/std.amd64"
options INCLUDE_CONFIG_FILE # embed config file in kernel binary
-#ident "GENERIC-$Revision: 1.459.2.9 $"
+#ident "GENERIC-$Revision: 1.459.2.10 $"
maxusers 64 # estimated number of users
@@ -77,6 +77,7 @@ options SYSCTL_INCLUDE_DESCR # Include
options SVS # Separate Virtual Space
makeoptions SPECTRE_V2_GCC_MITIGATION=1 # GCC Spectre variant 2
# migitation
+options SPECTRE_V2_GCC_MITIGATION
# CPU features
acpicpu* at cpu? # ACPI CPU (including frequency scaling)
Index: src/sys/arch/amd64/conf/files.amd64
diff -u src/sys/arch/amd64/conf/files.amd64:1.88.8.3 src/sys/arch/amd64/conf/files.amd64:1.88.8.4
--- src/sys/arch/amd64/conf/files.amd64:1.88.8.3 Wed Apr 11 14:23:30 2018
+++ src/sys/arch/amd64/conf/files.amd64 Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-# $NetBSD: files.amd64,v 1.88.8.3 2018/04/11 14:23:30 martin Exp $
+# $NetBSD: files.amd64,v 1.88.8.4 2018/06/09 15:12:21 martin Exp $
#
# new style config file for amd64 architecture
#
@@ -54,6 +54,7 @@ file arch/amd64/amd64/machdep.c machdep
file arch/amd64/amd64/process_machdep.c machdep
file arch/amd64/amd64/trap.c machdep
file arch/x86/x86/fpu.c machdep
+file arch/x86/x86/spectre.c machdep
file arch/x86/x86/dbregs.c machdep
file arch/x86/x86/convert_xmm_s87.c machdep
file arch/amd64/amd64/lock_stubs.S machdep
Index: src/sys/arch/i386/conf/GENERIC
diff -u src/sys/arch/i386/conf/GENERIC:1.1156.2.9 src/sys/arch/i386/conf/GENERIC:1.1156.2.10
--- src/sys/arch/i386/conf/GENERIC:1.1156.2.9 Wed Apr 18 14:45:08 2018
+++ src/sys/arch/i386/conf/GENERIC Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-# $NetBSD: GENERIC,v 1.1156.2.9 2018/04/18 14:45:08 martin Exp $
+# $NetBSD: GENERIC,v 1.1156.2.10 2018/06/09 15:12:21 martin Exp $
#
# GENERIC machine description file
#
@@ -22,7 +22,7 @@ include "arch/i386/conf/std.i386"
options INCLUDE_CONFIG_FILE # embed config file in kernel binary
-#ident "GENERIC-$Revision: 1.1156.2.9 $"
+#ident "GENERIC-$Revision: 1.1156.2.10 $"
maxusers 64 # estimated number of users
@@ -32,6 +32,7 @@ options USER_LDT # user-settable LDT; u
#options PAE # PAE mode (36 bits physical addressing)
makeoptions SPECTRE_V2_GCC_MITIGATION=1 # GCC Spectre variant 2
# migitation
+options SPECTRE_V2_GCC_MITIGATION
# CPU features
acpicpu* at cpu? # ACPI CPU (including frequency scaling)
Index: src/sys/arch/i386/conf/files.i386
diff -u src/sys/arch/i386/conf/files.i386:1.378.6.2 src/sys/arch/i386/conf/files.i386:1.378.6.3
--- src/sys/arch/i386/conf/files.i386:1.378.6.2 Wed Apr 11 14:23:30 2018
+++ src/sys/arch/i386/conf/files.i386 Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-# $NetBSD: files.i386,v 1.378.6.2 2018/04/11 14:23:30 martin Exp $
+# $NetBSD: files.i386,v 1.378.6.3 2018/06/09 15:12:21 martin Exp $
#
# new style config file for i386 architecture
#
@@ -85,6 +85,7 @@ file arch/i386/i386/trap.c
file dev/cons.c
file arch/x86/x86/fpu.c
file arch/x86/x86/dbregs.c
+file arch/x86/x86/spectre.c
file arch/i386/i386/mptramp.S multiprocessor
Index: src/sys/arch/i386/i386/machdep.c
diff -u src/sys/arch/i386/i386/machdep.c:1.782.6.5 src/sys/arch/i386/i386/machdep.c:1.782.6.6
--- src/sys/arch/i386/i386/machdep.c:1.782.6.5 Thu Apr 5 18:15:02 2018
+++ src/sys/arch/i386/i386/machdep.c Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: machdep.c,v 1.782.6.5 2018/04/05 18:15:02 martin Exp $ */
+/* $NetBSD: machdep.c,v 1.782.6.6 2018/06/09 15:12:21 martin Exp $ */
/*-
* Copyright (c) 1996, 1997, 1998, 2000, 2004, 2006, 2008, 2009
@@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.782.6.5 2018/04/05 18:15:02 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: machdep.c,v 1.782.6.6 2018/06/09 15:12:21 martin Exp $");
#include "opt_beep.h"
#include "opt_compat_ibcs2.h"
@@ -1187,6 +1187,9 @@ init386(paddr_t first_avail)
cpu_probe(&cpu_info_primary);
cpu_init_msrs(&cpu_info_primary, true);
+#ifndef XEN
+ cpu_speculation_init(&cpu_info_primary);
+#endif
#ifdef PAE
use_pae = 1;
Index: src/sys/arch/x86/include/cpu.h
diff -u src/sys/arch/x86/include/cpu.h:1.71.2.5 src/sys/arch/x86/include/cpu.h:1.71.2.6
--- src/sys/arch/x86/include/cpu.h:1.71.2.5 Sun Apr 1 08:51:47 2018
+++ src/sys/arch/x86/include/cpu.h Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.h,v 1.71.2.5 2018/04/01 08:51:47 martin Exp $ */
+/* $NetBSD: cpu.h,v 1.71.2.6 2018/06/09 15:12:21 martin Exp $ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@@ -357,6 +357,7 @@ void cpu_kick(struct cpu_info *);
void cpu_pcpuarea_init(struct cpu_info *);
void cpu_svs_init(struct cpu_info *);
+void cpu_speculation_init(struct cpu_info *);
#define curcpu() x86_curcpu()
#define curlwp x86_curlwp()
Index: src/sys/arch/x86/include/specialreg.h
diff -u src/sys/arch/x86/include/specialreg.h:1.98.2.4 src/sys/arch/x86/include/specialreg.h:1.98.2.5
--- src/sys/arch/x86/include/specialreg.h:1.98.2.4 Wed Apr 18 14:14:17 2018
+++ src/sys/arch/x86/include/specialreg.h Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: specialreg.h,v 1.98.2.4 2018/04/18 14:14:17 martin Exp $ */
+/* $NetBSD: specialreg.h,v 1.98.2.5 2018/06/09 15:12:21 martin Exp $ */
/*-
* Copyright (c) 1991 The Regents of the University of California.
@@ -104,10 +104,8 @@
#define XCR0_Hi16_ZMM 0x00000080 /* AVX-512 512 bits upper registers */
/*
- * Known fpu bits - only these get enabled
- * I think the XCR0_BNDREGS and XCR0_BNDCSR would need saving on
- * every context switch.
- * The save are is sized for all the fields below (max 2680 bytes).
+ * Known fpu bits - only these get enabled. The save area is sized for all the
+ * fields below (max 2680 bytes).
*/
#define XCR0_FPU (XCR0_X87 | XCR0_SSE | XCR0_YMM_Hi128 | \
XCR0_Opmask | XCR0_ZMM_Hi256 | XCR0_Hi16_ZMM)
@@ -405,11 +403,12 @@
#define CPUID_SEF_IBRS __BIT(26) /* IBRS / IBPB Speculation Control */
#define CPUID_SEF_STIBP __BIT(27) /* STIBP Speculation Control */
#define CPUID_SEF_ARCH_CAP __BIT(29) /* IA32_ARCH_CAPABILITIES */
+#define CPUID_SEF_SSBD __BIT(31) /* Speculative Store Bypass Disable */
#define CPUID_SEF_FLAGS2 "\20" \
"\3" "AVX512_4VNNIW" "\4" "AVX512_4FMAPS" \
"\33" "IBRS" "\34" "STIBP" \
- "\36" "ARCH_CAP"
+ "\36" "ARCH_CAP" "\40" "SSBD"
/*
* CPUID Processor extended state Enumeration Fn0000000d
@@ -643,6 +642,7 @@
#define MSR_IA32_SPEC_CTRL 0x048
#define IA32_SPEC_CTRL_IBRS 0x01
#define IA32_SPEC_CTRL_STIBP 0x02
+#define IA32_SPEC_CTRL_SSBD 0x04
#define MSR_IA32_PRED_CMD 0x049
#define IA32_PRED_CMD_IBPB 0x01
#define MSR_BIOS_UPDT_TRIG 0x079
@@ -660,6 +660,8 @@
#define MSR_IA32_ARCH_CAPABILITIES 0x10a
#define IA32_ARCH_RDCL_NO 0x01
#define IA32_ARCH_IBRS_ALL 0x02
+#define IA32_ARCH_RSBA 0x04
+#define IA32_ARCH_SSB_NO 0x10
#define MSR_BBL_CR_ADDR 0x116 /* PII+ only */
#define MSR_BBL_CR_DECC 0x118 /* PII+ only */
#define MSR_BBL_CR_CTL 0x119 /* PII+ only */
@@ -855,6 +857,9 @@
#define MSR_LS_CFG 0xc0011020
#define LS_CFG_DIS_LS2_SQUISH 0x02000000
+#define LS_CFG_DIS_SSB_F15H 0x0040000000000000ULL
+#define LS_CFG_DIS_SSB_F16H 0x0000000200000000ULL
+#define LS_CFG_DIS_SSB_F17H 0x0000000000000400ULL
#define MSR_IC_CFG 0xc0011021
#define IC_CFG_DIS_SEQ_PREFETCH 0x00000800
Index: src/sys/arch/x86/x86/x86_machdep.c
diff -u src/sys/arch/x86/x86/x86_machdep.c:1.91.4.2 src/sys/arch/x86/x86/x86_machdep.c:1.91.4.3
--- src/sys/arch/x86/x86/x86_machdep.c:1.91.4.2 Thu Mar 22 16:59:04 2018
+++ src/sys/arch/x86/x86/x86_machdep.c Sat Jun 9 15:12:21 2018
@@ -1,4 +1,4 @@
-/* $NetBSD: x86_machdep.c,v 1.91.4.2 2018/03/22 16:59:04 martin Exp $ */
+/* $NetBSD: x86_machdep.c,v 1.91.4.3 2018/06/09 15:12:21 martin 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.91.4.2 2018/03/22 16:59:04 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.91.4.3 2018/06/09 15:12:21 martin Exp $");
#include "opt_modular.h"
#include "opt_physmem.h"
@@ -1196,6 +1196,11 @@ SYSCTL_SETUP(sysctl_machdep_setup, "sysc
CTL_CREATE, CTL_EOL);
#endif
+#ifndef XEN
+ void sysctl_speculation_init(struct sysctllog **);
+ sysctl_speculation_init(clog);
+#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);
Added files:
Index: src/sys/arch/x86/x86/spectre.c
diff -u /dev/null src/sys/arch/x86/x86/spectre.c:1.19.2.2
--- /dev/null Sat Jun 9 15:12:21 2018
+++ src/sys/arch/x86/x86/spectre.c Sat Jun 9 15:12:21 2018
@@ -0,0 +1,546 @@
+/* $NetBSD: spectre.c,v 1.19.2.2 2018/06/09 15:12:21 martin Exp $ */
+
+/*
+ * Copyright (c) 2018 NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Mitigations for the SpectreV2 and SpectreV4 CPU flaws.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.19.2.2 2018/06/09 15:12:21 martin Exp $");
+
+#include "opt_spectre.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/cpu.h>
+#include <sys/sysctl.h>
+#include <sys/xcall.h>
+
+#include <machine/cpufunc.h>
+#include <machine/cpuvar.h>
+#include <machine/specialreg.h>
+#include <machine/frameasm.h>
+
+#include <x86/cputypes.h>
+
+enum v2_mitigation {
+ V2_MITIGATION_NONE,
+ V2_MITIGATION_AMD_DIS_IND,
+};
+
+enum v4_mitigation {
+ V4_MITIGATION_NONE,
+ V4_MITIGATION_INTEL_SSBD,
+ V4_MITIGATION_INTEL_SSB_NO,
+ V4_MITIGATION_AMD_NONARCH_F15H,
+ V4_MITIGATION_AMD_NONARCH_F16H,
+ V4_MITIGATION_AMD_NONARCH_F17H
+};
+
+static enum v2_mitigation v2_mitigation_method = V2_MITIGATION_NONE;
+static enum v4_mitigation v4_mitigation_method = V4_MITIGATION_NONE;
+
+static bool v2_mitigation_enabled __read_mostly = false;
+static bool v4_mitigation_enabled __read_mostly = false;
+
+static char v2_mitigation_name[64] = "(none)";
+static char v4_mitigation_name[64] = "(none)";
+
+/* --------------------------------------------------------------------- */
+
+static void
+v2_set_name(void)
+{
+ char name[64] = "";
+ size_t nmitig = 0;
+
+#if defined(SPECTRE_V2_GCC_MITIGATION)
+ strlcat(name, "[GCC retpoline]", sizeof(name));
+ nmitig++;
+#endif
+
+ if (!v2_mitigation_enabled) {
+ if (nmitig == 0)
+ strlcat(name, "(none)", sizeof(name));
+ } else {
+ if (nmitig)
+ strlcat(name, " + ", sizeof(name));
+ switch (v2_mitigation_method) {
+ case V2_MITIGATION_AMD_DIS_IND:
+ strlcat(name, "[AMD DIS_IND]", sizeof(name));
+ break;
+ default:
+ panic("%s: impossible", __func__);
+ }
+ }
+
+ strlcpy(v2_mitigation_name, name,
+ sizeof(v2_mitigation_name));
+}
+
+static void
+v2_detect_method(void)
+{
+ struct cpu_info *ci = curcpu();
+
+ if (cpu_vendor == CPUVENDOR_INTEL) {
+ v2_mitigation_method = V2_MITIGATION_NONE;
+ } else if (cpu_vendor == CPUVENDOR_AMD) {
+ /*
+ * The AMD Family 10h manual documents the IC_CFG.DIS_IND bit.
+ * This bit disables the Indirect Branch Predictor.
+ *
+ * Families 12h and 16h are believed to have this bit too, but
+ * their manuals don't document it.
+ */
+ switch (CPUID_TO_FAMILY(ci->ci_signature)) {
+ case 0x10:
+ case 0x12:
+ case 0x16:
+ v2_mitigation_method = V2_MITIGATION_AMD_DIS_IND;
+ break;
+ default:
+ v2_mitigation_method = V2_MITIGATION_NONE;
+ break;
+ }
+ } else {
+ v2_mitigation_method = V2_MITIGATION_NONE;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void
+mitigation_v2_apply_cpu(bool enabled)
+{
+ uint64_t msr;
+
+ switch (v2_mitigation_method) {
+ case V2_MITIGATION_NONE:
+ panic("impossible");
+ case V2_MITIGATION_AMD_DIS_IND:
+ msr = rdmsr(MSR_IC_CFG);
+ if (enabled) {
+ msr |= IC_CFG_DIS_IND;
+ } else {
+ msr &= ~IC_CFG_DIS_IND;
+ }
+ wrmsr(MSR_IC_CFG, msr);
+ break;
+ }
+}
+
+static void
+mitigation_v2_change_cpu(void *arg1, void *arg2)
+{
+ bool enabled = (bool)arg1;
+
+ mitigation_v2_apply_cpu(enabled);
+}
+
+static int
+mitigation_v2_change(bool enabled)
+{
+ struct cpu_info *ci = NULL;
+ CPU_INFO_ITERATOR cii;
+ uint64_t xc;
+
+ v2_detect_method();
+
+ mutex_enter(&cpu_lock);
+
+ /*
+ * We expect all the CPUs to be online.
+ */
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ struct schedstate_percpu *spc = &ci->ci_schedstate;
+ if (spc->spc_flags & SPCF_OFFLINE) {
+ printf("[!] cpu%d offline, SpectreV2 not changed\n",
+ cpu_index(ci));
+ mutex_exit(&cpu_lock);
+ return EOPNOTSUPP;
+ }
+ }
+
+ switch (v2_mitigation_method) {
+ case V2_MITIGATION_NONE:
+ printf("[!] No mitigation available\n");
+ mutex_exit(&cpu_lock);
+ return EOPNOTSUPP;
+ case V2_MITIGATION_AMD_DIS_IND:
+ printf("[+] %s SpectreV2 Mitigation...",
+ enabled ? "Enabling" : "Disabling");
+ xc = xc_broadcast(0, mitigation_v2_change_cpu,
+ (void *)enabled, NULL);
+ xc_wait(xc);
+ printf(" done!\n");
+ v2_mitigation_enabled = enabled;
+ mutex_exit(&cpu_lock);
+ v2_set_name();
+ return 0;
+ default:
+ panic("impossible");
+ }
+}
+
+static int
+sysctl_machdep_spectreV2_mitigated(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ int error;
+ bool val;
+
+ val = *(bool *)rnode->sysctl_data;
+
+ node = *rnode;
+ node.sysctl_data = &val;
+
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error != 0 || newp == NULL)
+ return error;
+
+ if (val == v2_mitigation_enabled)
+ return 0;
+ return mitigation_v2_change(val);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void
+v4_set_name(void)
+{
+ char name[64] = "";
+
+ if (!v4_mitigation_enabled) {
+ strlcat(name, "(none)", sizeof(name));
+ } else {
+ switch (v4_mitigation_method) {
+ case V4_MITIGATION_NONE:
+ panic("%s: impossible", __func__);
+ case V4_MITIGATION_INTEL_SSBD:
+ strlcat(name, "[Intel SSBD]", sizeof(name));
+ break;
+ case V4_MITIGATION_INTEL_SSB_NO:
+ strlcat(name, "[Intel SSB_NO]", sizeof(name));
+ break;
+ case V4_MITIGATION_AMD_NONARCH_F15H:
+ case V4_MITIGATION_AMD_NONARCH_F16H:
+ case V4_MITIGATION_AMD_NONARCH_F17H:
+ strlcat(name, "[AMD NONARCH]", sizeof(name));
+ break;
+ }
+ }
+
+ strlcpy(v4_mitigation_name, name,
+ sizeof(v4_mitigation_name));
+}
+
+static void
+v4_detect_method(void)
+{
+ struct cpu_info *ci = curcpu();
+ u_int descs[4];
+ uint64_t msr;
+
+ if (cpu_vendor == CPUVENDOR_INTEL) {
+ if (cpu_info_primary.ci_feat_val[7] & CPUID_SEF_ARCH_CAP) {
+ msr = rdmsr(MSR_IA32_ARCH_CAPABILITIES);
+ if (msr & IA32_ARCH_SSB_NO) {
+ /*
+ * The processor indicates it is not vulnerable
+ * to the Speculative Store Bypass (SpectreV4)
+ * flaw.
+ */
+ v4_mitigation_method = V4_MITIGATION_INTEL_SSB_NO;
+ return;
+ }
+ }
+ if (cpuid_level >= 7) {
+ x86_cpuid(7, descs);
+ if (descs[3] & CPUID_SEF_SSBD) {
+ /* descs[3] = %edx */
+ v4_mitigation_method = V4_MITIGATION_INTEL_SSBD;
+ return;
+ }
+ }
+ } else if (cpu_vendor == CPUVENDOR_AMD) {
+ switch (CPUID_TO_FAMILY(ci->ci_signature)) {
+ case 0x15:
+ v4_mitigation_method = V4_MITIGATION_AMD_NONARCH_F15H;
+ return;
+ case 0x16:
+ v4_mitigation_method = V4_MITIGATION_AMD_NONARCH_F16H;
+ return;
+ case 0x17:
+ v4_mitigation_method = V4_MITIGATION_AMD_NONARCH_F17H;
+ return;
+ default:
+ break;
+ }
+ }
+
+ v4_mitigation_method = V4_MITIGATION_NONE;
+}
+
+static void
+mitigation_v4_apply_cpu(bool enabled)
+{
+ uint64_t msr, msrval = 0, msrbit = 0;
+
+ switch (v4_mitigation_method) {
+ case V4_MITIGATION_NONE:
+ case V4_MITIGATION_INTEL_SSB_NO:
+ panic("impossible");
+ case V4_MITIGATION_INTEL_SSBD:
+ msrval = MSR_IA32_SPEC_CTRL;
+ msrbit = IA32_SPEC_CTRL_SSBD;
+ break;
+ case V4_MITIGATION_AMD_NONARCH_F15H:
+ msrval = MSR_LS_CFG;
+ msrbit = LS_CFG_DIS_SSB_F15H;
+ break;
+ case V4_MITIGATION_AMD_NONARCH_F16H:
+ msrval = MSR_LS_CFG;
+ msrbit = LS_CFG_DIS_SSB_F16H;
+ break;
+ case V4_MITIGATION_AMD_NONARCH_F17H:
+ msrval = MSR_LS_CFG;
+ msrbit = LS_CFG_DIS_SSB_F17H;
+ break;
+ }
+
+ msr = rdmsr(msrval);
+ if (enabled) {
+ msr |= msrbit;
+ } else {
+ msr &= ~msrbit;
+ }
+ wrmsr(msrval, msr);
+}
+
+static void
+mitigation_v4_change_cpu(void *arg1, void *arg2)
+{
+ bool enabled = (bool)arg1;
+
+ mitigation_v4_apply_cpu(enabled);
+}
+
+static int mitigation_v4_change(bool enabled)
+{
+ struct cpu_info *ci = NULL;
+ CPU_INFO_ITERATOR cii;
+ uint64_t xc;
+
+ v4_detect_method();
+
+ mutex_enter(&cpu_lock);
+
+ /*
+ * We expect all the CPUs to be online.
+ */
+ for (CPU_INFO_FOREACH(cii, ci)) {
+ struct schedstate_percpu *spc = &ci->ci_schedstate;
+ if (spc->spc_flags & SPCF_OFFLINE) {
+ printf("[!] cpu%d offline, SpectreV4 not changed\n",
+ cpu_index(ci));
+ mutex_exit(&cpu_lock);
+ return EOPNOTSUPP;
+ }
+ }
+
+ switch (v4_mitigation_method) {
+ case V4_MITIGATION_NONE:
+ printf("[!] No mitigation available\n");
+ mutex_exit(&cpu_lock);
+ return EOPNOTSUPP;
+ case V4_MITIGATION_INTEL_SSBD:
+ case V4_MITIGATION_AMD_NONARCH_F15H:
+ case V4_MITIGATION_AMD_NONARCH_F16H:
+ case V4_MITIGATION_AMD_NONARCH_F17H:
+ printf("[+] %s SpectreV4 Mitigation...",
+ enabled ? "Enabling" : "Disabling");
+ xc = xc_broadcast(0, mitigation_v4_change_cpu,
+ (void *)enabled, NULL);
+ xc_wait(xc);
+ printf(" done!\n");
+ v4_mitigation_enabled = enabled;
+ mutex_exit(&cpu_lock);
+ v4_set_name();
+ return 0;
+ case V4_MITIGATION_INTEL_SSB_NO:
+ printf("[+] The CPU is not affected by SpectreV4\n");
+ mutex_exit(&cpu_lock);
+ return 0;
+ default:
+ panic("impossible");
+ }
+}
+
+static int
+sysctl_machdep_spectreV4_mitigated(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ int error;
+ bool val;
+
+ val = *(bool *)rnode->sysctl_data;
+
+ node = *rnode;
+ node.sysctl_data = &val;
+
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error != 0 || newp == NULL)
+ return error;
+
+ if (val == v4_mitigation_enabled)
+ return 0;
+ return mitigation_v4_change(val);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void
+cpu_speculation_init(struct cpu_info *ci)
+{
+ /*
+ * Spectre V2.
+ *
+ * cpu0 is the one that detects the method and sets the global
+ * variable.
+ */
+#if 0
+ if (ci == &cpu_info_primary) {
+ v2_detect_method();
+ v2_mitigation_enabled =
+ (v2_mitigation_method != V2_MITIGATION_NONE);
+ v2_set_name();
+ }
+ if (v2_mitigation_method != V2_MITIGATION_NONE) {
+ mitigation_v2_apply_cpu(ci, true);
+ }
+#endif
+
+ /*
+ * Spectre V4.
+ *
+ * cpu0 is the one that detects the method and sets the global
+ * variable.
+ */
+#if 0
+ if (ci == &cpu_info_primary) {
+ v4_detect_method();
+ v4_mitigation_enabled =
+ (v4_mitigation_method != V4_MITIGATION_NONE);
+ v4_set_name();
+ }
+ if (v4_mitigation_method != V4_MITIGATION_NONE) {
+ mitigation_v4_apply_cpu(ci, true);
+ }
+#endif
+}
+
+void sysctl_speculation_init(struct sysctllog **);
+
+void
+sysctl_speculation_init(struct sysctllog **clog)
+{
+ const struct sysctlnode *spec_rnode;
+
+ /* SpectreV1 */
+ spec_rnode = NULL;
+ sysctl_createv(clog, 0, NULL, &spec_rnode,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "spectre_v1", NULL,
+ NULL, 0, NULL, 0,
+ CTL_MACHDEP, CTL_CREATE);
+ sysctl_createv(clog, 0, &spec_rnode, &spec_rnode,
+ CTLFLAG_PERMANENT | CTLFLAG_IMMEDIATE,
+ CTLTYPE_BOOL, "mitigated",
+ SYSCTL_DESCR("Whether Spectre Variant 1 is mitigated"),
+ NULL, 0 /* mitigated=0 */, NULL, 0,
+ CTL_CREATE, CTL_EOL);
+
+ /* SpectreV2 */
+ spec_rnode = NULL;
+ sysctl_createv(clog, 0, NULL, &spec_rnode,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "spectre_v2", NULL,
+ NULL, 0, NULL, 0,
+ CTL_MACHDEP, CTL_CREATE);
+ sysctl_createv(clog, 0, &spec_rnode, NULL,
+ CTLFLAG_READWRITE,
+ CTLTYPE_BOOL, "hwmitigated",
+ SYSCTL_DESCR("Whether Spectre Variant 2 is HW-mitigated"),
+ sysctl_machdep_spectreV2_mitigated, 0,
+ &v2_mitigation_enabled, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(clog, 0, &spec_rnode, NULL,
+ CTLFLAG_PERMANENT | CTLFLAG_IMMEDIATE,
+ CTLTYPE_BOOL, "swmitigated",
+ SYSCTL_DESCR("Whether Spectre Variant 2 is SW-mitigated"),
+#if defined(SPECTRE_V2_GCC_MITIGATION)
+ NULL, 1,
+#else
+ NULL, 0,
+#endif
+ NULL, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(clog, 0, &spec_rnode, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_STRING, "method",
+ SYSCTL_DESCR("Mitigation method in use"),
+ NULL, 0,
+ v2_mitigation_name, 0,
+ CTL_CREATE, CTL_EOL);
+
+ /* SpectreV4 */
+ spec_rnode = NULL;
+ sysctl_createv(clog, 0, NULL, &spec_rnode,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "spectre_v4", NULL,
+ NULL, 0, NULL, 0,
+ CTL_MACHDEP, CTL_CREATE);
+ sysctl_createv(clog, 0, &spec_rnode, NULL,
+ CTLFLAG_READWRITE,
+ CTLTYPE_BOOL, "mitigated",
+ SYSCTL_DESCR("Whether Spectre Variant 4 is mitigated"),
+ sysctl_machdep_spectreV4_mitigated, 0,
+ &v4_mitigation_enabled, 0,
+ CTL_CREATE, CTL_EOL);
+ sysctl_createv(clog, 0, &spec_rnode, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_STRING, "method",
+ SYSCTL_DESCR("Mitigation method in use"),
+ NULL, 0,
+ v4_mitigation_name, 0,
+ CTL_CREATE, CTL_EOL);
+}