From aea3b13bcc08c9ecb0546ccd0a48d6b5c54e0d6a Mon Sep 17 00:00:00 2001 From: Kanth Ghatraju Date: Tue, 16 Jan 2018 16:03:57 -0500 Subject: [PATCH] x86: Clean up IBRS functionality resident in common code The IBRS and IBPB code and defines are resident in common code. This patch moves them to x86 specific locations. The patch also adds the command line options: spectre_v2={on|off|auto} nospectre_v2 on: unconditionally enable off: unconditionally disable, no_spectre_v2, noibrs + noibpb auto: default, on Existing noibrs and noibpb will print a deprecated message Orabug: 27353383 Signed-off-by: Kanth Ghatraju Reviewed-by: Konrad Rzeszutek Wilk Acked-by: John Haxby Signed-off-by: Konrad Rzeszutek Wilk --- arch/x86/include/asm/spec_ctrl.h | 102 +++++++++++++++++++++++++++ arch/x86/kernel/cpu/bugs_64.c | 87 +++++++++++++++++++++++ arch/x86/kernel/cpu/microcode/core.c | 1 + arch/x86/kernel/cpu/scattered.c | 2 +- arch/x86/kvm/svm.c | 1 + arch/x86/kvm/vmx.c | 1 + include/linux/smp.h | 88 ----------------------- kernel/smp.c | 42 ----------- kernel/sysctl.c | 1 + 9 files changed, 194 insertions(+), 131 deletions(-) diff --git a/arch/x86/include/asm/spec_ctrl.h b/arch/x86/include/asm/spec_ctrl.h index e62ea4685a1c..85fe1105f9e1 100644 --- a/arch/x86/include/asm/spec_ctrl.h +++ b/arch/x86/include/asm/spec_ctrl.h @@ -210,5 +210,107 @@ enum { IBRS_ENABLED_USER, IBRS_MAX = IBRS_ENABLED_USER, }; + +/* indicate usage of IBRS to control execution speculation */ +extern int use_ibrs; +extern u32 sysctl_ibrs_enabled; +extern struct mutex spec_ctrl_mutex; + +#define ibrs_supported (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED) +#define ibrs_disabled (use_ibrs & SPEC_CTRL_IBRS_ADMIN_DISABLED) + +#define ibrs_inuse (check_ibrs_inuse()) + +static inline void set_ibrs_inuse(void) +{ + if (ibrs_supported) + use_ibrs |= SPEC_CTRL_IBRS_INUSE; +} + +static inline void clear_ibrs_inuse(void) +{ + use_ibrs &= ~SPEC_CTRL_IBRS_INUSE; +} + +static inline int check_ibrs_inuse(void) +{ + if (use_ibrs & SPEC_CTRL_IBRS_INUSE) + return 1; + else + /* rmb to prevent wrong speculation for security */ + rmb(); + return 0; +} + +static inline void set_ibrs_supported(void) +{ + use_ibrs |= SPEC_CTRL_IBRS_SUPPORTED; + if (!ibrs_disabled) + set_ibrs_inuse(); +} + +static inline void set_ibrs_disabled(void) +{ + use_ibrs |= SPEC_CTRL_IBRS_ADMIN_DISABLED; + if (check_ibrs_inuse()) + clear_ibrs_inuse(); +} + +static inline void clear_ibrs_disabled(void) +{ + use_ibrs &= ~SPEC_CTRL_IBRS_ADMIN_DISABLED; + set_ibrs_inuse(); +} + +/* indicate usage of IBPB to control execution speculation */ +extern int use_ibpb; +extern u32 sysctl_ibpb_enabled; + +#define ibpb_supported (use_ibpb & 0x2) +#define ibpb_disabled (use_ibpb & 0x4) + +#define ibpb_inuse (check_ibpb_inuse()) + +static inline void set_ibpb_inuse(void) +{ + if (ibpb_supported) + use_ibpb |= 0x1; +} + +static inline void clear_ibpb_inuse(void) +{ + use_ibpb &= ~0x1; +} + +static inline int check_ibpb_inuse(void) +{ + if (use_ibpb & 0x1) + return 1; + else + /* rmb to prevent wrong speculation for security */ + rmb(); + return 0; +} + +static inline void set_ibpb_supported(void) +{ + use_ibpb |= 0x2; + if (!ibpb_disabled) + set_ibpb_inuse(); +} + +static inline void set_ibpb_disabled(void) +{ + use_ibpb |= 0x4; + if (check_ibpb_inuse()) + clear_ibpb_inuse(); +} + +static inline void clear_ibpb_disabled(void) +{ + use_ibpb &= ~0x4; + set_ibpb_inuse(); +} + #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_SPEC_CTRL_H */ diff --git a/arch/x86/kernel/cpu/bugs_64.c b/arch/x86/kernel/cpu/bugs_64.c index 90bce3024963..0d471c667860 100644 --- a/arch/x86/kernel/cpu/bugs_64.c +++ b/arch/x86/kernel/cpu/bugs_64.c @@ -10,6 +10,32 @@ #include #include #include +#include +#include + +/* + * use IBRS + * bit 0 = indicate if ibrs is currently in use + * bit 1 = indicate if system supports ibrs + * bit 2 = indicate if admin disables ibrs + */ +int use_ibrs; +EXPORT_SYMBOL(use_ibrs); + +/* + * use IBRS + * bit 0 = indicate if ibpb is currently in use + * bit 1 = indicate if system supports ibpb + * bit 2 = indicate if admin disables ibpb + */ +int use_ibpb; +EXPORT_SYMBOL(use_ibpb); + +/* mutex to serialize IBRS & IBPB control changes */ +DEFINE_MUTEX(spec_ctrl_mutex); +EXPORT_SYMBOL(spec_ctrl_mutex); + +static void __init spectre_v2_parse_cmdline(void); void __init check_bugs(void) { @@ -30,6 +56,67 @@ void __init check_bugs(void) */ if (!direct_gbpages) set_memory_4k((unsigned long)__va(0), 1); + + spectre_v2_parse_cmdline(); +} + +static inline bool match_option(const char *arg, int arglen, const char *opt) +{ + int len = strlen(opt); + + return len == arglen && !strncmp(arg, opt, len); +} + +static void spectre_v2_usage_error(const char *str) +{ + pr_warn("%s arguments for option spectre_v2. " + "Usage spectre_v2={on|off|auto}\n", str); +} + +static void __init spectre_v2_parse_cmdline(void) +{ + char arg[20]; + int ret; + + if (cmdline_find_option_bool(boot_command_line, "noibrs")) { + pr_warn("Deprecated command option noibrs. " + "Use nospectre_v2 instead.\n"); + set_ibrs_disabled(); + } + + if (cmdline_find_option_bool(boot_command_line, "noibpb")) { + pr_warn("Deprecated command option noibpb. " + "Use nospectre_v2 instead.\n"); + set_ibpb_disabled(); + } + + if (cmdline_find_option_bool(boot_command_line, "nospectre_v2")) + goto disable; + + ret = cmdline_find_option(boot_command_line, "spectre_v2", arg, + sizeof(arg)); + + if (ret > 0) { + + if (match_option(arg, ret, "off")) + goto disable; + + if (match_option(arg, ret, "on") || + match_option(arg, ret, "auto")) { + if (!(ibrs_supported || ibpb_supported)) + pr_warn("Spectre_v2 mitigation unsupported\n"); + } else { + spectre_v2_usage_error("Invalid"); + } + } else { + spectre_v2_usage_error("Missing"); + } + + return; + +disable: + set_ibrs_disabled(); + set_ibpb_disabled(); } #ifdef CONFIG_SYSFS diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 44fe1cfee5fe..6b7a843db454 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c @@ -88,6 +88,7 @@ #include #include #include +#include MODULE_DESCRIPTION("Microcode Update Driver"); MODULE_AUTHOR("Tigran Aivazian "); diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c index 887580fdbc0f..af1e5c8d7910 100644 --- a/arch/x86/kernel/cpu/scattered.c +++ b/arch/x86/kernel/cpu/scattered.c @@ -6,7 +6,7 @@ #include #include - +#include #include struct cpuid_bit { diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index fa2cb89c5403..0ec051b77073 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "trace.h" diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 8aa10dd99157..aa9bc4f0a426 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "trace.h" diff --git a/include/linux/smp.h b/include/linux/smp.h index ed927292713b..c4414074bd88 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -50,94 +50,6 @@ void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info), int smp_call_function_single_async(int cpu, struct call_single_data *csd); -#ifdef CONFIG_X86 -#include -/* indicate usage of IBRS to control execution speculation */ -extern int use_ibrs; -extern u32 sysctl_ibrs_enabled; -extern struct mutex spec_ctrl_mutex; -#define ibrs_supported (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED) -#define ibrs_disabled (use_ibrs & SPEC_CTRL_IBRS_ADMIN_DISABLED) -static inline void set_ibrs_inuse(void) -{ - if (ibrs_supported) - use_ibrs |= SPEC_CTRL_IBRS_INUSE; -} -static inline void clear_ibrs_inuse(void) -{ - use_ibrs &= ~SPEC_CTRL_IBRS_INUSE; -} -static inline int check_ibrs_inuse(void) -{ - if (use_ibrs & SPEC_CTRL_IBRS_INUSE) - return 1; - else - /* rmb to prevent wrong speculation for security */ - rmb(); - return 0; -} -static inline void set_ibrs_supported(void) -{ - use_ibrs |= SPEC_CTRL_IBRS_SUPPORTED; - if (!ibrs_disabled) - set_ibrs_inuse(); -} -static inline void set_ibrs_disabled(void) -{ - use_ibrs |= SPEC_CTRL_IBRS_ADMIN_DISABLED; - if (check_ibrs_inuse()) - clear_ibrs_inuse(); -} -static inline void clear_ibrs_disabled(void) -{ - use_ibrs &= ~SPEC_CTRL_IBRS_ADMIN_DISABLED; - set_ibrs_inuse(); -} -#define ibrs_inuse (check_ibrs_inuse()) - -/* indicate usage of IBPB to control execution speculation */ -extern int use_ibpb; -extern u32 sysctl_ibpb_enabled; -#define ibpb_supported (use_ibpb & 0x2) -#define ibpb_disabled (use_ibpb & 0x4) -static inline void set_ibpb_inuse(void) -{ - if (ibpb_supported) - use_ibpb |= 0x1; -} -static inline void clear_ibpb_inuse(void) -{ - use_ibpb &= ~0x1; -} -static inline int check_ibpb_inuse(void) -{ - if (use_ibpb & 0x1) - return 1; - else - /* rmb to prevent wrong speculation for security */ - rmb(); - return 0; -} -static inline void set_ibpb_supported(void) -{ - use_ibpb |= 0x2; - if (!ibpb_disabled) - set_ibpb_inuse(); -} -static inline void set_ibpb_disabled(void) -{ - use_ibpb |= 0x4; - if (check_ibpb_inuse()) - clear_ibpb_inuse(); -} -static inline void clear_ibpb_disabled(void) -{ - use_ibpb &= ~0x4; - set_ibpb_inuse(); -} -#define ibpb_inuse (check_ibpb_inuse()) -#endif - #ifdef CONFIG_SMP #include diff --git a/kernel/smp.c b/kernel/smp.c index d71ad2deb805..e0fc52ca8d63 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -499,29 +499,6 @@ EXPORT_SYMBOL(smp_call_function); unsigned int setup_max_cpus = NR_CPUS; EXPORT_SYMBOL(setup_max_cpus); -/* - * use IBRS - * bit 0 = indicate if ibrs is currently in use - * bit 1 = indicate if system supports ibrs - * bit 2 = indicate if admin disables ibrs -*/ - -int use_ibrs; -EXPORT_SYMBOL(use_ibrs); - -/* - * use IBRS - * bit 0 = indicate if ibpb is currently in use - * bit 1 = indicate if system supports ibpb - * bit 2 = indicate if admin disables ibpb -*/ -int use_ibpb; -EXPORT_SYMBOL(use_ibpb); - -/* mutex to serialize IBRS & IBPB control changes */ -DEFINE_MUTEX(spec_ctrl_mutex); -EXPORT_SYMBOL(spec_ctrl_mutex); - /* * Setup routine for controlling SMP activation * @@ -545,25 +522,6 @@ static int __init nosmp(char *str) early_param("nosmp", nosmp); -static int __init noibrs(char *str) -{ - set_ibrs_disabled(); - - return 0; -} - -early_param("noibrs", noibrs); - -static int __init noibpb(char *str) -{ - set_ibpb_disabled(); - - return 0; -} - -early_param("noibpb", noibpb); - - /* this is hard limit */ static int __init nrcpus(char *str) { diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 5428d939b693..af526f11deb7 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -76,6 +76,7 @@ #include #include #include +#include #endif #ifdef CONFIG_SPARC #include -- 2.50.1