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); +}