diff options
Diffstat (limited to 'arch/xtensa/kernel/vectors.S')
| -rw-r--r-- | arch/xtensa/kernel/vectors.S | 160 | 
1 files changed, 137 insertions, 23 deletions
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S index cb8fd44caab..8453e6e3989 100644 --- a/arch/xtensa/kernel/vectors.S +++ b/arch/xtensa/kernel/vectors.S @@ -235,7 +235,7 @@ ENTRY(_DoubleExceptionVector)  	/* Check for overflow/underflow exception, jump if overflow. */ -	_bbci.l	a0, 6, _DoubleExceptionVector_WindowOverflow +	bbci.l	a0, 6, _DoubleExceptionVector_WindowOverflow  	/*  	 * Restart window underflow exception. @@ -376,38 +376,42 @@ _DoubleExceptionVector_WindowOverflow:  	beqz	a2, 1f		# if at start of vector, don't restore  	addi	a0, a0, -128 -	bbsi	a0, 8, 1f	# don't restore except for overflow 8 and 12 -	bbsi	a0, 7, 2f +	bbsi.l	a0, 8, 1f	# don't restore except for overflow 8 and 12 + +	/* +	 * This fixup handler is for the extremely unlikely case where the +	 * overflow handler's reference thru a0 gets a hardware TLB refill +	 * that bumps out the (distinct, aliasing) TLB entry that mapped its +	 * prior references thru a9/a13, and where our reference now thru +	 * a9/a13 gets a 2nd-level miss exception (not hardware TLB refill). +	 */ +	movi	a2, window_overflow_restore_a0_fixup +	s32i	a2, a3, EXC_TABLE_FIXUP +	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE +	xsr	a3, excsave1 + +	bbsi.l	a0, 7, 2f  	/*  	 * Restore a0 as saved by _WindowOverflow8(). -	 * -	 * FIXME:  we really need a fixup handler for this L32E, -	 * for the extremely unlikely case where the overflow handler's -	 * reference thru a0 gets a hardware TLB refill that bumps out -	 * the (distinct, aliasing) TLB entry that mapped its prior -	 * references thru a9, and where our reference now thru a9 -	 * gets a 2nd-level miss exception (not hardware TLB refill).  	 */ -	l32e	a2, a9, -16 -	wsr	a2, depc	# replace the saved a0 -	j	1f +	l32e	a0, a9, -16 +	wsr	a0, depc	# replace the saved a0 +	j	3f  2:  	/*  	 * Restore a0 as saved by _WindowOverflow12(). -	 * -	 * FIXME:  we really need a fixup handler for this L32E, -	 * for the extremely unlikely case where the overflow handler's -	 * reference thru a0 gets a hardware TLB refill that bumps out -	 * the (distinct, aliasing) TLB entry that mapped its prior -	 * references thru a13, and where our reference now thru a13 -	 * gets a 2nd-level miss exception (not hardware TLB refill).  	 */ -	l32e	a2, a13, -16 -	wsr	a2, depc	# replace the saved a0 +	l32e	a0, a13, -16 +	wsr	a0, depc	# replace the saved a0 +3: +	xsr	a3, excsave1 +	movi	a0, 0 +	s32i	a0, a3, EXC_TABLE_FIXUP +	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE  1:  	/*  	 * Restore WindowBase while leaving all address registers restored. @@ -449,6 +453,7 @@ _DoubleExceptionVector_WindowOverflow:  	s32i	a0, a2, PT_DEPC +_DoubleExceptionVector_handle_exception:  	addx4	a0, a0, a3  	l32i	a0, a0, EXC_TABLE_FAST_USER  	xsr	a3, excsave1 @@ -464,11 +469,120 @@ _DoubleExceptionVector_WindowOverflow:  	rotw	-3  	j	1b -	.end literal_prefix  ENDPROC(_DoubleExceptionVector)  /* + * Fixup handler for TLB miss in double exception handler for window owerflow. + * We get here with windowbase set to the window that was being spilled and + * a0 trashed. a0 bit 7 determines if this is a call8 (bit clear) or call12 + * (bit set) window. + * + * We do the following here: + * - go to the original window retaining a0 value; + * - set up exception stack to return back to appropriate a0 restore code + *   (we'll need to rotate window back and there's no place to save this + *    information, use different return address for that); + * - handle the exception; + * - go to the window that was being spilled; + * - set up window_overflow_restore_a0_fixup as a fixup routine; + * - reload a0; + * - restore the original window; + * - reset the default fixup routine; + * - return to user. By the time we get to this fixup handler all information + *   about the conditions of the original double exception that happened in + *   the window overflow handler is lost, so we just return to userspace to + *   retry overflow from start. + * + * a0: value of depc, original value in depc + * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE + * a3: exctable, original value in excsave1 + */ + +ENTRY(window_overflow_restore_a0_fixup) + +	rsr	a0, ps +	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH +	rsr	a2, windowbase +	sub	a0, a2, a0 +	extui	a0, a0, 0, 3 +	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE +	xsr	a3, excsave1 + +	_beqi	a0, 1, .Lhandle_1 +	_beqi	a0, 3, .Lhandle_3 + +	.macro	overflow_fixup_handle_exception_pane n + +	rsr	a0, depc +	rotw	-\n + +	xsr	a3, excsave1 +	wsr	a2, depc +	l32i	a2, a3, EXC_TABLE_KSTK +	s32i	a0, a2, PT_AREG0 + +	movi	a0, .Lrestore_\n +	s32i	a0, a2, PT_DEPC +	rsr	a0, exccause +	j	_DoubleExceptionVector_handle_exception + +	.endm + +	overflow_fixup_handle_exception_pane 2 +.Lhandle_1: +	overflow_fixup_handle_exception_pane 1 +.Lhandle_3: +	overflow_fixup_handle_exception_pane 3 + +	.macro	overflow_fixup_restore_a0_pane n + +	rotw	\n +	/* Need to preserve a0 value here to be able to handle exception +	 * that may occur on a0 reload from stack. It may occur because +	 * TLB miss handler may not be atomic and pointer to page table +	 * may be lost before we get here. There are no free registers, +	 * so we need to use EXC_TABLE_DOUBLE_SAVE area. +	 */ +	xsr	a3, excsave1 +	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE +	movi	a2, window_overflow_restore_a0_fixup +	s32i	a2, a3, EXC_TABLE_FIXUP +	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE +	xsr	a3, excsave1 +	bbsi.l	a0, 7, 1f +	l32e	a0, a9, -16 +	j	2f +1: +	l32e	a0, a13, -16 +2: +	rotw	-\n + +	.endm + +.Lrestore_2: +	overflow_fixup_restore_a0_pane 2 + +.Lset_default_fixup: +	xsr	a3, excsave1 +	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE +	movi	a2, 0 +	s32i	a2, a3, EXC_TABLE_FIXUP +	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE +	xsr	a3, excsave1 +	rfe + +.Lrestore_1: +	overflow_fixup_restore_a0_pane 1 +	j	.Lset_default_fixup +.Lrestore_3: +	overflow_fixup_restore_a0_pane 3 +	j	.Lset_default_fixup + +ENDPROC(window_overflow_restore_a0_fixup) + +	.end literal_prefix +/*   * Debug interrupt vector   *   * There is not much space here, so simply jump to another handler.  | 
