Matthias Brugger 214f30
From: "Russell King (Oracle)" <rmk+kernel@armlinux.org.uk>
Matthias Brugger 214f30
Date: Thu, 10 Feb 2022 16:05:45 +0000
Matthias Brugger 214f30
Subject: ARM: Spectre-BHB workaround
Matthias Brugger 214f30
Git-commit: b9baf5c8c5c356757f4f9d8180b5e9d234065bc3
Matthias Brugger 214f30
Patch-mainline: v5.17 or v5.17-rc8 (next release)
Matthias Brugger 214f30
References: bsc#1085308 CVE-2022-23960
Matthias Brugger 214f30
Matthias Brugger 214f30
Workaround the Spectre BHB issues for Cortex-A15, Cortex-A57,
Matthias Brugger 214f30
Cortex-A72, Cortex-A73 and Cortex-A75. We also include Brahma B15 as
Matthias Brugger 214f30
well to be safe, which is affected by Spectre V2 in the same ways as
Matthias Brugger 214f30
Cortex-A15.
Matthias Brugger 214f30
Matthias Brugger 214f30
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Matthias Brugger 214f30
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Matthias Brugger 214f30
Signed-off-by: Matthias Brugger <mbrugger@suse.com>
Matthias Brugger 214f30
---
Matthias Brugger 214f30
 arch/arm/include/asm/assembler.h   | 10 ++++
Matthias Brugger 214f30
 arch/arm/include/asm/spectre.h     |  4 ++
Matthias Brugger 214f30
 arch/arm/include/asm/vmlinux.lds.h | 18 +++++--
Matthias Brugger 214f30
 arch/arm/kernel/entry-armv.S       | 79 +++++++++++++++++++++++++++---
Matthias Brugger 214f30
 arch/arm/kernel/entry-common.S     | 24 +++++++++
Matthias Brugger 214f30
 arch/arm/kernel/spectre.c          |  4 ++
Matthias Brugger 214f30
 arch/arm/kernel/traps.c            | 38 ++++++++++++++
Matthias Brugger 214f30
 arch/arm/mm/Kconfig                | 10 ++++
Matthias Brugger 214f30
 arch/arm/mm/proc-v7-bugs.c         | 76 ++++++++++++++++++++++++++++
Matthias Brugger 214f30
 9 files changed, 254 insertions(+), 9 deletions(-)
Matthias Brugger 214f30
Matthias Brugger 214f30
diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h
Matthias Brugger 214f30
index 7d23d4bb2168..49ea603fc8e3 100644
Matthias Brugger 214f30
--- a/arch/arm/include/asm/assembler.h
Matthias Brugger 214f30
+++ b/arch/arm/include/asm/assembler.h
Matthias Brugger 214f30
@@ -107,6 +107,16 @@
Matthias Brugger 214f30
 	.endm
Matthias Brugger 214f30
 #endif
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+#if __LINUX_ARM_ARCH__ < 7
Matthias Brugger 214f30
+	.macro	dsb, args
Matthias Brugger 214f30
+	mcr	p15, 0, r0, c7, c10, 4
Matthias Brugger 214f30
+	.endm
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	.macro	isb, args
Matthias Brugger 214f30
+	mcr	p15, 0, r0, c7, r5, 4
Matthias Brugger 214f30
+	.endm
Matthias Brugger 214f30
+#endif
Matthias Brugger 214f30
+
Matthias Brugger 214f30
 	.macro asm_trace_hardirqs_off, save=1
Matthias Brugger 214f30
 #if defined(CONFIG_TRACE_IRQFLAGS)
Matthias Brugger 214f30
 	.if \save
Matthias Brugger 214f30
diff --git a/arch/arm/include/asm/spectre.h b/arch/arm/include/asm/spectre.h
Matthias Brugger 214f30
index 8a9019e08dba..d1fa5607d3aa 100644
Matthias Brugger 214f30
--- a/arch/arm/include/asm/spectre.h
Matthias Brugger 214f30
+++ b/arch/arm/include/asm/spectre.h
Matthias Brugger 214f30
@@ -14,6 +14,7 @@ enum {
Matthias Brugger 214f30
 	__SPECTRE_V2_METHOD_ICIALLU,
Matthias Brugger 214f30
 	__SPECTRE_V2_METHOD_SMC,
Matthias Brugger 214f30
 	__SPECTRE_V2_METHOD_HVC,
Matthias Brugger 214f30
+	__SPECTRE_V2_METHOD_LOOP8,
Matthias Brugger 214f30
 };
