This isn't used yet, because OPAL is nice enough not to cause unexpected program check interrupts to the OS. A future patch will allow OPAL to start using traps. Like so.
[OPAL] < assert failed at core/opal.c:814 > [OPAL] . [OPAL] . [OPAL] . [OPAL] OO__) [OPAL] <"__/ [OPAL] ^ ^ cpu 0x0: Vector: 700 (Program Check) at [c000000080287770] pc: 000000003002f360: opal_poll_events+0x54/0x174 [OPAL] lr: 000000003002f344: opal_poll_events+0x38/0x174 [OPAL] sp: c000000080287a00 msr: 9000000000021033 current = 0xc0000000016fa100 paca = 0xc0000000012c0000^I irqmask: 0x03^I irq_happened: 0x01 pid = 19, comm = kopald Linux version 5.7.0-rc3-00053-g2d9c3c965178-dirty enter ? for help [c000000080287a80] 000000003002e6b8 opal_v4_le_entry+0x224/0x29c [OPAL] [c000000080287b50] c000000000096ce8 opal_call+0x1c8/0x580 [c000000080287c90] c000000000097448 opal_poll_events+0x28/0x40 [c000000080287d00] c0000000000a26e0 opal_handle_events+0x70/0x140 [c000000080287d50] c00000000009a198 kopald+0x98/0x140 [c000000080287db0] c00000000012139c kthread+0x18c/0x1a0 [c000000080287e20] c00000000000cc28 ret_from_kernel_thread+0x5c/0x74 Signed-off-by: Nicholas Piggin <npig...@gmail.com> --- arch/powerpc/include/asm/opal-api.h | 7 +++- arch/powerpc/include/asm/opal.h | 2 ++ arch/powerpc/kernel/traps.c | 39 ++++++++++++++++------ arch/powerpc/platforms/powernv/opal-call.c | 1 + 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h index 8eb31b9aeb27..018d4734c323 100644 --- a/arch/powerpc/include/asm/opal-api.h +++ b/arch/powerpc/include/asm/opal-api.h @@ -216,7 +216,8 @@ #define OPAL_SECVAR_ENQUEUE_UPDATE 178 #define OPAL_ADDR_TO_SYM 181 #define OPAL_SYM_TO_ADDR 182 -#define OPAL_LAST 182 +#define OPAL_REPORT_TRAP 183 +#define OPAL_LAST 183 #define QUIESCE_HOLD 1 /* Spin all calls at entry */ #define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */ @@ -1184,6 +1185,10 @@ struct opal_mpipl_fadump { struct opal_mpipl_region region[]; } __packed; +#define OPAL_TRAP_FATAL 1 +#define OPAL_TRAP_WARN 2 +#define OPAL_TRAP_PANIC 3 + #endif /* __ASSEMBLY__ */ #endif /* __OPAL_API_H */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 56b6994aefb7..dc77c2d5e036 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -314,6 +314,8 @@ s64 opal_quiesce(u64 shutdown_type, s32 cpu); int64_t opal_addr_to_sym(uint64_t addr, __be64 *symaddr, __be64 *symsize, char *namebuf, uint64_t buflen); int64_t opal_sym_to_addr(const char *name, __be64 *symaddr, __be64 *symsize); +int64_t opal_report_trap(uint64_t nip); + /* Internal functions */ extern int early_init_dt_scan_opal(unsigned long node, const char *uname, diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 3fca22276bb1..0274ae7b8a03 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -52,6 +52,7 @@ #endif #ifdef CONFIG_PPC64 #include <asm/firmware.h> +#include <asm/opal.h> #include <asm/processor.h> #include <asm/tm.h> #endif @@ -1471,7 +1472,6 @@ void program_check_exception(struct pt_regs *regs) goto bail; } if (reason & REASON_TRAP) { - unsigned long bugaddr; /* Debugger is first in line to stop recursive faults in * rcu_lock, notify_die, or atomic_notifier_call_chain */ if (debugger_bpt(regs)) @@ -1485,18 +1485,35 @@ void program_check_exception(struct pt_regs *regs) == NOTIFY_STOP) goto bail; - bugaddr = regs->nip; - /* - * Fixup bugaddr for BUG_ON() in real mode - */ - if (!is_kernel_addr(bugaddr) && !(regs->msr & MSR_IR)) - bugaddr += PAGE_OFFSET; + if (!(regs->msr & MSR_PR)) { /* not user-mode */ + unsigned long bugaddr; + enum bug_trap_type t; + + /* + * Fixup bugaddr for BUG_ON() in real mode + */ + bugaddr = regs->nip; + if (!is_kernel_addr(bugaddr) && !(regs->msr & MSR_IR)) + bugaddr += PAGE_OFFSET; + t = report_bug(bugaddr, regs); + if (t == BUG_TRAP_TYPE_WARN) { + regs->nip += 4; + goto bail; + } + if (t == BUG_TRAP_TYPE_BUG) + goto bug; - if (!(regs->msr & MSR_PR) && /* not user-mode */ - report_bug(bugaddr, regs) == BUG_TRAP_TYPE_WARN) { - regs->nip += 4; - goto bail; + if (firmware_has_feature(FW_FEATURE_OPAL)) { + int64_t ret; + + ret = opal_report_trap(regs->nip); + if (ret == OPAL_TRAP_WARN) { + regs->nip += 4; + goto bail; + } + } } +bug: _exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip); goto bail; } diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c index 2233a58924cb..506b1798081a 100644 --- a/arch/powerpc/platforms/powernv/opal-call.c +++ b/arch/powerpc/platforms/powernv/opal-call.c @@ -295,3 +295,4 @@ OPAL_CALL(opal_secvar_get_next, OPAL_SECVAR_GET_NEXT); OPAL_CALL(opal_secvar_enqueue_update, OPAL_SECVAR_ENQUEUE_UPDATE); OPAL_CALL(opal_addr_to_sym, OPAL_ADDR_TO_SYM); OPAL_CALL(opal_sym_to_addr, OPAL_SYM_TO_ADDR); +OPAL_CALL(opal_report_trap, OPAL_REPORT_TRAP); -- 2.23.0