Module Name: src Committed By: maxv Date: Wed Mar 28 14:56:59 UTC 2018
Modified Files: src/sys/arch/x86/conf: files.x86 src/sys/arch/x86/x86: cpu.c Added Files: src/sys/arch/x86/x86: spectre.c Log Message: Move the SpectreV2 mitigation code into a dedicated spectre.c file. The content of the file is taken from the end of cpu.c, and is copied as-is. To generate a diff of this commit: cvs rdiff -u -r1.98 -r1.99 src/sys/arch/x86/conf/files.x86 cvs rdiff -u -r1.152 -r1.153 src/sys/arch/x86/x86/cpu.c cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/spectre.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/conf/files.x86 diff -u src/sys/arch/x86/conf/files.x86:1.98 src/sys/arch/x86/conf/files.x86:1.99 --- src/sys/arch/x86/conf/files.x86:1.98 Sun Mar 18 00:17:17 2018 +++ src/sys/arch/x86/conf/files.x86 Wed Mar 28 14:56:59 2018 @@ -1,4 +1,4 @@ -# $NetBSD: files.x86,v 1.98 2018/03/18 00:17:17 christos Exp $ +# $NetBSD: files.x86,v 1.99 2018/03/28 14:56:59 maxv Exp $ # options for MP configuration through the MP spec defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG MPBIOS_SCANPCI @@ -97,6 +97,7 @@ file arch/x86/x86/pmap.c machdep file arch/x86/x86/x86_tlb.c machdep file arch/x86/x86/pmc.c machdep file arch/x86/x86/procfs_machdep.c procfs +file arch/x86/x86/spectre.c machdep file arch/x86/x86/svs.c machdep & svs file arch/x86/x86/sys_machdep.c machdep file arch/x86/x86/syscall.c machdep Index: src/sys/arch/x86/x86/cpu.c diff -u src/sys/arch/x86/x86/cpu.c:1.152 src/sys/arch/x86/x86/cpu.c:1.153 --- src/sys/arch/x86/x86/cpu.c:1.152 Thu Mar 15 09:17:31 2018 +++ src/sys/arch/x86/x86/cpu.c Wed Mar 28 14:56:59 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.c,v 1.152 2018/03/15 09:17:31 maxv Exp $ */ +/* $NetBSD: cpu.c,v 1.153 2018/03/28 14:56:59 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.152 2018/03/15 09:17:31 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.153 2018/03/28 14:56:59 maxv Exp $"); #include "opt_ddb.h" #include "opt_mpbios.h" /* for MPDEBUG */ @@ -82,8 +82,6 @@ __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> @@ -106,7 +104,6 @@ __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> @@ -1337,175 +1334,3 @@ cpu_kick(struct cpu_info *ci) { x86_send_ipi(ci, 0); } - -/* --------------------------------------------------------------------- */ - -/* - * 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) { - /* - * 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: - 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; -} Added files: Index: src/sys/arch/x86/x86/spectre.c diff -u /dev/null src/sys/arch/x86/x86/spectre.c:1.1 --- /dev/null Wed Mar 28 14:56:59 2018 +++ src/sys/arch/x86/x86/spectre.c Wed Mar 28 14:56:59 2018 @@ -0,0 +1,215 @@ +/* $NetBSD: spectre.c,v 1.1 2018/03/28 14:56:59 maxv 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 Spectre V2 CPU flaw. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.1 2018/03/28 14:56:59 maxv Exp $"); + +#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 <x86/cputypes.h> + +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) { + /* + * 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: + 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; +}