Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c4f3b52c authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

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: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent a3d96f70
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -275,6 +275,12 @@ END_FTR_SECTION_NESTED(ftr,ftr,943)

#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)					\
	BEGIN_FTR_SECTION_NESTED(947)					\
+4 −1
Original line number Diff line number Diff line
@@ -187,6 +187,9 @@ struct paca_struct {
#ifdef CONFIG_PPC_BOOK3S_64
	/* Exclusive emergency stack pointer for machine check exception. */
	void *mc_emergency_sp;

	u16 in_nmi;			/* In nmi handler */

	/*
	 * Flag to check whether we are in machine check early handler
	 * and already using emergency stack.
+1 −0
Original line number Diff line number Diff line
@@ -235,6 +235,7 @@ int main(void)
#ifdef CONFIG_PPC_BOOK3S_64
	OFFSET(PACAMCEMERGSP, paca_struct, mc_emergency_sp);
	OFFSET(PACA_IN_MCE, paca_struct, in_mce);
	OFFSET(PACA_IN_NMI, paca_struct, in_nmi);
#endif
	OFFSET(PACAHWCPUID, paca_struct, hw_cpu_id);
	OFFSET(PACAKEXECSTATE, paca_struct, kexec_state);
+32 −5
Original line number Diff line number Diff line
@@ -116,7 +116,11 @@ EXC_VIRT_NONE(0x4000, 0x100)

EXC_REAL_BEGIN(system_reset, 0x100, 0x100)
	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)

EXC_REAL_END(system_reset, 0x100, 0x100)
@@ -128,9 +132,31 @@ EXC_COMMON_BEGIN(system_reset_idle_common)
#endif

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,
			system_reset, system_reset_exception,
			ret_from_except, ADD_NVGPRS;ADD_RECONCILE)
			system_reset, system_reset_exception, 1f,
			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
/*
@@ -138,8 +164,9 @@ EXC_COMMON_BEGIN(system_reset_common)
 */
TRAMP_REAL_BEGIN(system_reset_fwnmi)
	SET_SCRATCH0(r13)		/* save r13 */
	EXCEPTION_PROLOG_PSERIES(PACA_EXNMI, system_reset_common, EXC_STD,
				 NOTEST, 0x100)
	/* See comment at system_reset exception */
	EXCEPTION_PROLOG_PSERIES_NORI(PACA_EXNMI, system_reset_common,
						EXC_STD, NOTEST, 0x100)
#endif /* CONFIG_PPC_PSERIES */


+7 −1
Original line number Diff line number Diff line
@@ -282,11 +282,17 @@ void system_reset_exception(struct pt_regs *regs)
	/* See if any machine dependent calls */
	if (ppc_md.system_reset_exception) {
		if (ppc_md.system_reset_exception(regs))
			return;
			goto out;
	}

	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 */
	if (!(regs->msr & MSR_RI))
		panic("Unrecoverable System Reset");
Loading