Skip to content

Commit 08685be

Browse files
npigginmpe
authored andcommitted
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: f796437 ("powerpc/64s: flush L1D on kernel entry") Cc: [email protected] # 5.9+ which also have flush L1D patch backport Reported-by: Tulio Magno Quites Machado Filho <[email protected]> Signed-off-by: Nicholas Piggin <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent dd3a44c commit 08685be

File tree

6 files changed

+71
-4
lines changed

6 files changed

+71
-4
lines changed

arch/powerpc/include/asm/exception-64s.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,26 @@
6363
nop; \
6464
nop;
6565

66+
#define SCV_ENTRY_FLUSH_SLOT \
67+
SCV_ENTRY_FLUSH_FIXUP_SECTION; \
68+
nop; \
69+
nop; \
70+
nop;
71+
6672
/*
6773
* r10 must be free to use, r13 must be paca
6874
*/
6975
#define INTERRUPT_TO_KERNEL \
7076
STF_ENTRY_BARRIER_SLOT; \
7177
ENTRY_FLUSH_SLOT
7278

79+
/*
80+
* r10, ctr must be free to use, r13 must be paca
81+
*/
82+
#define SCV_INTERRUPT_TO_KERNEL \
83+
STF_ENTRY_BARRIER_SLOT; \
84+
SCV_ENTRY_FLUSH_SLOT
85+
7386
/*
7487
* Macros for annotating the expected destination of (h)rfid
7588
*

arch/powerpc/include/asm/feature-fixups.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,14 @@ label##3: \
240240
FTR_ENTRY_OFFSET 957b-958b; \
241241
.popsection;
242242

243+
#define SCV_ENTRY_FLUSH_FIXUP_SECTION \
244+
957: \
245+
.pushsection __scv_entry_flush_fixup,"a"; \
246+
.align 2; \
247+
958: \
248+
FTR_ENTRY_OFFSET 957b-958b; \
249+
.popsection;
250+
243251
#define RFI_FLUSH_FIXUP_SECTION \
244252
951: \
245253
.pushsection __rfi_flush_fixup,"a"; \
@@ -273,10 +281,12 @@ label##3: \
273281

274282
extern long stf_barrier_fallback;
275283
extern long entry_flush_fallback;
284+
extern long scv_entry_flush_fallback;
276285
extern long __start___stf_entry_barrier_fixup, __stop___stf_entry_barrier_fixup;
277286
extern long __start___stf_exit_barrier_fixup, __stop___stf_exit_barrier_fixup;
278287
extern long __start___uaccess_flush_fixup, __stop___uaccess_flush_fixup;
279288
extern long __start___entry_flush_fixup, __stop___entry_flush_fixup;
289+
extern long __start___scv_entry_flush_fixup, __stop___scv_entry_flush_fixup;
280290
extern long __start___rfi_flush_fixup, __stop___rfi_flush_fixup;
281291
extern long __start___barrier_nospec_fixup, __stop___barrier_nospec_fixup;
282292
extern long __start__btb_flush_fixup, __stop__btb_flush_fixup;

arch/powerpc/kernel/entry_64.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ BEGIN_FTR_SECTION
7575
bne .Ltabort_syscall
7676
END_FTR_SECTION_IFSET(CPU_FTR_TM)
7777
#endif
78-
INTERRUPT_TO_KERNEL
78+
SCV_INTERRUPT_TO_KERNEL
7979
mr r10,r1
8080
ld r1,PACAKSAVE(r13)
8181
std r10,0(r1)

arch/powerpc/kernel/exceptions-64s.S

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2993,6 +2993,25 @@ TRAMP_REAL_BEGIN(entry_flush_fallback)
29932993
ld r11,PACA_EXRFI+EX_R11(r13)
29942994
blr
29952995

2996+
/*
2997+
* The SCV entry flush happens with interrupts enabled, so it must disable
2998+
* to prevent EXRFI being clobbered by NMIs (e.g., soft_nmi_common). r10
2999+
* (containing LR) does not need to be preserved here because scv entry
3000+
* puts 0 in the pt_regs, CTR can be clobbered for the same reason.
3001+
*/
3002+
TRAMP_REAL_BEGIN(scv_entry_flush_fallback)
3003+
li r10,0
3004+
mtmsrd r10,1
3005+
lbz r10,PACAIRQHAPPENED(r13)
3006+
ori r10,r10,PACA_IRQ_HARD_DIS
3007+
stb r10,PACAIRQHAPPENED(r13)
3008+
std r11,PACA_EXRFI+EX_R11(r13)
3009+
L1D_DISPLACEMENT_FLUSH
3010+
ld r11,PACA_EXRFI+EX_R11(r13)
3011+
li r10,MSR_RI
3012+
mtmsrd r10,1
3013+
blr
3014+
29963015
TRAMP_REAL_BEGIN(rfi_flush_fallback)
29973016
SET_SCRATCH0(r13);
29983017
GET_PACA(r13);

