git: eaaf838e3304 - main - powerpc64: give each CPU its own KDB trap stack

From: Piotr Kubaj <pkubaj_at_FreeBSD.org>
Date: Thu, 15 Oct 2026 14:29:37 UTC
The branch main has been updated by pkubaj:

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

commit eaaf838e33042ed3f282a5cdf8e1260e78d4989b
Author:     Piotr Kubaj <pkubaj@FreeBSD.org>
AuthorDate: 2026-10-15 14:27:59 +0000
Commit:     Piotr Kubaj <pkubaj@FreeBSD.org>
CommitDate: 2026-10-15 14:27:59 +0000

    powerpc64: give each CPU its own KDB trap stack
    
    Kernel mode program, trace, breakpoint and machine check exceptions go
    through dbtrap, which saves the registers on trapstk and, if KDB doesn't
    want the trap, restores them from there and continues with the normal
    trap handler. There was just one trapstk for all CPUs, so when two of
    them trapped at the same time they overwrote each other's frame and one
    of them carried on with the other's registers. DTrace fbt probes are
    these traps, so a probe on a function that runs on several CPUs at once
    took the kernel down within seconds.
    
    Keep the stack in the pcpu instead. The boot CPU gets a static one,
    since it's set up before malloc works, the others allocate theirs in
    cpu_pcpu_init() like the Book-E critical interrupt stack.
    
    Approved by:    jhibbits
    MFC after:      1 week
    Differential Revision:  https://reviews.freebsd.org/D60362
---
 sys/powerpc/aim/aim_machdep.c  | 27 +++++++++++++++++++++++++++
 sys/powerpc/aim/locore64.S     |  7 -------
 sys/powerpc/aim/trap_subr64.S  |  7 +++----
 sys/powerpc/include/pcpu.h     |  3 ++-
 sys/powerpc/powerpc/genassym.c |  1 +
 5 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/sys/powerpc/aim/aim_machdep.c b/sys/powerpc/aim/aim_machdep.c
index 2dbd087c8f4e..c25a8fff9b4e 100644
--- a/sys/powerpc/aim/aim_machdep.c
+++ b/sys/powerpc/aim/aim_machdep.c
@@ -529,6 +529,20 @@ kdb_cpu_set_singlestep(void)
 	kdb_frame->srr1 |= PSL_SE;
 }
 
+#if defined(__powerpc64__) && defined(KDB)
+/* Stack used by the KDB trap handler (dbtrap) on each CPU. */
+#define	AIM_DBSTACK_SIZE	8192
+
+/*
+ * Stack for the KDB trap handler on the boot CPU.  It is static because the
+ * boot CPU is initialised long before malloc works; APs reach cpu_pcpu_init()
+ * at SI_SUB_CPU and allocate theirs.  Sizing a MAXCPU array would reserve
+ * megabytes for CPUs that do not exist.
+ */
+static char aim_boot_dbstack[AIM_DBSTACK_SIZE] __aligned(16);
+static bool aim_boot_dbstack_used;
+#endif
+
 /*
  * Initialise a struct pcpu.
  */
@@ -536,8 +550,21 @@ void
 cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t sz)
 {
 #ifdef __powerpc64__
+#ifdef KDB
+	char *dbstack;
+#endif
+
 /* Copy the SLB contents from the current CPU */
 memcpy(pcpu->pc_aim.slb, PCPU_GET(aim.slb), sizeof(pcpu->pc_aim.slb));
+
+#ifdef KDB
+	if (!aim_boot_dbstack_used) {
+		aim_boot_dbstack_used = true;
+		dbstack = aim_boot_dbstack;
+	} else
+		dbstack = malloc(AIM_DBSTACK_SIZE, M_DEVBUF, M_WAITOK);
+	pcpu->pc_aim.dbstack = dbstack + AIM_DBSTACK_SIZE;
+#endif
 #endif
 }
 
diff --git a/sys/powerpc/aim/locore64.S b/sys/powerpc/aim/locore64.S
index 9e49b605b8b4..de6bfe6f6b08 100644
--- a/sys/powerpc/aim/locore64.S
+++ b/sys/powerpc/aim/locore64.S
@@ -62,13 +62,6 @@ GLOBAL(tmpstk)
 TOC_ENTRY(tmpstk)
 TOC_ENTRY(can_wakeup)
 
-#ifdef KDB
-#define TRAPSTKSZ       8192            /* 8k trap stack */
-GLOBAL(trapstk)
-        .space        TRAPSTKSZ
-TOC_ENTRY(trapstk)
-#endif
-
 
 /*
  * Entry point for bootloaders that do not fully implement ELF and start
diff --git a/sys/powerpc/aim/trap_subr64.S b/sys/powerpc/aim/trap_subr64.S
index 56291337dd5b..db996d26bfa4 100644
--- a/sys/powerpc/aim/trap_subr64.S
+++ b/sys/powerpc/aim/trap_subr64.S
@@ -920,10 +920,9 @@ dbtrap:
 	andi.	%r1,%r1,0xff00
 	mtsprg3	%r1
 
-	GET_TOCBASE(%r1)			/* get new SP */
-	addis	%r1,%r1,TOC_REF(trapstk)@ha
-	ld	%r1,TOC_REF(trapstk)@l(%r1)
-	addi	%r1,%r1,(TRAPSTKSZ-48)
+	GET_CPUINFO(%r1)			/* this CPU's trap stack */
+	ld	%r1,PC_AIM_DBSTACK(%r1)
+	addi	%r1,%r1,-48
 
 	FRAME_SETUP(PC_DBSAVE)
 /* Call C trap code: */
diff --git a/sys/powerpc/include/pcpu.h b/sys/powerpc/include/pcpu.h
index 752e34639640..994964cab63e 100644
--- a/sys/powerpc/include/pcpu.h
+++ b/sys/powerpc/include/pcpu.h
@@ -69,7 +69,8 @@ struct pvo_entry;
 	struct pvo_entry *qmap_pvo;					\
 	struct mtx	qmap_lock;					\
 	uint64_t	opal_hmi_flags;					\
-	char		__pad[1337];
+	void		*dbstack;		/* KDB trap stack top */	\
+	char		__pad[1329];
 
 #ifdef __powerpc64__
 #define PCPU_MD_AIM_FIELDS	PCPU_MD_AIM64_FIELDS
diff --git a/sys/powerpc/powerpc/genassym.c b/sys/powerpc/powerpc/genassym.c
index 4105575b11ee..5365dd47bd7e 100644
--- a/sys/powerpc/powerpc/genassym.c
+++ b/sys/powerpc/powerpc/genassym.c
@@ -114,6 +114,7 @@ ASSYM(PC_KERNSLB, offsetof(struct pcpu, pc_aim.slb));
 ASSYM(PC_USERSLB, offsetof(struct pcpu, pc_aim.userslb));
 ASSYM(PC_SLBSAVE, offsetof(struct pcpu, pc_aim.slbsave));
 ASSYM(PC_SLBSTACK, offsetof(struct pcpu, pc_aim.slbstack));
+ASSYM(PC_AIM_DBSTACK, offsetof(struct pcpu, pc_aim.dbstack));
 ASSYM(USER_SLB_SLOT, USER_SLB_SLOT);
 ASSYM(USER_SLB_SLBE, USER_SLB_SLBE);
 ASSYM(SEGMENT_MASK, SEGMENT_MASK);