.macro __GEN_COMMON_BODY name
        .if IMASK
+               .if ! ISTACK
+               .error "No support for masked interrupt to use custom stack"
+               .endif
+
+               /* If coming from user, skip soft-mask tests. */
+               andi.   r10,r12,MSR_PR
+               bne     2f
+
+               /* Kernel code running below __end_interrupts is implicitly
+                * soft-masked */
+               LOAD_HANDLER(r10, __end_interrupts)
+               cmpld   r11,r10
+               li      r10,IMASK
+               blt-    1f
+
+               /* Test the soft mask state against our interrupt's bit */
                lbz     r10,PACAIRQSOFTMASK(r13)
-               andi.   r10,r10,IMASK
+1:             andi.   r10,r10,IMASK
                /* Associate vector numbers with bits in paca->irq_happened */
                .if IVEC == 0x500 || IVEC == 0xea0
                li      r10,PACA_IRQ_EE
 
        .if ISTACK
        andi.   r10,r12,MSR_PR          /* See if coming from user      */
-       mr      r10,r1                  /* Save r1                      */
+2:     mr      r10,r1                  /* Save r1                      */
        subi    r1,r1,INT_FRAME_SIZE    /* alloc frame on kernel stack  */
        beq-    100f
        ld      r1,PACAKSAVE(r13)       /* kernel stack to use          */
        ld      r10,PACA_EXGEN+EX_R10(r13)
        ld      r11,PACA_EXGEN+EX_R11(r13)
        ld      r12,PACA_EXGEN+EX_R12(r13)
-       /* returns to kernel where r13 must be set up, so don't restore it */
+       ld      r13,PACA_EXGEN+EX_R13(r13)
+       /* May return to masked low address where r13 is not set up */
        .if \hsrr
        HRFI_TO_KERNEL
        .else
 
 USE_FIXED_SECTION(virt_trampolines)
        /*
+        * All code below __end_interrupts is treated as soft-masked. If
+        * any code runs here with MSR[EE]=1, it must then cope with pending
+        * soft interrupt being raised (i.e., by ensuring it is replayed).
+        *
         * The __end_interrupts marker must be past the out-of-line (OOL)
         * handlers, so that they are copied to real address 0x100 when running
         * a relocatable kernel. This ensures they can be reached from the short