Skip to content

Commit f23699c

Browse files
npigginmpe
authored andcommitted
powerpc/64: allow alternate return locations for soft-masked interrupts
The exception table fixup adjusts a failed page fault's interrupt return location if it was taken at an address specified in the exception table, to a corresponding fixup handler address. Introduce a variation of that idea which adds a fixup table for NMIs and soft-masked asynchronous interrupts. This will be used to protect certain critical sections that are sensitive to being clobbered by interrupts coming in (due to using the same SPRs and/or irq soft-mask state). Signed-off-by: Nicholas Piggin <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 63e4080 commit f23699c

File tree

7 files changed

+138
-3
lines changed

7 files changed

+138
-3
lines changed

arch/powerpc/include/asm/interrupt.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
#include <asm/kprobes.h>
7474
#include <asm/runlatch.h>
7575

76+
#ifdef CONFIG_PPC64
77+
extern char __end_soft_masked[];
78+
unsigned long search_kernel_restart_table(unsigned long addr);
79+
#endif
80+
7681
#ifdef CONFIG_PPC_BOOK3S_64
7782
static inline void srr_regs_clobbered(void)
7883
{
@@ -269,6 +274,14 @@ static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct inter
269274
* new work to do (must use irq_work for that).
270275
*/
271276

277+
#ifdef CONFIG_PPC64
278+
if (arch_irq_disabled_regs(regs)) {
279+
unsigned long rst = search_kernel_restart_table(regs->nip);
280+
if (rst)
281+
regs_set_return_ip(regs, rst);
282+
}
283+
#endif
284+
272285
#ifdef CONFIG_PPC64
273286
if (nmi_disables_ftrace(regs))
274287
this_cpu_set_ftrace_enabled(state->ftrace_enabled);

arch/powerpc/include/asm/ppc_asm.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,14 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
762762
stringify_in_c(.long (_target) - . ;) \
763763
stringify_in_c(.previous)
764764

765+
#define RESTART_TABLE(_start, _end, _target) \
766+
stringify_in_c(.section __restart_table,"a";)\
767+
stringify_in_c(.balign 8;) \
768+
stringify_in_c(.llong (_start);) \
769+
stringify_in_c(.llong (_end);) \
770+
stringify_in_c(.llong (_target);) \
771+
stringify_in_c(.previous)
772+
765773
#ifdef CONFIG_PPC_FSL_BOOK3E
766774
#define BTB_FLUSH(reg) \
767775
lis reg,BUCSR_INIT@h; \

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

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,28 @@ kernel_dbg_exc:
901901
bl unknown_exception
902902
b interrupt_return
903903

904+
.macro SEARCH_RESTART_TABLE
905+
LOAD_REG_IMMEDIATE_SYM(r14, r11, __start___restart_table)
906+
LOAD_REG_IMMEDIATE_SYM(r15, r11, __stop___restart_table)
907+
300:
908+
cmpd r14,r15
909+
beq 302f
910+
ld r11,0(r14)
911+
cmpld r10,r11
912+
blt 301f
913+
ld r11,8(r14)
914+
cmpld r10,r11
915+
bge 301f
916+
ld r11,16(r14)
917+
b 303f
918+
301:
919+
addi r14,r14,24
920+
b 300b
921+
302:
922+
li r11,0
923+
303:
924+
.endm
925+
904926
/*
905927
* An interrupt came in while soft-disabled; We mark paca->irq_happened
906928
* accordingly and if the interrupt is level sensitive, we hard disable
@@ -909,6 +931,9 @@ kernel_dbg_exc:
909931
*/
910932

911933
.macro masked_interrupt_book3e paca_irq full_mask
934+
std r14,PACA_EXGEN+EX_R14(r13)
935+
std r15,PACA_EXGEN+EX_R15(r13)
936+
912937
lbz r10,PACAIRQHAPPENED(r13)
913938
.if \full_mask == 1
914939
ori r10,r10,\paca_irq | PACA_IRQ_HARD_DIS
@@ -918,15 +943,23 @@ kernel_dbg_exc:
918943
stb r10,PACAIRQHAPPENED(r13)
919944

920945
.if \full_mask == 1
921-
rldicl r10,r11,48,1 /* clear MSR_EE */
922-
rotldi r11,r10,16
946+
xori r11,r11,MSR_EE /* clear MSR_EE */
923947
mtspr SPRN_SRR1,r11
924948
.endif
925949

950+
mfspr r10,SPRN_SRR0
951+
SEARCH_RESTART_TABLE
952+
cmpdi r11,0
953+
beq 1f
954+
mtspr SPRN_SRR0,r11 /* return to restart address */
955+
1:
956+
926957
lwz r11,PACA_EXGEN+EX_CR(r13)
927958
mtcr r11
928959
ld r10,PACA_EXGEN+EX_R10(r13)
929960
ld r11,PACA_EXGEN+EX_R11(r13)
961+
ld r14,PACA_EXGEN+EX_R14(r13)
962+
ld r15,PACA_EXGEN+EX_R15(r13)
930963
mfspr r13,SPRN_SPRG_GEN_SCRATCH
931964
rfi
932965
b .

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,36 @@ END_FTR_SECTION_IFSET(CPU_FTR_CFAR)
591591
__GEN_COMMON_BODY \name
592592
.endm
593593

594+
.macro SEARCH_RESTART_TABLE
595+
#ifdef CONFIG_RELOCATABLE
596+
mr r12,r2
597+
ld r2,PACATOC(r13)
598+
LOAD_REG_ADDR(r9, __start___restart_table)
599+
LOAD_REG_ADDR(r10, __stop___restart_table)
600+
mr r2,r12
601+
#else
602+
LOAD_REG_IMMEDIATE_SYM(r9, r12, __start___restart_table)
603+
LOAD_REG_IMMEDIATE_SYM(r10, r12, __stop___restart_table)
604+
#endif
605+
300:
606+
cmpd r9,r10
607+
beq 302f
608+
ld r12,0(r9)
609+
cmpld r11,r12
610+
blt 301f
611+
ld r12,8(r9)
612+
cmpld r11,r12
613+
bge 301f
614+
ld r12,16(r9)
615+
b 303f
616+
301:
617+
addi r9,r9,24
618+
b 300b
619+
302:
620+
li r12,0
621+
303:
622+
.endm
623+
594624
/*
595625
* Restore all registers including H/SRR0/1 saved in a stack frame of a
596626
* standard exception.
@@ -2646,6 +2676,7 @@ EXC_COMMON_BEGIN(soft_nmi_common)
26462676
mtmsrd r9,1
26472677

26482678
kuap_kernel_restore r9, r10
2679+
26492680
EXCEPTION_RESTORE_REGS hsrr=0
26502681
RFI_TO_KERNEL
26512682

@@ -2703,6 +2734,16 @@ masked_interrupt:
27032734
stb r9,PACASRR_VALID(r13)
27042735
.endif
27052736

2737+
SEARCH_RESTART_TABLE
2738+
cmpdi r12,0
2739+
beq 3f
2740+
.if \hsrr
2741+
mtspr SPRN_HSRR0,r12
2742+
.else
2743+
mtspr SPRN_SRR0,r12
2744+
.endif
2745+
3:
2746+
27062747
ld r9,PACA_EXGEN+EX_CTR(r13)
27072748
mtctr r9
27082749
lwz r9,PACA_EXGEN+EX_CCR(r13)

arch/powerpc/kernel/vmlinux.lds.S

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
#define EMITS_PT_NOTE
1010
#define RO_EXCEPTION_TABLE_ALIGN 0
1111

12+
#define RESTART_TABLE(align) \
13+
. = ALIGN(align); \
14+
__restart_table : AT(ADDR(__restart_table) - LOAD_OFFSET) { \
15+
__start___restart_table = .; \
16+
KEEP(*(__restart_table)) \
17+
__stop___restart_table = .; \
18+
}
19+
1220
#include <asm/page.h>
1321
#include <asm-generic/vmlinux.lds.h>
1422
#include <asm/cache.h>
@@ -124,6 +132,8 @@ SECTIONS
124132
RO_DATA(PAGE_SIZE)
125133

126134
#ifdef CONFIG_PPC64
135+
RESTART_TABLE(8)
136+
127137
. = ALIGN(8);
128138
__stf_entry_barrier_fixup : AT(ADDR(__stf_entry_barrier_fixup) - LOAD_OFFSET) {
129139
__start___stf_entry_barrier_fixup = .;

arch/powerpc/lib/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ obj-$(CONFIG_PPC_BOOK3S_64) += copyuser_power7.o copypage_power7.o \
4242
memcpy_power7.o
4343

4444
obj64-y += copypage_64.o copyuser_64.o mem_64.o hweight_64.o \
45-
memcpy_64.o copy_mc_64.o
45+
memcpy_64.o copy_mc_64.o restart_table.o
4646

4747
ifndef CONFIG_PPC_QUEUED_SPINLOCKS
4848
obj64-$(CONFIG_SMP) += locks.o

arch/powerpc/lib/restart_table.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <asm/interrupt.h>
2+
#include <asm/kprobes.h>
3+
4+
struct restart_table_entry {
5+
unsigned long start;
6+
unsigned long end;
7+
unsigned long fixup;
8+
};
9+
10+
extern struct restart_table_entry __start___restart_table[];
11+
extern struct restart_table_entry __stop___restart_table[];
12+
13+
/* Given an address, look for it in the kernel exception table */
14+
unsigned long search_kernel_restart_table(unsigned long addr)
15+
{
16+
struct restart_table_entry *rte = __start___restart_table;
17+
18+
while (rte < __stop___restart_table) {
19+
unsigned long start = rte->start;
20+
unsigned long end = rte->end;
21+
unsigned long fixup = rte->fixup;
22+
23+
if (addr >= start && addr < end)
24+
return fixup;
25+
26+
rte++;
27+
}
28+
return 0;
29+
}
30+
NOKPROBE_SYMBOL(search_kernel_restart_table);

0 commit comments

Comments
 (0)