The RETPOLINE_AMD feature relies on a serializing LFENCE for speculation control. For AMD hardware, only set RETPOLINE_AMD if LFENCE is a serializing instruction, which is indicated by the LFENCE_RDTSC feature.
The call to spectre_v2_check_boottime_disable() is currently before the boot CPU is identified and, therefore, able to set the LFENCE_RDTSC feature. Move the call to spectre_v2_check_boottime_disable() to after identify_boot_cpu() in check_bugs(). Also, protect against specifying spectre_v2=retpoline,amd for non-AMD hardware and fall-back to the generic retpoline. Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Tom Lendacky <[email protected]> --- arch/x86/include/asm/nospec-branch.h | 2 -- arch/x86/kernel/cpu/bugs.c | 22 +++++++++++++++++----- arch/x86/kernel/setup.c | 2 -- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/arch/x86/include/asm/nospec-branch.h b/arch/x86/include/asm/nospec-branch.h index 8ddf851..6bda2c0 100644 --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -152,7 +152,5 @@ # define THUNK_TARGET(addr) [thunk_target] "rm" (addr) #endif -void spectre_v2_check_boottime_disable(void); - #endif /* __ASSEMBLY__ */ #endif /* __NOSPEC_BRANCH_H__ */ diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index b957f77..815dee2 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -24,6 +24,8 @@ #include <asm/pgtable.h> #include <asm/set_memory.h> +static void __init spectre_v2_check_boottime_disable(void); + void __init check_bugs(void) { identify_boot_cpu(); @@ -33,6 +35,9 @@ void __init check_bugs(void) print_cpu_info(&boot_cpu_data); } + /* Select the proper spectre mitigation before patching alternatives */ + spectre_v2_check_boottime_disable(); + #ifdef CONFIG_X86_32 /* * Check whether we are able to run this kernel safely on SMP. @@ -106,7 +111,7 @@ static inline bool match_option(const char *arg, int arglen, const char *opt) return len == arglen && !strncmp(arg, opt, len); } -void __init spectre_v2_check_boottime_disable(void) +static void __init spectre_v2_check_boottime_disable(void) { char arg[20]; int ret; @@ -148,14 +153,21 @@ void __init spectre_v2_check_boottime_disable(void) retpoline: if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { retpoline_amd: + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD || + !boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) { + pr_info("AMD retpoline not supported, fall back to generic\n"); + goto retpoline_generic; + } + spectre_v2_enabled = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD : SPECTRE_V2_RETPOLINE_MINIMAL_AMD; setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD); - } else { - retpoline_generic: - spectre_v2_enabled = retp_compiler() ? - SPECTRE_V2_RETPOLINE_GENERIC : SPECTRE_V2_RETPOLINE_MINIMAL; + setup_force_cpu_cap(X86_FEATURE_RETPOLINE); + return; } +retpoline_generic: + spectre_v2_enabled = retp_compiler() ? + SPECTRE_V2_RETPOLINE_GENERIC : SPECTRE_V2_RETPOLINE_MINIMAL; setup_force_cpu_cap(X86_FEATURE_RETPOLINE); return; #else diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 9fb4f9d..b5a908b 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1322,8 +1322,6 @@ void __init setup_arch(char **cmdline_p) register_refined_jiffies(CLOCK_TICK_RATE); - spectre_v2_check_boottime_disable(); - #ifdef CONFIG_EFI if (efi_enabled(EFI_BOOT)) efi_apply_memmap_quirks();

