Commit 08685be7 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc/64s: fix scv entry fallback flush vs interrupt



The L1D flush fallback functions are not recoverable vs interrupts,
yet the scv entry flush runs with MSR[EE]=1. This can result in a
timer (soft-NMI) or MCE or SRESET interrupt hitting here and overwriting
the EXRFI save area, which ends up corrupting userspace registers for
scv return.

Fix this by disabling RI and EE for the scv entry fallback flush.

Fixes: f7964378 ("powerpc/64s: flush L1D on kernel entry")
Cc: stable@vger.kernel.org # 5.9+ which also have flush L1D patch backport
Reported-by: default avatarTulio Magno Quites Machado Filho <tuliom@linux.ibm.com>
Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210111062408.287092-1-npiggin@gmail.com
parent dd3a44c0
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -63,6 +63,12 @@
	nop;								\
	nop;

#define SCV_ENTRY_FLUSH_SLOT						\
	SCV_ENTRY_FLUSH_FIXUP_SECTION;					\
	nop;								\
	nop;								\
	nop;

/*
 * r10 must be free to use, r13 must be paca
 */
@@ -70,6 +76,13 @@
	STF_ENTRY_BARRIER_SLOT;						\
	ENTRY_FLUSH_SLOT

/*
 * r10, ctr must be free to use, r13 must be paca
 */
#define SCV_INTERRUPT_TO_KERNEL						\
	STF_ENTRY_BARRIER_SLOT;						\
	SCV_ENTRY_FLUSH_SLOT

/*
 * Macros for annotating the expected destination of (h)rfid
 *
+10 −0
Original line number Diff line number Diff line
@@ -240,6 +240,14 @@ label##3: \
	FTR_ENTRY_OFFSET 957b-958b;			\
	.popsection;

#define SCV_ENTRY_FLUSH_FIXUP_SECTION			\
957:							\
	.pushsection __scv_entry_flush_fixup,"a";	\
	.align 2;					\
958:							\
	FTR_ENTRY_OFFSET 957b-958b;			\
	.popsection;

#define RFI_FLUSH_FIXUP_SECTION				\
951:							\
	.pushsection __rfi_flush_fixup,"a";		\
@@ -273,10 +281,12 @@ label##3: \

extern long stf_barrier_fallback;
extern long entry_flush_fallback;
extern long scv_entry_flush_fallback;
extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup;
extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup;
extern long __start___uaccess_flush_fixup, __stop___uaccess_flush_fixup;
extern long __start___entry_flush_fixup, __stop___entry_flush_fixup;
extern long __start___scv_entry_flush_fixup, __stop___scv_entry_flush_fixup;
extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
extern long __start___barrier_nospec_fixup, __stop___barrier_nospec_fixup;
extern long __start__btb_flush_fixup, __stop__btb_flush_fixup;
+1 −1
Original line number Diff line number Diff line
@@ -75,7 +75,7 @@ BEGIN_FTR_SECTION
	bne	.Ltabort_syscall
END_FTR_SECTION_IFSET(CPU_FTR_TM)
#endif
	INTERRUPT_TO_KERNEL
	SCV_INTERRUPT_TO_KERNEL
	mr	r10,r1
	ld	r1,PACAKSAVE(r13)
	std	r10,0(r1)
+19 −0
Original line number Diff line number Diff line
@@ -2993,6 +2993,25 @@ TRAMP_REAL_BEGIN(entry_flush_fallback)
	ld	r11,PACA_EXRFI+EX_R11(r13)
	blr

/*
 * The SCV entry flush happens with interrupts enabled, so it must disable
 * to prevent EXRFI being clobbered by NMIs (e.g., soft_nmi_common). r10
 * (containing LR) does not need to be preserved here because scv entry
 * puts 0 in the pt_regs, CTR can be clobbered for the same reason.
 */
TRAMP_REAL_BEGIN(scv_entry_flush_fallback)
	li	r10,0
	mtmsrd	r10,1
	lbz	r10,PACAIRQHAPPENED(r13)
	ori	r10,r10,PACA_IRQ_HARD_DIS
	stb	r10,PACAIRQHAPPENED(r13)
	std	r11,PACA_EXRFI+EX_R11(r13)
	L1D_DISPLACEMENT_FLUSH
	ld	r11,PACA_EXRFI+EX_R11(r13)
	li	r10,MSR_RI
	mtmsrd	r10,1
	blr

TRAMP_REAL_BEGIN(rfi_flush_fallback)
	SET_SCRATCH0(r13);
	GET_PACA(r13);
+7 −0
Original line number Diff line number Diff line
@@ -145,6 +145,13 @@ SECTIONS
		__stop___entry_flush_fixup = .;
	}

	. = ALIGN(8);
	__scv_entry_flush_fixup : AT(ADDR(__scv_entry_flush_fixup) - LOAD_OFFSET) {
		__start___scv_entry_flush_fixup = .;
		*(__scv_entry_flush_fixup)
		__stop___scv_entry_flush_fixup = .;
	}

	. = ALIGN(8);
	__stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) {
		__start___stf_exit_barrier_fixup = .;
Loading