powerpc/64s: Dedicated system reset interrupt stack

The system reset interrupt is used for crash/debug situations, so it is
desirable to have as little impact on the normal state of the system as
possible.

Currently it uses the current kernel stack to process the exception.
This stores into the stack which may be involved with the crash. The
stack pointer may be corrupted, or it may have overflowed.

Avoid or minimise these problems by creating a dedicated NMI stack for
the system reset interrupt to use.

Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Nicholas Piggin 2016-12-20 04:30:06 +10:00 committed by Michael Ellerman
parent c4f3b52ce7
commit b1ee8a3de5
6 changed files with 27 additions and 4 deletions

View File

@ -563,6 +563,19 @@ END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
bl hdlr; \
b ret
/*
* Exception where stack is already set in r1, r1 is saved in r10, and it
* continues rather than returns.
*/
#define EXCEPTION_COMMON_NORET_STACK(area, trap, label, hdlr, additions) \
EXCEPTION_PROLOG_COMMON_1(); \
EXCEPTION_PROLOG_COMMON_2(area); \
EXCEPTION_PROLOG_COMMON_3(trap); \
/* Volatile regs are potentially clobbered here */ \
additions; \
addi r3,r1,STACK_FRAME_OVERHEAD; \
bl hdlr
#define STD_EXCEPTION_COMMON(trap, label, hdlr) \
EXCEPTION_COMMON(PACA_EXGEN, trap, label, hdlr, \
ret_from_except, ADD_NVGPRS;ADD_RECONCILE)

View File

@ -185,7 +185,8 @@ struct paca_struct {
u64 exmc[13]; /* used for machine checks */
#endif
#ifdef CONFIG_PPC_BOOK3S_64
/* Exclusive emergency stack pointer for machine check exception. */
/* Exclusive stacks for system reset and machine check exception. */
void *nmi_emergency_sp;
void *mc_emergency_sp;
u16 in_nmi; /* In nmi handler */

View File

@ -234,6 +234,7 @@ int main(void)
OFFSET(PACAEMERGSP, paca_struct, emergency_sp);
#ifdef CONFIG_PPC_BOOK3S_64
OFFSET(PACAMCEMERGSP, paca_struct, mc_emergency_sp);
OFFSET(PACA_NMI_EMERG_SP, paca_struct, nmi_emergency_sp);
OFFSET(PACA_IN_MCE, paca_struct, in_mce);
OFFSET(PACA_IN_NMI, paca_struct, in_nmi);
#endif

View File

@ -144,10 +144,12 @@ EXC_COMMON_BEGIN(system_reset_common)
li r10,MSR_RI
mtmsrd r10,1
EXCEPTION_COMMON(PACA_EXNMI, 0x100,
system_reset, system_reset_exception, 1f,
mr r10,r1
ld r1,PACA_NMI_EMERG_SP(r13)
subi r1,r1,INT_FRAME_SIZE
EXCEPTION_COMMON_NORET_STACK(PACA_EXNMI, 0x100,
system_reset, system_reset_exception,
ADD_NVGPRS;ADD_RECONCILE)
1: /* EXCEPTION_COMMON continues here */
/*
* The stack is no longer in use, decrement in_nmi.

View File

@ -628,6 +628,11 @@ void __init emergency_stack_init(void)
paca[i].emergency_sp = (void *)ti + THREAD_SIZE;
#ifdef CONFIG_PPC_BOOK3S_64
/* emergency stack for NMI exception handling. */
ti = __va(memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit));
klp_init_thread_info(ti);
paca[i].nmi_emergency_sp = (void *)ti + THREAD_SIZE;
/* emergency stack for machine check exception handling. */
ti = __va(memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit));
klp_init_thread_info(ti);

View File

@ -2235,6 +2235,7 @@ static void dump_one_paca(int cpu)
DUMP(p, kernel_msr, "lx");
DUMP(p, emergency_sp, "p");
#ifdef CONFIG_PPC_BOOK3S_64
DUMP(p, nmi_emergency_sp, "p");
DUMP(p, mc_emergency_sp, "p");
DUMP(p, in_nmi, "x");
DUMP(p, in_mce, "x");