Add the minimal infrastructure to control the speculation control feature. - Integrate it into the spectre_v2 coammand line parser and the mitigation selector function. The conditional selector function is a placeholder right now, which needs to be expanded with CPU specific decision functions. - Provide a static key for the actual code control. - Provide a init function which is called after jump label patching is functional. - Provide an interface for the late micro code loader to allow late discovery of the IBRS support. Not yet functional. Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/nospec-branch.h | 9 +++++ arch/x86/kernel/cpu/Makefile | 1 arch/x86/kernel/cpu/bugs.c | 17 +++++++++ arch/x86/kernel/cpu/specctrl.c | 62 +++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+) --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -3,6 +3,8 @@ #ifndef __NOSPEC_BRANCH_H__ #define __NOSPEC_BRANCH_H__ +#include + #include #include #include @@ -165,5 +167,12 @@ enum spectre_v2_mitigation { enum spectre_v2_mitigation spectre_v2_enabled; void spectre_v2_select_mitigation(void); +DECLARE_STATIC_KEY_FALSE(specctrl_ibrs); + +void specctrl_init_features(void); +void specctrl_update_features(void); +bool specctrl_force_enable_ibrs(void); +bool specctrl_cond_enable_ibrs(bool full_retpoline); + #endif /* __ASSEMBLY__ */ #endif /* __NOSPEC_BRANCH_H__ */ --- a/arch/x86/kernel/cpu/Makefile +++ b/arch/x86/kernel/cpu/Makefile @@ -24,6 +24,7 @@ obj-y += match.o obj-y += bugs.o obj-$(CONFIG_CPU_FREQ) += aperfmperf.o obj-y += cpuid-deps.o +obj-y += specctrl.c obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -79,6 +79,7 @@ enum spectre_v2_mitigation_cmd { SPECTRE_V2_CMD_RETPOLINE, SPECTRE_V2_CMD_RETPOLINE_GENERIC, SPECTRE_V2_CMD_RETPOLINE_AMD, + SPECTRE_V2_CMD_IBRS, }; static const char *spectre_v2_strings[] = { @@ -87,6 +88,7 @@ static const char *spectre_v2_strings[] [SPECTRE_V2_RETPOLINE_MINIMAL_AMD] = "Mitigation: Minimal AMD ASM retpoline", [SPECTRE_V2_RETPOLINE_GENERIC] = "Mitigation: Full generic retpoline", [SPECTRE_V2_RETPOLINE_AMD] = "Mitigation: Full AMD retpoline", + [SPECTRE_V2_IBRS] = "Mitigation: Indirect Branch Restricted Speculation", }; #undef pr_fmt @@ -163,6 +165,7 @@ static void __init spectre_v2_check_boot void spectre_v2_select_mitigation(void) { + bool full_retpoline = IS_ENABLED(CONFIG_RETPOLINE) && retp_compiler(); enum spectre_v2_mitigation mode = SPECTRE_V2_NONE; /* @@ -178,9 +181,22 @@ void spectre_v2_select_mitigation(void) case SPECTRE_V2_CMD_NONE: return; + case SPECTRE_V2_CMD_IBRS: + /* Command line requested IBRS. Try to enable it */ + if (specctrl_force_enable_ibrs()) { + mode = SPECTRE_V2_IBRS; + goto set_mode; + } + /* FALLTRHU */ + case SPECTRE_V2_CMD_FORCE: /* FALLTRHU */ case SPECTRE_V2_CMD_AUTO: + /* Check whether the CPU prefers to have IBRS */ + if (specctrl_cond_enable_ibrs(full_retpoline)) { + mode = SPECTRE_V2_IBRS; + goto set_mode; + } goto retpoline_auto; case SPECTRE_V2_CMD_RETPOLINE_AMD: @@ -223,6 +239,7 @@ void spectre_v2_select_mitigation(void) setup_force_cpu_cap(X86_FEATURE_RETPOLINE); } +set_mode: if (spectre_v2_enabled == mode) return; spectre_v2_enabled = mode; --- /dev/null +++ b/arch/x86/kernel/cpu/specctrl.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +/* Static key to control enablement of IBRS */ +DEFINE_STATIC_KEY_FALSE(specctrl_ibrs); + +/** + * specctrl_init_features - Init speculation control features + * + * Called after static key patching is functional. The decision which + * mitigation to use has been made already in check_bugs() before patching + * the alternatives. + */ +void __init specctrl_init_features(void) +{ + if (spectre_v2_enabled != SPECTRE_V2_IBRS) + return; + + static_branch_enable(&specctrl_ibrs); +} + +/** + * specctrl_update_features - Update the speculation control features + * + * Called after a late microcode load changed CPU feature bits. + * + * Note: This is called with CPU hotplug lock and microcode mutex held. + */ +void specctrl_update_features(void) +{ + if (static_key_enabled(&specctrl_ibrs)) + return; + + /* + * FIXME: Either the CPU bits need to be reevaluated here or its + * done in the late microcode loader. Borislav ? + */ + spectre_v2_select_mitigation(); + if (spectre_v2_enabled != SPECTRE_V2_IBRS) + return; + static_branch_enable_cpuslocked(&specctrl_ibrs); +} + +bool specctrl_force_enable_ibrs(void) +{ + if (!boot_cpu_has(X86_FEATURE_SPEC_CTRL)) + return false; + return true; +} + +bool specctrl_cond_enable_ibrs(bool full_retpoline) +{ + if (!boot_cpu_has(X86_FEATURE_SPEC_CTRL)) + return false; + /* + * FIXME: Add logic here to decide what the best option is for a + * particular CPU. + */ + return true; +}