mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-23 23:32:14 +00:00
powerpc/64s: Disallow system reset vs system reset reentrancy
In preparation for using a dedicated stack for system reset interrupts, prevent a nested system reset from recovering, in order to simplify code that is called in crash/debug path. This allows a system reset interrupt to just use the base stack pointer. Keep an in_nmi nesting counter similarly to the in_mce counter. Consider the interrrupt non-recoverable if it is taken inside another system reset. Interrupt nesting could be allowed similarly to MCE, but system reset is a special case that's not for normal operation, so simplicity wins until there is requirement for nested system reset interrupts. Signed-off-by: Nicholas Piggin <npiggin@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
a3d96f70c1
commit
c4f3b52ce7
6 changed files with 51 additions and 7 deletions
|
@ -275,6 +275,12 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Do not enable RI */
|
||||||
|
#define EXCEPTION_PROLOG_PSERIES_NORI(area, label, h, extra, vec) \
|
||||||
|
EXCEPTION_PROLOG_0(area); \
|
||||||
|
EXCEPTION_PROLOG_1(area, extra, vec); \
|
||||||
|
EXCEPTION_PROLOG_PSERIES_1_NORI(label, h);
|
||||||
|
|
||||||
|
|
||||||
#define __KVM_HANDLER(area, h, n) \
|
#define __KVM_HANDLER(area, h, n) \
|
||||||
BEGIN_FTR_SECTION_NESTED(947) \
|
BEGIN_FTR_SECTION_NESTED(947) \
|
||||||
|
|
|
@ -187,12 +187,15 @@ struct paca_struct {
|
||||||
#ifdef CONFIG_PPC_BOOK3S_64
|
#ifdef CONFIG_PPC_BOOK3S_64
|
||||||
/* Exclusive emergency stack pointer for machine check exception. */
|
/* Exclusive emergency stack pointer for machine check exception. */
|
||||||
void *mc_emergency_sp;
|
void *mc_emergency_sp;
|
||||||
|
|
||||||
|
u16 in_nmi; /* In nmi handler */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flag to check whether we are in machine check early handler
|
* Flag to check whether we are in machine check early handler
|
||||||
* and already using emergency stack.
|
* and already using emergency stack.
|
||||||
*/
|
*/
|
||||||
u16 in_mce;
|
u16 in_mce;
|
||||||
u8 hmi_event_available; /* HMI event is available */
|
u8 hmi_event_available; /* HMI event is available */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Stuff for accurate time accounting */
|
/* Stuff for accurate time accounting */
|
||||||
|
|
|
@ -235,6 +235,7 @@ int main(void)
|
||||||
#ifdef CONFIG_PPC_BOOK3S_64
|
#ifdef CONFIG_PPC_BOOK3S_64
|
||||||
OFFSET(PACAMCEMERGSP, paca_struct, mc_emergency_sp);
|
OFFSET(PACAMCEMERGSP, paca_struct, mc_emergency_sp);
|
||||||
OFFSET(PACA_IN_MCE, paca_struct, in_mce);
|
OFFSET(PACA_IN_MCE, paca_struct, in_mce);
|
||||||
|
OFFSET(PACA_IN_NMI, paca_struct, in_nmi);
|
||||||
#endif
|
#endif
|
||||||
OFFSET(PACAHWCPUID, paca_struct, hw_cpu_id);
|
OFFSET(PACAHWCPUID, paca_struct, hw_cpu_id);
|
||||||
OFFSET(PACAKEXECSTATE, paca_struct, kexec_state);
|
OFFSET(PACAKEXECSTATE, paca_struct, kexec_state);
|
||||||
|
|
|
@ -116,7 +116,11 @@ EXC_VIRT_NONE(0x4000, 0x100)
|
||||||
|
|
||||||
EXC_REAL_BEGIN(system_reset, 0x100, 0x100)
|
EXC_REAL_BEGIN(system_reset, 0x100, 0x100)
|
||||||
SET_SCRATCH0(r13)
|
SET_SCRATCH0(r13)
|
||||||
EXCEPTION_PROLOG_PSERIES(PACA_EXNMI, system_reset_common, EXC_STD,
|
/*
|
||||||
|
* MSR_RI is not enabled, because PACA_EXNMI and nmi stack is
|
||||||
|
* being used, so a nested NMI exception would corrupt it.
|
||||||
|
*/
|
||||||
|
EXCEPTION_PROLOG_PSERIES_NORI(PACA_EXNMI, system_reset_common, EXC_STD,
|
||||||
IDLETEST, 0x100)
|
IDLETEST, 0x100)
|
||||||
|
|
||||||
EXC_REAL_END(system_reset, 0x100, 0x100)
|
EXC_REAL_END(system_reset, 0x100, 0x100)
|
||||||
|
@ -128,9 +132,31 @@ EXC_COMMON_BEGIN(system_reset_idle_common)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
EXC_COMMON_BEGIN(system_reset_common)
|
EXC_COMMON_BEGIN(system_reset_common)
|
||||||
|
/*
|
||||||
|
* Increment paca->in_nmi then enable MSR_RI. SLB or MCE will be able
|
||||||
|
* to recover, but nested NMI will notice in_nmi and not recover
|
||||||
|
* because of the use of the NMI stack. in_nmi reentrancy is tested in
|
||||||
|
* system_reset_exception.
|
||||||
|
*/
|
||||||
|
lhz r10,PACA_IN_NMI(r13)
|
||||||
|
addi r10,r10,1
|
||||||
|
sth r10,PACA_IN_NMI(r13)
|
||||||
|
li r10,MSR_RI
|
||||||
|
mtmsrd r10,1
|
||||||
|
|
||||||
EXCEPTION_COMMON(PACA_EXNMI, 0x100,
|
EXCEPTION_COMMON(PACA_EXNMI, 0x100,
|
||||||
system_reset, system_reset_exception,
|
system_reset, system_reset_exception, 1f,
|
||||||
ret_from_except, ADD_NVGPRS;ADD_RECONCILE)
|
ADD_NVGPRS;ADD_RECONCILE)
|
||||||
|
1: /* EXCEPTION_COMMON continues here */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The stack is no longer in use, decrement in_nmi.
|
||||||
|
*/
|
||||||
|
lhz r10,PACA_IN_NMI(r13)
|
||||||
|
subi r10,r10,1
|
||||||
|
sth r10,PACA_IN_NMI(r13)
|
||||||
|
|
||||||
|
b ret_from_except
|
||||||
|
|
||||||
#ifdef CONFIG_PPC_PSERIES
|
#ifdef CONFIG_PPC_PSERIES
|
||||||
/*
|
/*
|
||||||
|
@ -138,8 +164,9 @@ EXC_COMMON_BEGIN(system_reset_common)
|
||||||
*/
|
*/
|
||||||
TRAMP_REAL_BEGIN(system_reset_fwnmi)
|
TRAMP_REAL_BEGIN(system_reset_fwnmi)
|
||||||
SET_SCRATCH0(r13) /* save r13 */
|
SET_SCRATCH0(r13) /* save r13 */
|
||||||
EXCEPTION_PROLOG_PSERIES(PACA_EXNMI, system_reset_common, EXC_STD,
|
/* See comment at system_reset exception */
|
||||||
NOTEST, 0x100)
|
EXCEPTION_PROLOG_PSERIES_NORI(PACA_EXNMI, system_reset_common,
|
||||||
|
EXC_STD, NOTEST, 0x100)
|
||||||
#endif /* CONFIG_PPC_PSERIES */
|
#endif /* CONFIG_PPC_PSERIES */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -282,11 +282,17 @@ void system_reset_exception(struct pt_regs *regs)
|
||||||
/* See if any machine dependent calls */
|
/* See if any machine dependent calls */
|
||||||
if (ppc_md.system_reset_exception) {
|
if (ppc_md.system_reset_exception) {
|
||||||
if (ppc_md.system_reset_exception(regs))
|
if (ppc_md.system_reset_exception(regs))
|
||||||
return;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
die("System Reset", regs, SIGABRT);
|
die("System Reset", regs, SIGABRT);
|
||||||
|
|
||||||
|
out:
|
||||||
|
#ifdef CONFIG_PPC_BOOK3S_64
|
||||||
|
BUG_ON(get_paca()->in_nmi == 0);
|
||||||
|
if (get_paca()->in_nmi > 1)
|
||||||
|
panic("Unrecoverable nested System Reset");
|
||||||
|
#endif
|
||||||
/* Must die if the interrupt is not recoverable */
|
/* Must die if the interrupt is not recoverable */
|
||||||
if (!(regs->msr & MSR_RI))
|
if (!(regs->msr & MSR_RI))
|
||||||
panic("Unrecoverable System Reset");
|
panic("Unrecoverable System Reset");
|
||||||
|
|
|
@ -2236,6 +2236,7 @@ static void dump_one_paca(int cpu)
|
||||||
DUMP(p, emergency_sp, "p");
|
DUMP(p, emergency_sp, "p");
|
||||||
#ifdef CONFIG_PPC_BOOK3S_64
|
#ifdef CONFIG_PPC_BOOK3S_64
|
||||||
DUMP(p, mc_emergency_sp, "p");
|
DUMP(p, mc_emergency_sp, "p");
|
||||||
|
DUMP(p, in_nmi, "x");
|
||||||
DUMP(p, in_mce, "x");
|
DUMP(p, in_mce, "x");
|
||||||
DUMP(p, hmi_event_available, "x");
|
DUMP(p, hmi_event_available, "x");
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue