The branch main has been updated by jhibbits:

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

commit 68ecb918a5313150be660322c6686ae6292b4aac
Author:     Justin Hibbits <[email protected]>
AuthorDate: 2026-09-04 03:40:12 +0000
Commit:     Justin Hibbits <[email protected]>
CommitDate: 2026-09-05 04:09:45 +0000

    powerpc/booke: Reorganize FRAME_LEAVE
    
    There's a small window between when the SRR* registers are restore and
    the exception returns, in which a TLB miss exception may be triggered.
    Since there are not special SRR* registers for TLB miss exceptions, the
    registers from the frame will be ovwritten, and the FRAME_LEAVE block
    will effectively be re-entered on exit, leading to a very hard to
    diagnose panic or wedge.
    
    Minimize this chance by pushing the SRR* restore to the last possible
    moments, caching them in a PCPU save area instead until the end.  This
    matches what the AIM side already does.
---
 sys/powerpc/booke/trap_subr.S | 42 +++++++++++++++++++++++++++++++-----------
 1 file changed, 31 insertions(+), 11 deletions(-)

diff --git a/sys/powerpc/booke/trap_subr.S b/sys/powerpc/booke/trap_subr.S
index 10babefbb2f8..55e4d03639d4 100644
--- a/sys/powerpc/booke/trap_subr.S
+++ b/sys/powerpc/booke/trap_subr.S
@@ -314,13 +314,23 @@
 
 /*
  *
+ * sprg_sp - SPRG{1-3} reg free to use as a scratch once r1 is restored
+ * savearea - temp save area (pc_{tempsave, critsave, mchksave, dbsave})
  * isrr0-1 - save restore registers to restore CPU state to (may be
  *           SRR0-1, CSRR0-1, MCSRR0-1
  *
  * Notes:
  *  - potential TLB miss: YES. The deref'd kstack may be not covered
+ *
+ *  - xSRR0-1 are staged in the savearea rather than written to the SPRs up
+ *    front.  A DTLB miss on the kstack below is not maskable by wrteei, and
+ *    the hardware overwrites SRR0-1 on entry to the miss handler, which then
+ *    restores its own values -- so anything parked in SRR0-1 across the
+ *    register reload is lost, and the rfi returns into the middle of this
+ *    macro instead of to the interrupted context.  Everything after the last
+ *    kstack access touches only pcpu and SPRs, which cannot fault.
  */
-#define        FRAME_LEAVE(isrr0, isrr1)                                       
\
+#define        FRAME_LEAVE(sprg_sp, savearea, isrr0, isrr1)                    
\
        wrteei 0;                                                       \
        /* restore CTR, XER, LR, CR */                                  \
        LOAD    %r4, FRAME_CTR+CALLSIZE(%r1);                           \
@@ -334,16 +344,26 @@
        /* restore DBCR0 */                                             \
        LOAD    %r4, FRAME_BOOKE_DBCR0+CALLSIZE(%r1);                   \
        mtspr   SPR_DBCR0, %r4;                                         \
-       /* restore xSRR0-1 */                                           \
+       /* stage xSRR0-1 where a TLB miss cannot reach them */          \
        LOAD    %r30, FRAME_SRR0+CALLSIZE(%r1);                         \
        LOAD    %r31, FRAME_SRR1+CALLSIZE(%r1);                         \
-       mtspr   isrr0, %r30;                                            \
-       mtspr   isrr1, %r31;                                            \
+       GET_CPUINFO(%r4);                                               \
+       STORE   %r30, (savearea+CPUSAVE_SRR0)(%r4);                     \
+       STORE   %r31, (savearea+CPUSAVE_SRR1)(%r4);                     \
        /* restore R2-31, SP */                                         \
        LD_REGS(%r1);                                                   \
        LOAD    %r2, FRAME_2+CALLSIZE(%r1);                             \
        LOAD    %r0, FRAME_0+CALLSIZE(%r1);                             \
        LOAD    %r1, FRAME_1+CALLSIZE(%r1);                             \
+       /* no kstack references past here; park r3 to free a scratch */ \
+       mtspr   sprg_sp, %r3;                                           \
+       GET_CPUINFO(%r3);                                               \
+       LOAD    %r3, (savearea+CPUSAVE_SRR0)(%r3);                      \
+       mtspr   isrr0, %r3;                                             \
+       GET_CPUINFO(%r3);                                               \
+       LOAD    %r3, (savearea+CPUSAVE_SRR1)(%r3);                      \
+       mtspr   isrr1, %r3;                                             \
+       mfspr   %r3, sprg_sp;                                           \
        isync
 
 /*
@@ -541,7 +561,7 @@ INTERRUPT(int_critical_input)
        bl      CNAME(powerpc_interrupt)
        TOC_RESTORE
        CRIT_SRR_RESTORE
-       FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
+       FRAME_LEAVE(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
        rfci
 
 
@@ -555,7 +575,7 @@ INTERRUPT(int_machine_check)
        addi    %r3, %r1, CALLSIZE
        bl      CNAME(powerpc_interrupt)
        TOC_RESTORE
-       FRAME_LEAVE(SPR_MCSRR0, SPR_MCSRR1)
+       FRAME_LEAVE(SPR_SPRG3, PC_BOOKE_MCHKSAVE, SPR_MCSRR0, SPR_MCSRR1)
        rfmci
 
 
@@ -642,7 +662,7 @@ INTERRUPT(int_watchdog)
        bl      CNAME(powerpc_interrupt)
        TOC_RESTORE
        CRIT_SRR_RESTORE
-       FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
+       FRAME_LEAVE(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
        rfci
 
 
@@ -964,14 +984,14 @@ INTERRUPT(int_debug)
        STANDARD_CRIT_PROLOG(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_CSRR0, SPR_CSRR1)
        FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
        bl      int_debug_int
-       FRAME_LEAVE(SPR_CSRR0, SPR_CSRR1)
+       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)
        FRAME_SETUP(SPR_SPRG2, PC_BOOKE_CRITSAVE, EXC_DEBUG)
        bl      int_debug_int
-       FRAME_LEAVE(SPR_DSRR0, SPR_DSRR1)
+       FRAME_LEAVE(SPR_SPRG2, PC_BOOKE_CRITSAVE, SPR_DSRR0, SPR_DSRR1)
        rfdi
        /* .long 0x4c00004e */
 
@@ -1043,7 +1063,7 @@ CNAME(trapexit):
 CNAME(asttrapexit):
        b       trapexit                /* test ast ret value ? */
 1:
-       FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
+       FRAME_LEAVE(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
        rfi
 
 
@@ -1097,7 +1117,7 @@ dbtrap:
        b       trap_common
 
 dbleave:
-       FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
+       FRAME_LEAVE(SPR_SPRG1, PC_DBSAVE, SPR_SRR0, SPR_SRR1)
        rfi
 ASEND(breakpoint)
 #endif /* KDB */

Reply via email to