Matthias Brugger 214f30
 
Matthias Brugger 214f30
 enum {
Matthias Brugger 214f30
@@ -21,8 +22,11 @@ enum {
Matthias Brugger 214f30
 	SPECTRE_V2_METHOD_ICIALLU = BIT(__SPECTRE_V2_METHOD_ICIALLU),
Matthias Brugger 214f30
 	SPECTRE_V2_METHOD_SMC = BIT(__SPECTRE_V2_METHOD_SMC),
Matthias Brugger 214f30
 	SPECTRE_V2_METHOD_HVC = BIT(__SPECTRE_V2_METHOD_HVC),
Matthias Brugger 214f30
+	SPECTRE_V2_METHOD_LOOP8 = BIT(__SPECTRE_V2_METHOD_LOOP8),
Matthias Brugger 214f30
 };
Matthias Brugger 214f30
 
Matthias Brugger 214f30
 void spectre_v2_update_state(unsigned int state, unsigned int methods);
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+int spectre_bhb_update_vectors(unsigned int method);
Matthias Brugger 214f30
+
Matthias Brugger 214f30
 #endif
Matthias Brugger 214f30
diff --git a/arch/arm/include/asm/vmlinux.lds.h b/arch/arm/include/asm/vmlinux.lds.h
Matthias Brugger 214f30
index e02710d17cf9..0ef21bfae9f6 100644
Matthias Brugger 214f30
--- a/arch/arm/include/asm/vmlinux.lds.h
Matthias Brugger 214f30
+++ b/arch/arm/include/asm/vmlinux.lds.h
Matthias Brugger 214f30
@@ -116,11 +116,23 @@
Matthias Brugger 214f30
  */
Matthias Brugger 214f30
 #define ARM_VECTORS							\
Matthias Brugger 214f30
 	__vectors_lma = .;						\
Matthias Brugger 214f30
-	.vectors 0xffff0000 : AT(__vectors_start) {			\
Matthias Brugger 214f30
-		*(.vectors)						\
Matthias Brugger 214f30
+	OVERLAY 0xffff0000 : NOCROSSREFS AT(__vectors_lma) {		\
Matthias Brugger 214f30
+		.vectors {						\
Matthias Brugger 214f30
+			*(.vectors)					\
Matthias Brugger 214f30
+		}							\
Matthias Brugger 214f30
+		.vectors.bhb.loop8 {					\
Matthias Brugger 214f30
+			*(.vectors.bhb.loop8)				\
Matthias Brugger 214f30
+		}							\
Matthias Brugger 214f30
+		.vectors.bhb.bpiall {					\
Matthias Brugger 214f30
+			*(.vectors.bhb.bpiall)				\
Matthias Brugger 214f30
+		}							\
Matthias Brugger 214f30
 	}								\
Matthias Brugger 214f30
 	ARM_LMA(__vectors, .vectors);					\
Matthias Brugger 214f30
-	. = __vectors_lma + SIZEOF(.vectors);				\
Matthias Brugger 214f30
+	ARM_LMA(__vectors_bhb_loop8, .vectors.bhb.loop8);		\
Matthias Brugger 214f30
+	ARM_LMA(__vectors_bhb_bpiall, .vectors.bhb.bpiall);		\
Matthias Brugger 214f30
+	. = __vectors_lma + SIZEOF(.vectors) +				\
Matthias Brugger 214f30
+		SIZEOF(.vectors.bhb.loop8) +				\
Matthias Brugger 214f30
+		SIZEOF(.vectors.bhb.bpiall);				\
Matthias Brugger 214f30
 									\
Matthias Brugger 214f30
 	__stubs_lma = .;						\
Matthias Brugger 214f30
 	.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_lma) {		\
Matthias Brugger 214f30
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
Matthias Brugger 214f30
index 5cd057859fe9..676703cbfe4b 100644
Matthias Brugger 214f30
--- a/arch/arm/kernel/entry-armv.S
Matthias Brugger 214f30
+++ b/arch/arm/kernel/entry-armv.S
Matthias Brugger 214f30
@@ -1002,12 +1002,11 @@ vector_\name:
Matthias Brugger 214f30
 	sub	lr, lr, #\correction
Matthias Brugger 214f30
 	.endif
Matthias Brugger 214f30
 
Matthias Brugger 214f30
-	@
Matthias Brugger 214f30
-	@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
Matthias Brugger 214f30
-	@ (parent CPSR)
Matthias Brugger 214f30
-	@
Matthias Brugger 214f30
+	@ Save r0, lr_<exception> (parent PC)
Matthias Brugger 214f30
 	stmia	sp, {r0, lr}		@ save r0, lr
Matthias Brugger 214f30
-	mrs	lr, spsr
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	@ Save spsr_<exception> (parent CPSR)
Matthias Brugger 214f30
+2:	mrs	lr, spsr
Matthias Brugger 214f30
 	str	lr, [sp, #8]		@ save spsr
Matthias Brugger 214f30
 
Matthias Brugger 214f30
 	@
Matthias Brugger 214f30
@@ -1028,6 +1027,44 @@ vector_\name:
Matthias Brugger 214f30
 	movs	pc, lr			@ branch to handler in SVC mode
Matthias Brugger 214f30
 ENDPROC(vector_\name)
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
Matthias Brugger 214f30
+	.subsection 1
Matthias Brugger 214f30
+	.align 5
Matthias Brugger 214f30
+vector_bhb_loop8_\name:
Matthias Brugger 214f30
+	.if \correction
Matthias Brugger 214f30
+	sub	lr, lr, #\correction
Matthias Brugger 214f30
+	.endif
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	@ Save r0, lr_<exception> (parent PC)
Matthias Brugger 214f30
+	stmia	sp, {r0, lr}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	@ bhb workaround
Matthias Brugger 214f30
+	mov	r0, #8
Matthias Brugger 214f30
+1:	b	. + 4
Matthias Brugger 214f30
+	subs	r0, r0, #1
Matthias Brugger 214f30
+	bne	1b
Matthias Brugger 214f30
+	dsb
Matthias Brugger 214f30
+	isb
Matthias Brugger 214f30
+	b	2b
Matthias Brugger 214f30
+ENDPROC(vector_bhb_loop8_\name)
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+vector_bhb_bpiall_\name:
Matthias Brugger 214f30
+	.if \correction
Matthias Brugger 214f30
+	sub	lr, lr, #\correction
Matthias Brugger 214f30
+	.endif
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	@ Save r0, lr_<exception> (parent PC)
Matthias Brugger 214f30
+	stmia	sp, {r0, lr}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	@ bhb workaround
Matthias Brugger 214f30
+	mcr	p15, 0, r0, c7, c5, 6	@ BPIALL
Matthias Brugger 214f30
+	@ isb not needed due to "movs pc, lr" in the vector stub
Matthias Brugger 214f30
+	@ which gives a "context synchronisation".
Matthias Brugger 214f30
+	b	2b
Matthias Brugger 214f30
+ENDPROC(vector_bhb_bpiall_\name)
Matthias Brugger 214f30
+	.previous
Matthias Brugger 214f30
+#endif
Matthias Brugger 214f30
+
Matthias Brugger 214f30
 	.align	2
Matthias Brugger 214f30
 	@ handler addresses follow this label
Matthias Brugger 214f30
 1:
Matthias Brugger 214f30
@@ -1036,6 +1073,10 @@ ENDPROC(vector_\name)
Matthias Brugger 214f30
 	.section .stubs, "ax", %progbits
Matthias Brugger 214f30
 	@ This must be the first word
Matthias Brugger 214f30
 	.word	vector_swi
Matthias Brugger 214f30
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
Matthias Brugger 214f30
+	.word	vector_bhb_loop8_swi
Matthias Brugger 214f30
+	.word	vector_bhb_bpiall_swi
Matthias Brugger 214f30
+#endif
Matthias Brugger 214f30
 
Matthias Brugger 214f30
 vector_rst:
Matthias Brugger 214f30
  ARM(	swi	SYS_ERROR0	)
Matthias Brugger 214f30
@@ -1150,8 +1191,10 @@ vector_addrexcptn:
Matthias Brugger 214f30
  * FIQ "NMI" handler
Matthias Brugger 214f30
  *-----------------------------------------------------------------------------
Matthias Brugger 214f30
  * Handle a FIQ using the SVC stack allowing FIQ act like NMI on x86
Matthias Brugger 214f30
- * systems.
Matthias Brugger 214f30
+ * systems. This must be the last vector stub, so lets place it in its own
Matthias Brugger 214f30
+ * subsection.
Matthias Brugger 214f30
  */
Matthias Brugger 214f30
+	.subsection 2
Matthias Brugger 214f30
 	vector_stub	fiq, FIQ_MODE, 4
Matthias Brugger 214f30
 
Matthias Brugger 214f30
 	.long	__fiq_usr			@  0  (USR_26 / USR_32)
Matthias Brugger 214f30
@@ -1184,6 +1227,30 @@ vector_addrexcptn:
Matthias Brugger 214f30
 	W(b)	vector_irq
Matthias Brugger 214f30
 	W(b)	vector_fiq
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
Matthias Brugger 214f30
+	.section .vectors.bhb.loop8, "ax", %progbits
Matthias Brugger 214f30
+.L__vectors_bhb_loop8_start:
Matthias Brugger 214f30
+	W(b)	vector_rst
Matthias Brugger 214f30
+	W(b)	vector_bhb_loop8_und
Matthias Brugger 214f30
+	W(ldr)	pc, .L__vectors_bhb_loop8_start + 0x1004
Matthias Brugger 214f30
+	W(b)	vector_bhb_loop8_pabt
Matthias Brugger 214f30
+	W(b)	vector_bhb_loop8_dabt
Matthias Brugger 214f30
+	W(b)	vector_addrexcptn
Matthias Brugger 214f30
+	W(b)	vector_bhb_loop8_irq
Matthias Brugger 214f30
+	W(b)	vector_bhb_loop8_fiq
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	.section .vectors.bhb.bpiall, "ax", %progbits
Matthias Brugger 214f30
+.L__vectors_bhb_bpiall_start:
Matthias Brugger 214f30
+	W(b)	vector_rst
Matthias Brugger 214f30
+	W(b)	vector_bhb_bpiall_und
Matthias Brugger 214f30
+	W(ldr)	pc, .L__vectors_bhb_bpiall_start + 0x1008
Matthias Brugger 214f30
+	W(b)	vector_bhb_bpiall_pabt
Matthias Brugger 214f30
+	W(b)	vector_bhb_bpiall_dabt
Matthias Brugger 214f30
+	W(b)	vector_addrexcptn
Matthias Brugger 214f30
+	W(b)	vector_bhb_bpiall_irq
Matthias Brugger 214f30
+	W(b)	vector_bhb_bpiall_fiq
Matthias Brugger 214f30
+#endif
Matthias Brugger 214f30
+
Matthias Brugger 214f30
 	.data
Matthias Brugger 214f30
 	.align	2
Matthias Brugger 214f30
 
Matthias Brugger 214f30
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
Matthias Brugger 214f30
index ac86c34682bb..dbc1913ee30b 100644
Matthias Brugger 214f30
--- a/arch/arm/kernel/entry-common.S
Matthias Brugger 214f30
+++ b/arch/arm/kernel/entry-common.S
Matthias Brugger 214f30
@@ -153,6 +153,29 @@ ENDPROC(ret_from_fork)
Matthias Brugger 214f30
  *-----------------------------------------------------------------------------
Matthias Brugger 214f30
  */
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+	.align	5
Matthias Brugger 214f30
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
Matthias Brugger 214f30
+ENTRY(vector_bhb_loop8_swi)
Matthias Brugger 214f30
+	sub	sp, sp, #PT_REGS_SIZE
Matthias Brugger 214f30
+	stmia	sp, {r0 - r12}
Matthias Brugger 214f30
+	mov	r8, #8
Matthias Brugger 214f30
+1:	b	2f
Matthias Brugger 214f30
+2:	subs	r8, r8, #1
Matthias Brugger 214f30
+	bne	1b
Matthias Brugger 214f30
+	dsb
Matthias Brugger 214f30
+	isb
Matthias Brugger 214f30
+	b	3f
Matthias Brugger 214f30
+ENDPROC(vector_bhb_loop8_swi)
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	.align	5
Matthias Brugger 214f30
+ENTRY(vector_bhb_bpiall_swi)
Matthias Brugger 214f30
+	sub	sp, sp, #PT_REGS_SIZE
Matthias Brugger 214f30
+	stmia	sp, {r0 - r12}
Matthias Brugger 214f30
+	mcr	p15, 0, r8, c7, c5, 6	@ BPIALL
Matthias Brugger 214f30
+	isb
Matthias Brugger 214f30
+	b	3f
Matthias Brugger 214f30
+ENDPROC(vector_bhb_bpiall_swi)
Matthias Brugger 214f30
+#endif
Matthias Brugger 214f30
 	.align	5
Matthias Brugger 214f30
 ENTRY(vector_swi)
Matthias Brugger 214f30
 #ifdef CONFIG_CPU_V7M
Matthias Brugger 214f30
@@ -160,6 +183,7 @@ ENTRY(vector_swi)
Matthias Brugger 214f30
 #else
Matthias Brugger 214f30
 	sub	sp, sp, #PT_REGS_SIZE
Matthias Brugger 214f30
 	stmia	sp, {r0 - r12}			@ Calling r0 - r12
Matthias Brugger 214f30
+3:
Matthias Brugger 214f30
  ARM(	add	r8, sp, #S_PC		)
Matthias Brugger 214f30
  ARM(	stmdb	r8, {sp, lr}^		)	@ Calling sp, lr
Matthias Brugger 214f30
  THUMB(	mov	r8, sp			)
Matthias Brugger 214f30
diff --git a/arch/arm/kernel/spectre.c b/arch/arm/kernel/spectre.c
Matthias Brugger 214f30
index 6f6dd1cfd099..ade967f18d06 100644
Matthias Brugger 214f30
--- a/arch/arm/kernel/spectre.c
Matthias Brugger 214f30
+++ b/arch/arm/kernel/spectre.c
Matthias Brugger 214f30
@@ -45,6 +45,10 @@ ssize_t cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr,
Matthias Brugger 214f30
 		method = "Firmware call";
Matthias Brugger 214f30
 		break;
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+	case SPECTRE_V2_METHOD_LOOP8:
Matthias Brugger 214f30
+		method = "History overwrite";
Matthias Brugger 214f30
+		break;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
 	default:
Matthias Brugger 214f30
 		method = "Multiple mitigations";
Matthias Brugger 214f30
 		break;
Matthias Brugger 214f30
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
Matthias Brugger 214f30
index abc82dfeab51..90c887aa67a4 100644
Matthias Brugger 214f30
--- a/arch/arm/kernel/traps.c
Matthias Brugger 214f30
+++ b/arch/arm/kernel/traps.c
Matthias Brugger 214f30
@@ -30,6 +30,7 @@
Matthias Brugger 214f30
 #include <linux/atomic.h>
Matthias Brugger 214f30
 #include <asm/cacheflush.h>
Matthias Brugger 214f30
 #include <asm/exception.h>
Matthias Brugger 214f30
+#include <asm/spectre.h>
Matthias Brugger 214f30
 #include <asm/unistd.h>
Matthias Brugger 214f30
 #include <asm/traps.h>
Matthias Brugger 214f30
 #include <asm/ptrace.h>
Matthias Brugger 214f30
@@ -801,6 +802,43 @@ static void flush_vectors(void *vma, size_t offset, size_t size)
Matthias Brugger 214f30
 	flush_icache_range(start, end);
Matthias Brugger 214f30
 }
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
Matthias Brugger 214f30
+int spectre_bhb_update_vectors(unsigned int method)
Matthias Brugger 214f30
+{
Matthias Brugger 214f30
+	extern char __vectors_bhb_bpiall_start[], __vectors_bhb_bpiall_end[];
Matthias Brugger 214f30
+	extern char __vectors_bhb_loop8_start[], __vectors_bhb_loop8_end[];
Matthias Brugger 214f30
+	void *vec_start, *vec_end;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	if (system_state >= SYSTEM_RUNNING) {
Matthias Brugger 214f30
+		pr_err("CPU%u: Spectre BHB workaround too late - system vulnerable\n",
Matthias Brugger 214f30
+		       smp_processor_id());
Matthias Brugger 214f30
+		return SPECTRE_VULNERABLE;
Matthias Brugger 214f30
+	}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	switch (method) {
Matthias Brugger 214f30
+	case SPECTRE_V2_METHOD_LOOP8:
Matthias Brugger 214f30
+		vec_start = __vectors_bhb_loop8_start;
Matthias Brugger 214f30
+		vec_end = __vectors_bhb_loop8_end;
Matthias Brugger 214f30
+		break;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	case SPECTRE_V2_METHOD_BPIALL:
Matthias Brugger 214f30
+		vec_start = __vectors_bhb_bpiall_start;
Matthias Brugger 214f30
+		vec_end = __vectors_bhb_bpiall_end;
Matthias Brugger 214f30
+		break;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	default:
Matthias Brugger 214f30
+		pr_err("CPU%u: unknown Spectre BHB state %d\n",
Matthias Brugger 214f30
+		       smp_processor_id(), method);
Matthias Brugger 214f30
+		return SPECTRE_VULNERABLE;
Matthias Brugger 214f30
+	}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	copy_from_lma(vectors_page, vec_start, vec_end);
Matthias Brugger 214f30
+	flush_vectors(vectors_page, 0, vec_end - vec_start);
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	return SPECTRE_MITIGATED;
Matthias Brugger 214f30
+}
Matthias Brugger 214f30
+#endif
Matthias Brugger 214f30
+
Matthias Brugger 214f30
 void __init early_trap_init(void *vectors_base)
Matthias Brugger 214f30
 {
Matthias Brugger 214f30
 	extern char __stubs_start[], __stubs_end[];
Matthias Brugger 214f30
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
Matthias Brugger 214f30
index 850329ea9bf8..9724c16e9076 100644
Matthias Brugger 214f30
--- a/arch/arm/mm/Kconfig
Matthias Brugger 214f30
+++ b/arch/arm/mm/Kconfig
Matthias Brugger 214f30
@@ -851,6 +851,16 @@ config HARDEN_BRANCH_PREDICTOR
Matthias Brugger 214f30
 
Matthias Brugger 214f30
 	   If unsure, say Y.
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+config HARDEN_BRANCH_HISTORY
Matthias Brugger 214f30
+	bool "Harden Spectre style attacks against branch history" if EXPERT
Matthias Brugger 214f30
+	depends on CPU_SPECTRE
Matthias Brugger 214f30
+	default y
Matthias Brugger 214f30
+	help
Matthias Brugger 214f30
+	  Speculation attacks against some high-performance processors can
Matthias Brugger 214f30
+	  make use of branch history to influence future speculation. When
Matthias Brugger 214f30
+	  taking an exception, a sequence of branches overwrites the branch
Matthias Brugger 214f30
+	  history, or branch history is invalidated.
Matthias Brugger 214f30
+
Matthias Brugger 214f30
 config TLS_REG_EMUL
Matthias Brugger 214f30
 	bool
Matthias Brugger 214f30
 	select NEED_KUSER_HELPERS
Matthias Brugger 214f30
diff --git a/arch/arm/mm/proc-v7-bugs.c b/arch/arm/mm/proc-v7-bugs.c
Matthias Brugger 214f30
index e438e59bb63e..c226feab2457 100644
Matthias Brugger 214f30
--- a/arch/arm/mm/proc-v7-bugs.c
Matthias Brugger 214f30
+++ b/arch/arm/mm/proc-v7-bugs.c
Matthias Brugger 214f30
@@ -177,6 +177,81 @@ static void cpu_v7_spectre_v2_init(void)
Matthias Brugger 214f30
 	spectre_v2_update_state(state, method);
Matthias Brugger 214f30
 }
Matthias Brugger 214f30
 
Matthias Brugger 214f30
+#ifdef CONFIG_HARDEN_BRANCH_HISTORY
Matthias Brugger 214f30
+static int spectre_bhb_method;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+static const char *spectre_bhb_method_name(int method)
Matthias Brugger 214f30
+{
Matthias Brugger 214f30
+	switch (method) {
Matthias Brugger 214f30
+	case SPECTRE_V2_METHOD_LOOP8:
Matthias Brugger 214f30
+		return "loop";
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	case SPECTRE_V2_METHOD_BPIALL:
Matthias Brugger 214f30
+		return "BPIALL";
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	default:
Matthias Brugger 214f30
+		return "unknown";
Matthias Brugger 214f30
+	}
Matthias Brugger 214f30
+}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+static int spectre_bhb_install_workaround(int method)
Matthias Brugger 214f30
+{
Matthias Brugger 214f30
+	if (spectre_bhb_method != method) {
Matthias Brugger 214f30
+		if (spectre_bhb_method) {
Matthias Brugger 214f30
+			pr_err("CPU%u: Spectre BHB: method disagreement, system vulnerable\n",
Matthias Brugger 214f30
+			       smp_processor_id());
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+			return SPECTRE_VULNERABLE;
Matthias Brugger 214f30
+		}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+		if (spectre_bhb_update_vectors(method) == SPECTRE_VULNERABLE)
Matthias Brugger 214f30
+			return SPECTRE_VULNERABLE;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+		spectre_bhb_method = method;
Matthias Brugger 214f30
+	}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	pr_info("CPU%u: Spectre BHB: using %s workaround\n",
Matthias Brugger 214f30
+		smp_processor_id(), spectre_bhb_method_name(method));
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	return SPECTRE_MITIGATED;
Matthias Brugger 214f30
+}
Matthias Brugger 214f30
+#else
Matthias Brugger 214f30
+static int spectre_bhb_install_workaround(int method)
Matthias Brugger 214f30
+{
Matthias Brugger 214f30
+	return SPECTRE_VULNERABLE;
Matthias Brugger 214f30
+}
Matthias Brugger 214f30
+#endif
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+static void cpu_v7_spectre_bhb_init(void)
Matthias Brugger 214f30
+{
Matthias Brugger 214f30
+	unsigned int state, method = 0;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	switch (read_cpuid_part()) {
Matthias Brugger 214f30
+	case ARM_CPU_PART_CORTEX_A15:
Matthias Brugger 214f30
+	case ARM_CPU_PART_BRAHMA_B15:
Matthias Brugger 214f30
+	case ARM_CPU_PART_CORTEX_A57:
Matthias Brugger 214f30
+	case ARM_CPU_PART_CORTEX_A72:
Matthias Brugger 214f30
+		state = SPECTRE_MITIGATED;
Matthias Brugger 214f30
+		method = SPECTRE_V2_METHOD_LOOP8;
Matthias Brugger 214f30
+		break;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	case ARM_CPU_PART_CORTEX_A73:
Matthias Brugger 214f30
+	case ARM_CPU_PART_CORTEX_A75:
Matthias Brugger 214f30
+		state = SPECTRE_MITIGATED;
Matthias Brugger 214f30
+		method = SPECTRE_V2_METHOD_BPIALL;
Matthias Brugger 214f30
+		break;
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	default:
Matthias Brugger 214f30
+		state = SPECTRE_UNAFFECTED;
Matthias Brugger 214f30
+		break;
Matthias Brugger 214f30
+	}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	if (state == SPECTRE_MITIGATED)
Matthias Brugger 214f30
+		state = spectre_bhb_install_workaround(method);
Matthias Brugger 214f30
+
Matthias Brugger 214f30
+	spectre_v2_update_state(state, method);
Matthias Brugger 214f30
+}
Matthias Brugger 214f30
+
Matthias Brugger 214f30
 static __maybe_unused bool cpu_v7_check_auxcr_set(bool *warned,
Matthias Brugger 214f30
 						  u32 mask, const char *msg)
Matthias Brugger 214f30
 {
Matthias Brugger 214f30
@@ -217,4 +292,5 @@ void cpu_v7_ca15_ibe(void)
Matthias Brugger 214f30
 void cpu_v7_bugs_init(void)
Matthias Brugger 214f30
 {
Matthias Brugger 214f30
 	cpu_v7_spectre_v2_init();
Matthias Brugger 214f30
+	cpu_v7_spectre_bhb_init();
Matthias Brugger 214f30
 }
Matthias Brugger 214f30
-- 
Matthias Brugger 214f30
2.34.1
Matthias Brugger 214f30