xmon can be entered via sreset NMI (from a management sreset, or an
NMI IPI), which can interrupt OPAL. Add checks to xmon to see if pc
or sp are within OPAL memory, and if so, then use OPAL_DEBUG to
print the opal stack and return the Linux stack, which can then be
dumped by xmon

The OPAL side of this, with sample xmon output is here:

https://lists.ozlabs.org/pipermail/skiboot/2018-March/010856.html

This could be plumed into the oops printing code as well.

Thanks,
Nick
---
 arch/powerpc/include/asm/opal.h                |  4 ++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |  1 +
 arch/powerpc/platforms/powernv/opal.c          |  5 +++++
 arch/powerpc/xmon/xmon.c                       | 27 ++++++++++++++++++++++++++
 4 files changed, 37 insertions(+)

diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 12e70fb58700..afcc0c5ed5b0 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -27,6 +27,8 @@ extern struct kobject *opal_kobj;
 /* /ibm,opal */
 extern struct device_node *opal_node;
 
+bool in_opal_text_heap_stack(u64 address);
+
 /* API functions */
 int64_t opal_invalid_call(void);
 int64_t opal_npu_destroy_context(uint64_t phb_id, uint64_t pid, uint64_t bdf);
@@ -289,6 +291,8 @@ int opal_sensor_group_clear(u32 group_hndl, int token);
 
 s64 opal_signal_system_reset(s32 cpu);
 
+s64 opal_debug(u32 debug_type, u64 r1);
+
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
                                   int depth, void *data);
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S 
b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 1b2936ba6040..78b9ae003553 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -323,3 +323,4 @@ OPAL_CALL(opal_sensor_group_clear,          
OPAL_SENSOR_GROUP_CLEAR);
 OPAL_CALL(opal_npu_spa_setup,                  OPAL_NPU_SPA_SETUP);
 OPAL_CALL(opal_npu_spa_clear_cache,            OPAL_NPU_SPA_CLEAR_CACHE);
 OPAL_CALL(opal_npu_tl_set,                     OPAL_NPU_TL_SET);
+OPAL_CALL(opal_debug,                          167);
diff --git a/arch/powerpc/platforms/powernv/opal.c 
b/arch/powerpc/platforms/powernv/opal.c
index c15182765ff5..0b7ff5fb18f8 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -64,6 +64,11 @@ static struct atomic_notifier_head 
opal_msg_notifier_head[OPAL_MSG_TYPE_MAX];
 static uint32_t opal_heartbeat;
 static struct task_struct *kopald_tsk;
 
+bool in_opal_text_heap_stack(u64 address)
+{
+       return (address >= opal.base && address < opal.base + opal.size);
+}
+
 void opal_configure_cores(void)
 {
        u64 reinit_flags = 0;
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 82e1a3ee6e0f..ade1adcc1ab8 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -452,6 +452,15 @@ static inline int unrecoverable_excp(struct pt_regs *regs)
 #endif
 }
 
+static bool in_opal(unsigned long addr)
+{
+       if (firmware_has_feature(FW_FEATURE_OPAL))
+               if (in_opal_text_heap_stack(addr))
+                       return true;
+
+       return false;
+}
+
 static int xmon_core(struct pt_regs *regs, int fromipi)
 {
        int cmd = 0;
@@ -510,6 +519,9 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
 
        xmon_fault_jmp[cpu] = recurse_jmp;
 
+       if (in_opal(regs->nip))
+               printf("xmon: cpu 0x%x stopped in OPAL!\n", cpu);
+
        bp = NULL;
        if ((regs->msr & (MSR_IR|MSR_PR|MSR_64BIT)) == (MSR_IR|MSR_64BIT))
                bp = at_breakpoint(regs->nip);
@@ -1484,8 +1496,23 @@ static void xmon_show_stack(unsigned long sp, unsigned 
long lr,
        unsigned long marker;
        struct pt_regs regs;
 
+       if (in_opal(sp)) {
+               struct debug_struct {
+                       unsigned long nip;
+                       unsigned long r1;
+                       unsigned long r1_caller;
+               } db;
+               printf("SP is in OPAL, calling OPAL to dump stack\n");
+               db.nip = cpu_to_be64(pc);
+               db.r1 = cpu_to_be64(sp);
+               opal_debug(1, (unsigned long)&db);
+               sp = be64_to_cpu(db.r1_caller);
+       }
+
        while (max_to_print--) {
                if (!is_kernel_addr(sp)) {
+                       if (in_opal(pc) && in_opal(sp))
+                               printf("SP (%lx) is in OPAL\n", sp);
                        if (sp != 0)
                                printf("SP (%lx) is in userspace\n", sp);
                        break;
-- 
2.16.1

Reply via email to