@@ -175,6 +175,7 @@ GLOBAL(entry_SYSCALL_64_after_hwframe)
/* clobbers %rax, make sure it is after saving the syscall nr */
IBRS_ENTER
+ CLEAR_BRANCH_HISTORY
call do_syscall_64 /* returns with IRQs disabled */
@@ -1768,3 +1769,60 @@ ENTRY(rewind_stack_and_make_dead)
call make_task_dead
END(rewind_stack_and_make_dead)
+
+/*
+ * This sequence executes branches in order to remove user branch information
+ * from the branch history tracker in the Branch Predictor, therefore removing
+ * user influence on subsequent BTB lookups.
+ *
+ * It should be used on parts prior to Alder Lake. Newer parts should use the
+ * BHI_DIS_S hardware control instead. If a pre-Alder Lake part is being
+ * virtualized on newer hardware the VMM should protect against BHI attacks by
+ * setting BHI_DIS_S for the guests.
+ *
+ * CALLs/RETs are necessary to prevent Loop Stream Detector(LSD) from engaging
+ * and not clearing the branch history. The call tree looks like:
+ *
+ * call 1
+ * call 2
+ * call 2
+ * call 2
+ * call 2
+ * call 2
+ * ret
+ * ret
+ * ret
+ * ret
+ * ret
+ * ret
+ *
+ * This means that the stack is non-constant and ORC can't unwind it with %rsp
+ * alone. Therefore we unconditionally set up the frame pointer, which allows
+ * ORC to unwind properly.
+ *
+ * The alignment is for performance and not for safety, and may be safely
+ * refactored in the future if needed.
+ */
+ENTRY(clear_bhb_loop)
+ push %rbp
+ mov %rsp, %rbp
+ movl $5, %ecx
+ call 1f
+ jmp 5f
+ .align 64, 0xcc
+1: call 2f
+ RET
+ .align 64, 0xcc
+2: movl $5, %eax
+3: jmp 4f
+ nop
+4: sub $1, %eax
+ jnz 3b
+ sub $1, %ecx
+ jnz 1b
+ RET
+5: lfence
+ pop %rbp
+ RET
+END(clear_bhb_loop)
+EXPORT_SYMBOL_GPL(clear_bhb_loop)
@@ -108,6 +108,7 @@ ENTRY(entry_SYSENTER_compat)
cld
IBRS_ENTER
+ CLEAR_BRANCH_HISTORY
/*
* SYSENTER doesn't filter flags, so we need to clear NT and AC
@@ -257,6 +258,7 @@ GLOBAL(entry_SYSCALL_compat_after_hwframe)
TRACE_IRQS_OFF
IBRS_ENTER
+ CLEAR_BRANCH_HISTORY
movq %rsp, %rdi
call do_fast_syscall_32
@@ -417,6 +419,7 @@ ENTRY(entry_INT80_compat)
*/
TRACE_IRQS_OFF
IBRS_ENTER
+ CLEAR_BRANCH_HISTORY
movq %rsp, %rdi
call do_int80_syscall_32
@@ -382,6 +382,14 @@
#define X86_FEATURE_SEV_ES (19*32+ 3) /* AMD Secure Encrypted Virtualization - Encrypted State */
#define X86_FEATURE_SME_COHERENT (19*32+10) /* "" AMD hardware-enforced cache coherency */
+/*
+ * Extended auxiliary flags: Linux defined - for features scattered in various
+ * CPUID levels like 0x80000022, etc and Linux defined features.
+ *
+ * Reuse free bits when adding new feature flags!
+ */
+#define X86_FEATURE_CLEAR_BHB_LOOP (21*32+ 1) /* "" Clear branch history at syscall entry using SW loop */
+
/*
* BUG word(s)
*/
@@ -175,6 +175,14 @@
.Lskip_rsb_\@:
.endm
+#ifdef CONFIG_X86_64
+.macro CLEAR_BRANCH_HISTORY
+ ALTERNATIVE "", "call clear_bhb_loop", X86_FEATURE_CLEAR_BHB_LOOP
+.endm
+#else
+#define CLEAR_BRANCH_HISTORY
+#endif
+
#else /* __ASSEMBLY__ */
#define ANNOTATE_RETPOLINE_SAFE \
@@ -183,6 +191,10 @@
_ASM_PTR " 999b\n\t" \
".popsection\n\t"
+#ifdef CONFIG_X86_64
+extern void clear_bhb_loop(void);
+#endif
+
#ifdef CONFIG_RETPOLINE
#ifdef CONFIG_X86_64
@@ -198,6 +198,8 @@ SYM_INNER_LABEL(vmx_vmexit, SYM_L_GLOBAL)
call vmx_spec_ctrl_restore_host
+ CLEAR_BRANCH_HISTORY
+
/* Put return value in AX */
mov %_ASM_BX, %_ASM_AX