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
					
				| @ -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)					\ | ||||
|  | ||||
| @ -187,12 +187,15 @@ 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. | ||||
| 	 */ | ||||
| 	u16 in_mce; | ||||
| 	u8 hmi_event_available;		 /* HMI event is available */ | ||||
| 	u8 hmi_event_available;		/* HMI event is available */ | ||||
| #endif | ||||
| 
 | ||||
| 	/* Stuff for accurate time accounting */ | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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 */ | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -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"); | ||||
|  | ||||
| @ -2236,6 +2236,7 @@ static void dump_one_paca(int cpu) | ||||
| 	DUMP(p, emergency_sp, "p"); | ||||
| #ifdef CONFIG_PPC_BOOK3S_64 | ||||
| 	DUMP(p, mc_emergency_sp, "p"); | ||||
| 	DUMP(p, in_nmi, "x"); | ||||
| 	DUMP(p, in_mce, "x"); | ||||
| 	DUMP(p, hmi_event_available, "x"); | ||||
| #endif | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user