git: de5fcd166502 - main - powerpc/booke: Add a machine check stack
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 12 Sep 2026 02:40:44 UTC
The branch main has been updated by jhibbits:
URL: https://cgit.FreeBSD.org/src/commit/?id=de5fcd16650207f6f2e7c50afd1ebbaeb36612c7
commit de5fcd16650207f6f2e7c50afd1ebbaeb36612c7
Author: Justin Hibbits <jhibbits@FreeBSD.org>
AuthorDate: 2026-09-05 18:38:55 +0000
Commit: Justin Hibbits <jhibbits@FreeBSD.org>
CommitDate: 2026-09-12 02:40:30 +0000
powerpc/booke: Add a machine check stack
Machine check and critical exceptions are independent of each other, and
can interrupt each other. Since they're asynchronous we cannot trust
that the existing stack pointer (%r1) is correct at time of entry, so
add a private machine check stack separate from the critical exception
stack. As part of this, switch to the STANDARD_CRIT_PROLOG() for
machine check exceptions, and overload the macro to specify the stack to
switch to. Also add a savearea argument to CRIT_SRR_RESTORE() so that
we can restore machine check exception state from the right location.
---
sys/powerpc/booke/booke_machdep.c | 14 ++++++++++++--
sys/powerpc/booke/trap_subr.S | 30 ++++++++++++++++++------------
sys/powerpc/include/pcpu.h | 7 ++++---
sys/powerpc/powerpc/genassym.c | 1 +
4 files changed, 35 insertions(+), 17 deletions(-)
diff --git a/sys/powerpc/booke/booke_machdep.c b/sys/powerpc/booke/booke_machdep.c
index 58b847766d46..21b9852945d6 100644
--- a/sys/powerpc/booke/booke_machdep.c
+++ b/sys/powerpc/booke/booke_machdep.c
@@ -398,22 +398,32 @@ extern uintptr_t tlb0_miss_locks[];
* MAXCPU array here would reserve megabytes for CPUs that do not exist.
*/
static char booke_boot_critstack[BOOKE_CRITSTACK_SIZE] __aligned(16);
+static char booke_boot_mchkstack[BOOKE_CRITSTACK_SIZE] __aligned(16);
static bool booke_boot_critstack_used;
/* Initialise a struct pcpu. */
void
cpu_pcpu_init(struct pcpu *pcpu, int cpuid, size_t sz)
{
- char *critstack;
+ char *critstack, *mchkstack;
pcpu->pc_booke.tid_next = TID_MIN;
+ /*
+ * Machine check and critical interrupts have their own stacks with
+ * their own stack pointer, because regular mode registers cannot be
+ * trusted.
+ */
if (!booke_boot_critstack_used) {
booke_boot_critstack_used = true;
critstack = booke_boot_critstack;
- } else
+ mchkstack = booke_boot_mchkstack;
+ } else {
critstack = malloc(BOOKE_CRITSTACK_SIZE, M_DEVBUF, M_WAITOK);
+ mchkstack = malloc(BOOKE_CRITSTACK_SIZE, M_DEVBUF, M_WAITOK);
+ }
pcpu->pc_booke.critstack = critstack + BOOKE_CRITSTACK_SIZE;
+ pcpu->pc_booke.mchkstack = mchkstack + BOOKE_CRITSTACK_SIZE;
#ifdef SMP
uintptr_t *ptr;
diff --git a/sys/powerpc/booke/trap_subr.S b/sys/powerpc/booke/trap_subr.S
index 55e4d03639d4..69ed40cdd8ca 100644
--- a/sys/powerpc/booke/trap_subr.S
+++ b/sys/powerpc/booke/trap_subr.S
@@ -136,7 +136,7 @@
LOAD %r1, PC_CURPCB(%r1); /* Per-thread kernel stack */ \
1:
-#define STANDARD_CRIT_PROLOG(sprg_sp, savearea, isrr0, isrr1) \
+#define STANDARD_CRIT_PROLOG(sprg_sp, savearea, stack, isrr0, isrr1) \
mtspr sprg_sp, %r1; /* Save SP */ \
GET_CPUINFO(%r1); /* Per-cpu structure */ \
STORE %r30, (savearea+CPUSAVE_R30)(%r1); \
@@ -166,7 +166,7 @@
bf 17, 1f; \
LOAD %r1, PC_CURPCB(%r1); /* Per-thread kernel stack */ \
b 2f; \
-1: LOAD %r1, PC_BOOKE_CRITSTACK(%r1); \
+1: LOAD %r1, stack(%r1); \
2:
/*
@@ -177,10 +177,10 @@
* a TLB miss return. Nested exceptions taken by the C dispatcher clobber
* them either way, so restore before returning.
*/
-#define CRIT_SRR_RESTORE \
+#define CRIT_SRR_RESTORE(savearea) \
GET_CPUINFO(%r3); \
- LOAD %r4, (PC_BOOKE_CRITSAVE+BOOKE_CRITSAVE_SRR0)(%r3); \
- LOAD %r5, (PC_BOOKE_CRITSAVE+BOOKE_CRITSAVE_SRR1)(%r3); \
+ LOAD %r4, (savearea+BOOKE_CRITSAVE_SRR0)(%r3); \
+ LOAD %r5, (savearea+BOOKE_CRITSAVE_SRR1)(%r3); \
mtspr SPR_SRR0, %r4; \
mtspr SPR_SRR1, %r5
@@ -554,13 +554,14 @@ INTERRUPT(int_unknown)
* Critical input interrupt
****************************************************************************/
INTERRUPT(int_critical_input)
- STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
+ STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE,
+ PC_BOOKE_CRITSTACK, SPR_CSRR0, SPR_CSRR1)
FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_CRIT)
GET_TOCBASE(%r2)
addi %r3, %r1, CALLSIZE
bl CNAME(powerpc_interrupt)
TOC_RESTORE
- CRIT_SRR_RESTORE
+ CRIT_SRR_RESTORE(PC_BOOKE_CRITSAVE)
FRAME_LEAVE(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
rfci
@@ -569,12 +570,14 @@ INTERRUPT(int_critical_input)
* Machine check interrupt
****************************************************************************/
INTERRUPT(int_machine_check)
- STANDARD_PROLOG(SPR_SPRG3, PC_BOOKE_MCHKSAVE, SPR_MCSRR0, SPR_MCSRR1)
+ STANDARD_CRIT_PROLOG(SPR_SPRG3, PC_BOOKE_MCHKSAVE, PC_BOOKE_MCHKSTACK,
+ SPR_MCSRR0, SPR_MCSRR1)
FRAME_SETUP(SPR_SPRG3, PC_BOOKE_MCHKSAVE, EXC_MCHK)
GET_TOCBASE(%r2)
addi %r3, %r1, CALLSIZE
bl CNAME(powerpc_interrupt)
TOC_RESTORE
+ CRIT_SRR_RESTORE(PC_BOOKE_MCHKSAVE)
FRAME_LEAVE(SPR_SPRG3, PC_BOOKE_MCHKSAVE, SPR_MCSRR0, SPR_MCSRR1)
rfmci
@@ -655,13 +658,14 @@ INTERRUPT(int_fixed_interval_timer)
* Watchdog interrupt
****************************************************************************/
INTERRUPT(int_watchdog)
- STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
+ STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE,
+ PC_BOOKE_CRITSTACK, SPR_CSRR0, SPR_CSRR1)
FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_WDOG)
GET_TOCBASE(%r2)
addi %r3, %r1, CALLSIZE
bl CNAME(powerpc_interrupt)
TOC_RESTORE
- CRIT_SRR_RESTORE
+ CRIT_SRR_RESTORE(PC_BOOKE_CRITSAVE)
FRAME_LEAVE(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
rfci
@@ -981,14 +985,16 @@ interrupt_vector_top:
* Debug interrupt
****************************************************************************/
INTERRUPT(int_debug)
- STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
+ STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE,
+ PC_BOOKE_CRITSTACK, SPR_CSRR0, SPR_CSRR1)
FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
bl int_debug_int
FRAME_LEAVE(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
rfci
INTERRUPT(int_debug_ed)
- STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_DSRR0, SPR_DSRR1)
+ STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE,
+ PC_BOOKE_CRITSTACK, SPR_DSRR0, SPR_DSRR1)
FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
bl int_debug_int
FRAME_LEAVE(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_DSRR0, SPR_DSRR1)
diff --git a/sys/powerpc/include/pcpu.h b/sys/powerpc/include/pcpu.h
index 18f0e3209b92..752e34639640 100644
--- a/sys/powerpc/include/pcpu.h
+++ b/sys/powerpc/include/pcpu.h
@@ -93,17 +93,18 @@ struct pvo_entry;
#define BOOKE_CRITSTACK_SIZE 16384
#ifdef __powerpc64__
-#define BOOKE_PCPU_PAD 893
+#define BOOKE_PCPU_PAD 869
#else
-#define BOOKE_PCPU_PAD 361
+#define BOOKE_PCPU_PAD 349
#endif
#define PCPU_MD_BOOKE_FIELDS \
register_t critsave[BOOKE_CRITSAVE_LEN]; \
- register_t mchksave[CPUSAVE_LEN]; \
+ register_t mchksave[BOOKE_CRITSAVE_LEN]; \
register_t tlbsave[BOOKE_TLBSAVE_LEN]; \
register_t tlb_level; \
uintptr_t *tlb_lock; \
void *critstack; \
+ void *mchkstack; \
int tid_next; \
char __pad[BOOKE_PCPU_PAD];
diff --git a/sys/powerpc/powerpc/genassym.c b/sys/powerpc/powerpc/genassym.c
index e8c08867d778..4105575b11ee 100644
--- a/sys/powerpc/powerpc/genassym.c
+++ b/sys/powerpc/powerpc/genassym.c
@@ -70,6 +70,7 @@ ASSYM(PC_BOOKE_TLBSAVE, offsetof(struct pcpu, pc_booke.tlbsave));
ASSYM(PC_BOOKE_TLB_LEVEL, offsetof(struct pcpu, pc_booke.tlb_level));
ASSYM(PC_BOOKE_TLB_LOCK, offsetof(struct pcpu, pc_booke.tlb_lock));
ASSYM(PC_BOOKE_CRITSTACK, offsetof(struct pcpu, pc_booke.critstack));
+ASSYM(PC_BOOKE_MCHKSTACK, offsetof(struct pcpu, pc_booke.mchkstack));
#endif
ASSYM(CPUSAVE_R27, CPUSAVE_R27*sizeof(register_t));