diff options
Diffstat (limited to 'arch/powerpc/kernel/exceptions-64s.S')
| -rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 25 | 
1 files changed, 24 insertions, 1 deletions
| diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 48da0f5d2f7f..1c80bd292e48 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */  /*   * This file contains the 64-bit "server" PowerPC variant   * of the low level exception handling including exception @@ -734,7 +735,29 @@ EXC_REAL(program_check, 0x700, 0x100)  EXC_VIRT(program_check, 0x4700, 0x100, 0x700)  TRAMP_KVM(PACA_EXGEN, 0x700)  EXC_COMMON_BEGIN(program_check_common) -	EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN) +	/* +	 * It's possible to receive a TM Bad Thing type program check with +	 * userspace register values (in particular r1), but with SRR1 reporting +	 * that we came from the kernel. Normally that would confuse the bad +	 * stack logic, and we would report a bad kernel stack pointer. Instead +	 * we switch to the emergency stack if we're taking a TM Bad Thing from +	 * the kernel. +	 */ +	li	r10,MSR_PR		/* Build a mask of MSR_PR ..	*/ +	oris	r10,r10,0x200000@h	/* .. and SRR1_PROGTM		*/ +	and	r10,r10,r12		/* Mask SRR1 with that.		*/ +	srdi	r10,r10,8		/* Shift it so we can compare	*/ +	cmpldi	r10,(0x200000 >> 8)	/* .. with an immediate.	*/ +	bne 1f				/* If != go to normal path.	*/ + +	/* SRR1 had PR=0 and SRR1_PROGTM=1, so use the emergency stack	*/ +	andi.	r10,r12,MSR_PR;		/* Set CR0 correctly for label	*/ +					/* 3 in EXCEPTION_PROLOG_COMMON	*/ +	mr	r10,r1			/* Save r1			*/ +	ld	r1,PACAEMERGSP(r13)	/* Use emergency stack		*/ +	subi	r1,r1,INT_FRAME_SIZE	/* alloc stack frame		*/ +	b 3f				/* Jump into the macro !!	*/ +1:	EXCEPTION_PROLOG_COMMON(0x700, PACA_EXGEN)  	bl	save_nvgprs  	RECONCILE_IRQ_STATE(r10, r11)  	addi	r3,r1,STACK_FRAME_OVERHEAD |