diff options
author | Nicholas Piggin <npiggin@gmail.com> | 2021-06-18 01:51:08 +1000 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2021-06-25 00:06:56 +1000 |
commit | f23699c93becd746295aaa506537882a46a62219 (patch) | |
tree | ea44289996524915c83e6876b39babbe6a640ff8 /arch/powerpc/include/asm/interrupt.h | |
parent | 63e40806eea984f770c992120bbfd71b589ea580 (diff) | |
download | linux-f23699c93becd746295aaa506537882a46a62219.tar.gz linux-f23699c93becd746295aaa506537882a46a62219.tar.bz2 linux-f23699c93becd746295aaa506537882a46a62219.zip |
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 <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20210617155116.2167984-10-npiggin@gmail.com
Diffstat (limited to 'arch/powerpc/include/asm/interrupt.h')
-rw-r--r-- | arch/powerpc/include/asm/interrupt.h | 13 |
1 files changed, 13 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/interrupt.h b/arch/powerpc/include/asm/interrupt.h index de36fb5d9c51..a4bf6c0013bb 100644 --- a/arch/powerpc/include/asm/interrupt.h +++ b/arch/powerpc/include/asm/interrupt.h @@ -73,6 +73,11 @@ #include <asm/kprobes.h> #include <asm/runlatch.h> +#ifdef CONFIG_PPC64 +extern char __end_soft_masked[]; +unsigned long search_kernel_restart_table(unsigned long addr); +#endif + #ifdef CONFIG_PPC_BOOK3S_64 static inline void srr_regs_clobbered(void) { @@ -270,6 +275,14 @@ static inline void interrupt_nmi_exit_prepare(struct pt_regs *regs, struct inter */ #ifdef CONFIG_PPC64 + if (arch_irq_disabled_regs(regs)) { + unsigned long rst = search_kernel_restart_table(regs->nip); + if (rst) + regs_set_return_ip(regs, rst); + } +#endif + +#ifdef CONFIG_PPC64 if (nmi_disables_ftrace(regs)) this_cpu_set_ftrace_enabled(state->ftrace_enabled); |