powerpc/64s: Fix system reset vs general interrupt reentrancy
authorNicholas Piggin <npiggin@gmail.com>
Mon, 19 Dec 2016 18:30:04 +0000 (04:30 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 28 Apr 2017 11:02:25 +0000 (21:02 +1000)
The system reset interrupt can occur when MSR_EE=0, and it currently
uses the PACA_EXGEN save area.

Some PACA_EXGEN interrupts have a window where MSR_RI=1 and MSR_EE=0
when the save area is still in use. A system reset interrupt in this
window can lead to undetected corruption when the save area gets
overwritten.

This patch introduces PACA_EXNMI save area for system reset exceptions,
which closes this corruption window. It's also helpful to retain the
EXGEN state for debugging situations, even if not considering the
recoverability aspect.

This patch also moves the PACA_EXMC area down to a less frequently used
part of the paca with the new save area.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/paca.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/exceptions-64s.S

index 229f22a2e9b18fcae048a986be479a5cd1a46f14..63a309a432ad562f7c3cf0bc64a782a0e853fe41 100644 (file)
@@ -549,8 +549,8 @@ BEGIN_FTR_SECTION                           \
        beql    ppc64_runlatch_on_trampoline;   \
 END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
 
-#define EXCEPTION_COMMON(trap, label, hdlr, ret, additions)    \
-       EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN);              \
+#define EXCEPTION_COMMON(area, trap, label, hdlr, ret, additions) \
+       EXCEPTION_PROLOG_COMMON(trap, area);                    \
        /* Volatile regs are potentially clobbered here */      \
        additions;                                              \
        addi    r3,r1,STACK_FRAME_OVERHEAD;                     \
@@ -558,17 +558,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
        b       ret
 
 #define STD_EXCEPTION_COMMON(trap, label, hdlr)                        \
-       EXCEPTION_COMMON(trap, label, hdlr, ret_from_except,    \
-                        ADD_NVGPRS;ADD_RECONCILE)
+       EXCEPTION_COMMON(PACA_EXGEN, trap, label, hdlr,         \
+               ret_from_except, ADD_NVGPRS;ADD_RECONCILE)
 
 /*
  * Like STD_EXCEPTION_COMMON, but for exceptions that can occur
  * in the idle task and therefore need the special idle handling
  * (finish nap and runlatch)
  */
-#define STD_EXCEPTION_COMMON_ASYNC(trap, label, hdlr)            \
-       EXCEPTION_COMMON(trap, label, hdlr, ret_from_except_lite, \
-                        FINISH_NAP;ADD_RECONCILE;RUNLATCH_ON)
+#define STD_EXCEPTION_COMMON_ASYNC(trap, label, hdlr)          \
+       EXCEPTION_COMMON(PACA_EXGEN, trap, label, hdlr,         \
+               ret_from_except_lite, FINISH_NAP;ADD_RECONCILE;RUNLATCH_ON)
 
 /*
  * When the idle code in power4_idle puts the CPU into NAP mode,
index 140ddb9ae5a87f49de3eae58e17d0d9be64ccea2..601e2327dd8c98bc5bbcd921bd3c565b78a62302 100644 (file)
@@ -99,7 +99,6 @@ struct paca_struct {
         */
        /* used for most interrupts/exceptions */
        u64 exgen[13] __attribute__((aligned(0x80)));
-       u64 exmc[13];           /* used for machine checks */
        u64 exslb[13];          /* used for SLB/segment table misses
                                 * on the linear mapping */
        /* SLB related definitions */
@@ -180,6 +179,11 @@ struct paca_struct {
        struct paca_struct **thread_sibling_pacas;
 #endif
 
+#ifdef CONFIG_PPC_STD_MMU_64
+       /* Non-maskable exceptions that are not performance critical */
+       u64 exnmi[13];          /* used for system reset (nmi) */
+       u64 exmc[13];           /* used for machine checks */
+#endif
 #ifdef CONFIG_PPC_BOOK3S_64
        /* Exclusive emergency stack pointer for machine check exception. */
        void *mc_emergency_sp;
index 8e1163426ccb95682366129514cc1f1eecbefe2e..46732ee70b43069e28bc178c17c9e97faa80ae3a 100644 (file)
@@ -220,6 +220,7 @@ int main(void)
        OFFSET(PACA_EXGEN, paca_struct, exgen);
        OFFSET(PACA_EXMC, paca_struct, exmc);
        OFFSET(PACA_EXSLB, paca_struct, exslb);
+       OFFSET(PACA_EXNMI, paca_struct, exnmi);
        OFFSET(PACALPPACAPTR, paca_struct, lppaca_ptr);
        OFFSET(PACA_SLBSHADOWPTR, paca_struct, slb_shadow_ptr);
        OFFSET(SLBSHADOW_STACKVSID, slb_shadow, save_area[SLB_NUM_BOLTED - 1].vsid);
index f765531c67b16f9521c9920ebae0043d1524e515..3a654b1f24e9b00256c71d0f3ad9257cbe6979ae 100644 (file)
@@ -116,7 +116,7 @@ EXC_VIRT_NONE(0x4000, 0x100)
 
 EXC_REAL_BEGIN(system_reset, 0x100, 0x100)
        SET_SCRATCH0(r13)
-       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
+       EXCEPTION_PROLOG_PSERIES(PACA_EXNMI, system_reset_common, EXC_STD,
                                 IDLETEST, 0x100)
 
 EXC_REAL_END(system_reset, 0x100, 0x100)
@@ -127,7 +127,10 @@ EXC_COMMON_BEGIN(system_reset_idle_common)
        b       pnv_powersave_wakeup
 #endif
 
-EXC_COMMON(system_reset_common, 0x100, system_reset_exception)
+EXC_COMMON_BEGIN(system_reset_common)
+       EXCEPTION_COMMON(PACA_EXNMI, 0x100,
+                       system_reset, system_reset_exception,
+                       ret_from_except, ADD_NVGPRS;ADD_RECONCILE)
 
 #ifdef CONFIG_PPC_PSERIES
 /*
@@ -135,7 +138,7 @@ EXC_COMMON(system_reset_common, 0x100, system_reset_exception)
  */
 TRAMP_REAL_BEGIN(system_reset_fwnmi)
        SET_SCRATCH0(r13)               /* save r13 */
-       EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common, EXC_STD,
+       EXCEPTION_PROLOG_PSERIES(PACA_EXNMI, system_reset_common, EXC_STD,
                                 NOTEST, 0x100)
 #endif /* CONFIG_PPC_PSERIES */