Change the way retpoline is enabled.
Up to now, the retpoline feature was enabled using alternatives
depending whether the X86_FEATURE_RETPOLINE cpu capability was set
or not. The usage of alternatives prevented enabling or disabling
after the boot sequence.
Now, retpoline is enabled using jump labels controlled by the
retpoline_enabled_key static key. This enables retpoline to be
selectively enabled or disabled even after the boot sequence.
Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@oracle.com>
(cherry picked from UEK5 commit
3d01785866e2a73119ed4e35d5cb6b02edf5957a)
Orabug:
28607548
Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
Reviewed-by: Darren Kenny <darren.kenny@oracle.com>
Reviewed-by: Mihai Carabas <mihai.carabas@oracle.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: Brian Maly <brian.maly@oracle.com>
#ifndef _ASM_X86_NOSPEC_BRANCH_H_
#define _ASM_X86_NOSPEC_BRANCH_H_
+#include <linux/jump_label.h>
+
#include <asm/alternative.h>
#include <asm/alternative-asm.h>
#include <asm/cpufeature.h>
#ifdef __ASSEMBLY__
+.extern retpoline_enabled_key
+
/*
* These are the bare retpoline primitives for indirect jmp and call.
* Do not use these directly; they only exist to make the ALTERNATIVE
*/
.macro JMP_NOSPEC reg:req
#ifdef CONFIG_RETPOLINE
+ STATIC_JUMP_IF_TRUE .Lretpoline_jmp_\@, retpoline_enabled_key, def=0
+ jmp *\reg
+.Lretpoline_jmp_\@:
ALTERNATIVE_2 __stringify(jmp *\reg), \
__stringify(RETPOLINE_JMP \reg), X86_FEATURE_RETPOLINE, \
__stringify(lfence; jmp *\reg), X86_FEATURE_RETPOLINE_AMD
.macro CALL_NOSPEC reg:req
#ifdef CONFIG_RETPOLINE
+ STATIC_JUMP_IF_TRUE .Lretpoline_call_\@, retpoline_enabled_key, def=0
+ call *\reg
+ jmp .Ldone_call_\@
+.Lretpoline_call_\@:
ALTERNATIVE_2 __stringify(call *\reg), \
__stringify(RETPOLINE_CALL \reg), X86_FEATURE_RETPOLINE,\
__stringify(lfence; call *\reg), X86_FEATURE_RETPOLINE_AMD
+.Ldone_call_\@:
#else
call *\reg
#endif
* otherwise we'll run out of registers. We don't care about CET
* here, anyway.
*/
-# define CALL_NOSPEC ALTERNATIVE("call *%[thunk_target]\n", \
- " jmp 904f;\n" \
+# define CALL_NOSPEC \
+ "910: .byte " __stringify(STATIC_KEY_INIT_NOP) "\n" \
+ ".pushsection __jump_table, \"aw\"\n" \
+ _ASM_ALIGN "\n" \
+ _ASM_PTR "910b, 904f, retpoline_enabled_key\n" \
+ ".popsection\n" \
+ " call *%[thunk_target];\n" \
+ " jmp 905f;\n" \
" .align 16\n" \
"901: call 903f;\n" \
"902: pause;\n" \
" pushl %[thunk_target];\n" \
" ret;\n" \
" .align 16\n" \
- "904: call 901b;\n", \
- X86_FEATURE_RETPOLINE)
+ "904: call 901b;\n" \
+ "905:"
# define THUNK_TARGET(addr) [thunk_target] "rm" (addr)
#else /* No retpoline for C / inline asm */
extern void unprotected_firmware_begin(void);
extern void unprotected_firmware_end(void);
+DECLARE_STATIC_KEY_FALSE(retpoline_enabled_key);
+
#define ibrs_firmware (use_ibrs & SPEC_CTRL_IBRS_FIRMWARE)
#define ibrs_supported (use_ibrs & SPEC_CTRL_IBRS_SUPPORTED)
#define ibrs_disabled (use_ibrs & SPEC_CTRL_IBRS_ADMIN_DISABLED)
EXPORT_SYMBOL(retpoline_fallback);
+DEFINE_STATIC_KEY_FALSE(retpoline_enabled_key);
+EXPORT_SYMBOL(retpoline_enabled_key);
+
int __init spectre_v2_heuristics_setup(char *p)
{
ssize_t len;
return;
}
+ /*
+ * Set the retpoline capability to advertise that that retpoline
+ * is available, however the retpoline feature is enabled via
+ * the retpoline_enabled_key static key.
+ */
+ if (IS_ENABLED(CONFIG_RETPOLINE)) {
+ setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
+ if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC))
+ pr_err("Spectre mitigation: LFENCE not serializing, setting up generic retpoline\n");
+ else
+ setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD);
+ }
+ }
+
switch (cmd) {
case SPECTRE_V2_CMD_NONE:
disable_ibrs_and_friends(true);
goto out;
retpoline_auto:
- if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+ boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
retpoline_amd:
- if (!boot_cpu_has(X86_FEATURE_LFENCE_RDTSC)) {
- pr_err("LFENCE not serializing. Switching to generic retpoline\n");
- goto retpoline_generic;
- }
mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_AMD :
SPECTRE_V2_RETPOLINE_MINIMAL_AMD;
/* On AMD we do not need IBRS, so lets use the ASM mitigation. */
- setup_force_cpu_cap(X86_FEATURE_RETPOLINE_AMD);
- setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
} else {
retpoline_generic:
mode = retp_compiler() ? SPECTRE_V2_RETPOLINE_GENERIC :
/* But if we can't, then just use retpoline */
}
}
- setup_force_cpu_cap(X86_FEATURE_RETPOLINE);
}
+ /* Enable retpoline */
+ static_branch_enable(&retpoline_enabled_key);
display:
spectre_v2_enabled = mode;
pr_info("%s\n", spectre_v2_strings[mode]);