arch/powerpc/kernel/vmlinux.lds.S

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ SECTIONS
145145
__stop___entry_flush_fixup = .;
146146
}
147147

148+
. = ALIGN(8);
149+
__scv_entry_flush_fixup : AT(ADDR(__scv_entry_flush_fixup) - LOAD_OFFSET) {
150+
__start___scv_entry_flush_fixup = .;
151+
*(__scv_entry_flush_fixup)
152+
__stop___scv_entry_flush_fixup = .;
153+
}
154+
148155
. = ALIGN(8);
149156
__stf_exit_barrier_fixup : AT(ADDR(__stf_exit_barrier_fixup) - LOAD_OFFSET) {
150157
__start___stf_exit_barrier_fixup = .;

arch/powerpc/lib/feature-fixups.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,6 @@ void do_entry_flush_fixups(enum l1d_flush_type types)
290290
long *start, *end;
291291
int i;
292292

293-
start = PTRRELOC(&__start___entry_flush_fixup);
294-
end = PTRRELOC(&__stop___entry_flush_fixup);
295-
296293
instrs[0] = 0x60000000; /* nop */
297294
instrs[1] = 0x60000000; /* nop */
298295
instrs[2] = 0x60000000; /* nop */
@@ -312,6 +309,8 @@ void do_entry_flush_fixups(enum l1d_flush_type types)
312309
if (types & L1D_FLUSH_MTTRIG)
313310
instrs[i++] = 0x7c12dba6; /* mtspr TRIG2,r0 (SPR #882) */
314311

312+
start = PTRRELOC(&__start___entry_flush_fixup);
313+
end = PTRRELOC(&__stop___entry_flush_fixup);
315314
for (i = 0; start < end; start++, i++) {
316315
dest = (void *)start + *start;
317316

@@ -328,6 +327,25 @@ void do_entry_flush_fixups(enum l1d_flush_type types)
328327
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
329328
}
330329

330+
start = PTRRELOC(&__start___scv_entry_flush_fixup);
331+
end = PTRRELOC(&__stop___scv_entry_flush_fixup);
332+
for (; start < end; start++, i++) {
333+
dest = (void *)start + *start;
334+
335+
pr_devel("patching dest %lx\n", (unsigned long)dest);
336+
337+
patch_instruction((struct ppc_inst *)dest, ppc_inst(instrs[0]));
338+
339+
if (types == L1D_FLUSH_FALLBACK)
340+
patch_branch((struct ppc_inst *)(dest + 1), (unsigned long)&scv_entry_flush_fallback,
341+
BRANCH_SET_LINK);
342+
else
343+
patch_instruction((struct ppc_inst *)(dest + 1), ppc_inst(instrs[1]));
344+
345+
patch_instruction((struct ppc_inst *)(dest + 2), ppc_inst(instrs[2]));
346+
}
347+
348+
331349
printk(KERN_DEBUG "entry-flush: patched %d locations (%s flush)\n", i,
332350
(types == L1D_FLUSH_NONE) ? "no" :
333351
(types == L1D_FLUSH_FALLBACK) ? "fallback displacement" :

0 commit comments

Comments
 (0)