git: 5aeedaf7204a - main - powerpc/ddb: Dump more state in `show pcpu`

From: Justin Hibbits <jhibbits_at_FreeBSD.org>
Date: Sat, 05 Sep 2026 04:15:19 UTC
The branch main has been updated by jhibbits:

URL: https://cgit.FreeBSD.org/src/commit/?id=5aeedaf7204a97b88f04d6a1890dfd1ff02d6101

commit 5aeedaf7204a97b88f04d6a1890dfd1ff02d6101
Author:     Justin Hibbits <jhibbits@FreeBSD.org>
AuthorDate: 2026-09-05 04:03:11 +0000
Commit:     Justin Hibbits <jhibbits@FreeBSD.org>
CommitDate: 2026-09-05 04:11:57 +0000

    powerpc/ddb: Dump more state in `show pcpu`
    
    Add a new CPU-family `show pcpu` handler, cpu_db_show_mdpcpu() to dump
    CPU-specific PCPU data.  Only Book-E is populated for now, but AIM may
    be populated later.
    
    These new field prints: save areas, TLB miss nesting, the new critical
    stack pointer.  All of them have been very useful for debugging very
    esoteric bugs, so make them easier to see from DDB, instead of having to
    rummage through hex dumps.
---
 sys/powerpc/aim/aim_machdep.c      |  7 ++++++
 sys/powerpc/booke/booke_machdep.c  | 48 ++++++++++++++++++++++++++++++++++++++
 sys/powerpc/include/md_var.h       |  5 ++++
 sys/powerpc/powerpc/db_interface.c |  7 ++++++
 4 files changed, 67 insertions(+)

diff --git a/sys/powerpc/aim/aim_machdep.c b/sys/powerpc/aim/aim_machdep.c
index 814c679ff47e..2dbd087c8f4e 100644
--- a/sys/powerpc/aim/aim_machdep.c
+++ b/sys/powerpc/aim/aim_machdep.c
@@ -541,6 +541,13 @@ memcpy(pcpu->pc_aim.slb, PCPU_GET(aim.slb), sizeof(pcpu->pc_aim.slb));
 #endif
 }
 
+#ifdef DDB
+void
+cpu_db_show_mdpcpu(struct pcpu *pc)
+{
+}
+#endif
+
 /* Return 0 on handled success, otherwise signal number. */
 int
 cpu_machine_check(struct thread *td, struct trapframe *frame, int *ucode)
diff --git a/sys/powerpc/booke/booke_machdep.c b/sys/powerpc/booke/booke_machdep.c
index 99b14bc9e974..58b847766d46 100644
--- a/sys/powerpc/booke/booke_machdep.c
+++ b/sys/powerpc/booke/booke_machdep.c
@@ -426,6 +426,54 @@ cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t sz)
 #endif
 }
 
+#ifdef DDB
+/*
+ * Dump an exception save area.  In a nested save, R31 holds the DEAR of the
+ * outer exception.
+ */
+static void
+db_show_booke_save(const char *name, register_t *sv)
+{
+
+	db_printf("%s r30 %#jx r31 %#jx dear %#jx esr %#jx\n", name,
+	    (uintmax_t)sv[CPUSAVE_R30], (uintmax_t)sv[CPUSAVE_R31],
+	    (uintmax_t)sv[CPUSAVE_BOOKE_DEAR],
+	    (uintmax_t)sv[CPUSAVE_BOOKE_ESR]);
+	db_printf("%s srr0 %#jx srr1 %#jx\n", name,
+	    (uintmax_t)sv[CPUSAVE_SRR0], (uintmax_t)sv[CPUSAVE_SRR1]);
+}
+
+void
+cpu_db_show_mdpcpu(struct pcpu *pc)
+{
+	register_t *tlbsave;
+	int i;
+
+	db_printf("tid_next = %d tlb_level = %#jx critstack = %p\n",
+	    pc->pc_booke.tid_next, (uintmax_t)pc->pc_booke.tlb_level,
+	    pc->pc_booke.critstack);
+	db_show_booke_save("tempsave", pc->pc_tempsave);
+	db_show_booke_save("disisave", pc->pc_disisave);
+	db_show_booke_save("critsave", pc->pc_booke.critsave);
+	/*
+	 * In critsave, CPUSAVE_SRR0-1 hold the interrupt's own CSRR0-1 (DSRR0-1
+	 * for the enhanced-debug vector); the non-critical SRR0-1 that were
+	 * live at the time are kept separately.
+	 */
+	db_printf("critsave held srr0 %#jx srr1 %#jx\n",
+	    (uintmax_t)pc->pc_booke.critsave[BOOKE_CRITSAVE_SRR0],
+	    (uintmax_t)pc->pc_booke.critsave[BOOKE_CRITSAVE_SRR1]);
+	db_show_booke_save("mchksave", pc->pc_booke.mchksave);
+	for (i = 0; i < BOOKE_TLB_MAXNEST &&
+	    i < (int)pc->pc_booke.tlb_level; i++) {
+		tlbsave = &pc->pc_booke.tlbsave[i * BOOKE_TLB_SAVELEN];
+		db_printf("tlbsave%d srr0 %#jx srr1 %#jx\n", i,
+		    (uintmax_t)tlbsave[TLBSAVE_BOOKE_SRR0],
+		    (uintmax_t)tlbsave[TLBSAVE_BOOKE_SRR1]);
+	}
+}
+#endif /* DDB */
+
 /* Shutdown the CPU as much as possible. */
 void
 cpu_halt(void)
diff --git a/sys/powerpc/include/md_var.h b/sys/powerpc/include/md_var.h
index e995f0a91b63..b51d779fbd0f 100644
--- a/sys/powerpc/include/md_var.h
+++ b/sys/powerpc/include/md_var.h
@@ -68,4 +68,9 @@ void	cpu_setup(u_int);
 struct	trapframe;
 void	powerpc_interrupt(struct trapframe *);
 
+/* Platform half of DDB 'show pcpu' (db_show_mdpcpu) */
+struct	pcpu;
+void	cpu_db_show_mdpcpu(struct pcpu *);
+
+
 #endif /* !_MACHINE_MD_VAR_H_ */
diff --git a/sys/powerpc/powerpc/db_interface.c b/sys/powerpc/powerpc/db_interface.c
index 158578d7a27d..f0da39ba93ec 100644
--- a/sys/powerpc/powerpc/db_interface.c
+++ b/sys/powerpc/powerpc/db_interface.c
@@ -86,8 +86,15 @@ db_write_bytes(vm_offset_t addr, size_t size, char *data)
 void
 db_show_mdpcpu(struct pcpu *pc)
 {
+	struct thread *td;
 
 	db_printf("PPC: hwref   = %#zx\n", pc->pc_hwref);
 	db_printf("PPC: ipimask = %#x\n", pc->pc_ipimask);
 	db_printf("PPC: flags   = %#x\n", pc->pc_flags);
+	td = pc->pc_curthread;
+	if (td != NULL)
+		db_printf("PPC: spinlocks = %d saved_msr = %#jx\n",
+		    td->td_md.md_spinlock_count,
+		    (uintmax_t)td->td_md.md_saved_msr);
+	cpu_db_show_mdpcpu(pc);
 }