Commit 99d5040e authored by Max Filippov's avatar Max Filippov Committed by Chris Zankel
Browse files

xtensa: keep a3 and excsave1 on entry to exception handlers



Based on the SMP patch by Joe Taylor and subsequent fixes.
Preserve exception table pointer (normally stored in excsave1 SR) as it
cannot be easily restored in SMP environment.

Signed-off-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
Signed-off-by: default avatarChris Zankel <chris@zankel.net>
parent 16c5becf
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -82,6 +82,7 @@
#define PS_CALLINC_SHIFT	16
#define PS_CALLINC_SHIFT	16
#define PS_CALLINC_MASK		0x00030000
#define PS_CALLINC_MASK		0x00030000
#define PS_OWB_SHIFT		8
#define PS_OWB_SHIFT		8
#define PS_OWB_WIDTH		4
#define PS_OWB_MASK		0x00000F00
#define PS_OWB_MASK		0x00000F00
#define PS_RING_SHIFT		6
#define PS_RING_SHIFT		6
#define PS_RING_MASK		0x000000C0
#define PS_RING_MASK		0x000000C0
+2 −3
Original line number Original line Diff line number Diff line
@@ -146,9 +146,9 @@
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -171,7 +171,6 @@ ENTRY(fast_unaligned)
	s32i	a8, a2, PT_AREG8
	s32i	a8, a2, PT_AREG8


	rsr	a0, depc
	rsr	a0, depc
	xsr	a3, excsave1
	s32i	a0, a2, PT_AREG2
	s32i	a0, a2, PT_AREG2
	s32i	a3, a2, PT_AREG3
	s32i	a3, a2, PT_AREG3


+4 −5
Original line number Original line Diff line number Diff line
@@ -32,9 +32,9 @@
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -225,9 +225,9 @@ ENDPROC(coprocessor_restore)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -245,7 +245,6 @@ ENTRY(fast_coprocessor)


	/* Save remaining registers a1-a3 and SAR */
	/* Save remaining registers a1-a3 and SAR */


	xsr	a3, excsave1
	s32i	a3, a2, PT_AREG3
	s32i	a3, a2, PT_AREG3
	rsr	a3, sar
	rsr	a3, sar
	s32i	a1, a2, PT_AREG1
	s32i	a1, a2, PT_AREG1
+47 −68
Original line number Original line Diff line number Diff line
@@ -91,9 +91,9 @@
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original value in depc
 *   a2:	new stack pointer, original value in depc
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave1:	a3
 *   excsave1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -109,9 +109,8 @@


ENTRY(user_exception)
ENTRY(user_exception)


	/* Save a2, a3, and depc, restore excsave_1 and set SP. */
	/* Save a1, a2, a3, and set SP. */


	xsr	a3, excsave1
	rsr	a0, depc
	rsr	a0, depc
	s32i	a1, a2, PT_AREG1
	s32i	a1, a2, PT_AREG1
	s32i	a0, a2, PT_AREG2
	s32i	a0, a2, PT_AREG2
@@ -237,9 +236,9 @@ ENDPROC(user_exception)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -255,9 +254,8 @@ ENDPROC(user_exception)


ENTRY(kernel_exception)
ENTRY(kernel_exception)


	/* Save a0, a2, a3, DEPC and set SP. */
	/* Save a1, a2, a3, and set SP. */


	xsr	a3, excsave1		# restore a3, excsave_1
	rsr	a0, depc		# get a2
	rsr	a0, depc		# get a2
	s32i	a1, a2, PT_AREG1
	s32i	a1, a2, PT_AREG1
	s32i	a0, a2, PT_AREG2
	s32i	a0, a2, PT_AREG2
@@ -408,7 +406,7 @@ common_exception:
	 * exception handler and call the exception handler.
	 * exception handler and call the exception handler.
	 */
	 */


	movi	a4, exc_table
	rsr	a4, excsave1
	mov	a6, a1			# pass stack frame
	mov	a6, a1			# pass stack frame
	mov	a7, a0			# pass EXCCAUSE
	mov	a7, a0			# pass EXCCAUSE
	addx4	a4, a0, a4
	addx4	a4, a0, a4
@@ -832,9 +830,9 @@ ENDPROC(unrecoverable_exception)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -857,18 +855,16 @@ ENTRY(fast_alloca)


	rsr	a0, depc		# get a2
	rsr	a0, depc		# get a2
	s32i	a4, a2, PT_AREG4	# save a4 and
	s32i	a4, a2, PT_AREG4	# save a4 and
	s32i	a3, a2, PT_AREG3
	s32i	a0, a2, PT_AREG2	# a2 to stack
	s32i	a0, a2, PT_AREG2	# a2 to stack


	/* Exit critical section. */
	/* Exit critical section. */


	movi	a0, 0
	movi	a0, 0
	rsr	a3, excsave1
	s32i	a0, a3, EXC_TABLE_FIXUP
	s32i	a0, a3, EXC_TABLE_FIXUP


	/* Restore a3, excsave_1 */

	xsr	a3, excsave1		# make sure excsave_1 is valid for dbl.
	rsr	a4, epc1		# get exception address
	rsr	a4, epc1		# get exception address
	s32i	a3, a2, PT_AREG3	# save a3 to stack


#ifdef ALLOCA_EXCEPTION_IN_IRAM
#ifdef ALLOCA_EXCEPTION_IN_IRAM
#error	iram not supported
#error	iram not supported
@@ -1007,9 +1003,9 @@ ENDPROC(fast_alloca)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 */
 */


ENTRY(fast_syscall_kernel)
ENTRY(fast_syscall_kernel)
@@ -1056,7 +1052,6 @@ ENTRY(fast_syscall_unrecoverable)


	l32i    a0, a2, PT_AREG0        # restore a0
	l32i    a0, a2, PT_AREG0        # restore a0
	xsr     a2, depc                # restore a2, depc
	xsr     a2, depc                # restore a2, depc
	rsr     a3, excsave1


	wsr     a0, excsave1
	wsr     a0, excsave1
	movi    a0, unrecoverable_exception
	movi    a0, unrecoverable_exception
@@ -1078,10 +1073,10 @@ ENDPROC(fast_syscall_unrecoverable)
 *   a0:	a2 (syscall-nr), original value saved on stack (PT_AREG0)
 *   a0:	a2 (syscall-nr), original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in a0 and DEPC
 *   a2:	new stack pointer, original in a0 and DEPC
 *   a3:	dispatch table, original in excsave_1
 *   a3:	a3
 *   a4..a15:	unchanged
 *   a4..a15:	unchanged
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1114,8 +1109,6 @@ ENDPROC(fast_syscall_unrecoverable)


ENTRY(fast_syscall_xtensa)
ENTRY(fast_syscall_xtensa)


	xsr	a3, excsave1		# restore a3, excsave1

	s32i	a7, a2, PT_AREG7	# we need an additional register
	s32i	a7, a2, PT_AREG7	# we need an additional register
	movi	a7, 4			# sizeof(unsigned int)
	movi	a7, 4			# sizeof(unsigned int)
	access_ok a3, a7, a0, a2, .Leac	# a0: scratch reg, a2: sp
	access_ok a3, a7, a0, a2, .Leac	# a0: scratch reg, a2: sp
@@ -1178,9 +1171,9 @@ ENDPROC(fast_syscall_xtensa)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.
 * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.
 */
 */
@@ -1189,15 +1182,16 @@ ENTRY(fast_syscall_spill_registers)


	/* Register a FIXUP handler (pass current wb as a parameter) */
	/* Register a FIXUP handler (pass current wb as a parameter) */


	xsr	a3, excsave1
	movi	a0, fast_syscall_spill_registers_fixup
	movi	a0, fast_syscall_spill_registers_fixup
	s32i	a0, a3, EXC_TABLE_FIXUP
	s32i	a0, a3, EXC_TABLE_FIXUP
	rsr	a0, windowbase
	rsr	a0, windowbase
	s32i	a0, a3, EXC_TABLE_PARAM
	s32i	a0, a3, EXC_TABLE_PARAM
	xsr	a3, excsave1		# restore a3 and excsave_1


	/* Save a3 and SAR on stack. */
	/* Save a3, a4 and SAR on stack. */


	rsr	a0, sar
	rsr	a0, sar
	xsr	a3, excsave1		# restore a3 and excsave_1
	s32i	a3, a2, PT_AREG3
	s32i	a3, a2, PT_AREG3
	s32i	a4, a2, PT_AREG4
	s32i	a4, a2, PT_AREG4
	s32i	a0, a2, PT_AREG5	# store SAR to PT_AREG5
	s32i	a0, a2, PT_AREG5	# store SAR to PT_AREG5
@@ -1251,14 +1245,14 @@ fast_syscall_spill_registers_fixup:
	 * in WS, so that the exception handlers save them to the task stack.
	 * in WS, so that the exception handlers save them to the task stack.
	 */
	 */


	rsr	a3, excsave1	# get spill-mask
	xsr	a3, excsave1	# get spill-mask
	slli	a2, a3, 1	# shift left by one
	slli	a2, a3, 1	# shift left by one


	slli	a3, a2, 32-WSBITS
	slli	a3, a2, 32-WSBITS
	src	a2, a2, a3	# a1 = xxwww1yyxxxwww1yy......
	src	a2, a2, a3	# a1 = xxwww1yyxxxwww1yy......
	wsr	a2, windowstart	# set corrected windowstart
	wsr	a2, windowstart	# set corrected windowstart


	movi	a3, exc_table
	rsr	a3, excsave1
	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE	# restore a2
	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE	# restore a2
	l32i	a3, a3, EXC_TABLE_PARAM	# original WB (in user task)
	l32i	a3, a3, EXC_TABLE_PARAM	# original WB (in user task)


@@ -1295,7 +1289,7 @@ fast_syscall_spill_registers_fixup:


	/* Jump to the exception handler. */
	/* Jump to the exception handler. */


	movi	a3, exc_table
	rsr	a3, excsave1
	rsr	a0, exccause
	rsr	a0, exccause
	addx4	a0, a0, a3              	# find entry in table
	addx4	a0, a0, a3              	# find entry in table
	l32i	a0, a0, EXC_TABLE_FAST_USER     # load handler
	l32i	a0, a0, EXC_TABLE_FAST_USER     # load handler
@@ -1312,6 +1306,7 @@ fast_syscall_spill_registers_fixup_return:
	xsr	a3, excsave1
	xsr	a3, excsave1
	movi	a2, fast_syscall_spill_registers_fixup
	movi	a2, fast_syscall_spill_registers_fixup
	s32i	a2, a3, EXC_TABLE_FIXUP
	s32i	a2, a3, EXC_TABLE_FIXUP
	s32i	a0, a3, EXC_TABLE_DOUBLE_SAVE
	rsr	a2, windowbase
	rsr	a2, windowbase
	s32i	a2, a3, EXC_TABLE_PARAM
	s32i	a2, a3, EXC_TABLE_PARAM
	l32i	a2, a3, EXC_TABLE_KSTK
	l32i	a2, a3, EXC_TABLE_KSTK
@@ -1323,11 +1318,6 @@ fast_syscall_spill_registers_fixup_return:
	wsr	a3, windowbase
	wsr	a3, windowbase
	rsync
	rsync


	/* Restore a3 and return. */

	movi	a3, exc_table
	xsr	a3, excsave1

	rfde
	rfde




@@ -1514,9 +1504,8 @@ ENTRY(_spill_registers)


	movi	a0, 0
	movi	a0, 0


	movi	a3, exc_table
	rsr	a3, excsave1
	l32i	a1, a3, EXC_TABLE_KSTK
	l32i	a1, a3, EXC_TABLE_KSTK
	wsr	a3, excsave1


	movi	a4, (1 << PS_WOE_BIT) | LOCKLEVEL
	movi	a4, (1 << PS_WOE_BIT) | LOCKLEVEL
	wsr	a4, ps
	wsr	a4, ps
@@ -1560,9 +1549,9 @@ ENDPROC(fast_second_level_miss_double_kernel)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1570,9 +1559,10 @@ ENDPROC(fast_second_level_miss_double_kernel)


ENTRY(fast_second_level_miss)
ENTRY(fast_second_level_miss)


	/* Save a1. Note: we don't expect a double exception. */
	/* Save a1 and a3. Note: we don't expect a double exception. */


	s32i	a1, a2, PT_AREG1
	s32i	a1, a2, PT_AREG1
	s32i	a3, a2, PT_AREG3


	/* We need to map the page of PTEs for the user task.  Find
	/* We need to map the page of PTEs for the user task.  Find
	 * the pointer to that page.  Also, it's possible for tsk->mm
	 * the pointer to that page.  Also, it's possible for tsk->mm
@@ -1594,9 +1584,6 @@ ENTRY(fast_second_level_miss)
	l32i	a0, a1, TASK_MM		# tsk->mm
	l32i	a0, a1, TASK_MM		# tsk->mm
	beqz	a0, 9f
	beqz	a0, 9f



	/* We deliberately destroy a3 that holds the exception table. */

8:	rsr	a3, excvaddr		# fault address
8:	rsr	a3, excvaddr		# fault address
	_PGD_OFFSET(a0, a3, a1)
	_PGD_OFFSET(a0, a3, a1)
	l32i	a0, a0, 0		# read pmdval
	l32i	a0, a0, 0		# read pmdval
@@ -1647,7 +1634,7 @@ ENTRY(fast_second_level_miss)


	/* Exit critical section. */
	/* Exit critical section. */


4:	movi	a3, exc_table		# restore a3
4:	rsr	a3, excsave1
	movi	a0, 0
	movi	a0, 0
	s32i	a0, a3, EXC_TABLE_FIXUP
	s32i	a0, a3, EXC_TABLE_FIXUP


@@ -1655,8 +1642,8 @@ ENTRY(fast_second_level_miss)


	l32i	a0, a2, PT_AREG0
	l32i	a0, a2, PT_AREG0
	l32i	a1, a2, PT_AREG1
	l32i	a1, a2, PT_AREG1
	l32i	a3, a2, PT_AREG3
	l32i	a2, a2, PT_DEPC
	l32i	a2, a2, PT_DEPC
	xsr	a3, excsave1


	bgeui	a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
	bgeui	a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f


@@ -1743,11 +1730,8 @@ ENTRY(fast_second_level_miss)


2:	/* Invalid PGD, default exception handling */
2:	/* Invalid PGD, default exception handling */


	movi	a3, exc_table
	rsr	a1, depc
	rsr	a1, depc
	xsr	a3, excsave1
	s32i	a1, a2, PT_AREG2
	s32i	a1, a2, PT_AREG2
	s32i	a3, a2, PT_AREG3
	mov	a1, a2
	mov	a1, a2


	rsr	a2, ps
	rsr	a2, ps
@@ -1767,9 +1751,9 @@ ENDPROC(fast_second_level_miss)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a0:	trashed, original value saved on stack (PT_AREG0)
 *   a1:	a1
 *   a1:	a1
 *   a2:	new stack pointer, original in DEPC
 *   a2:	new stack pointer, original in DEPC
 *   a3:	dispatch table
 *   a3:	a3
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   depc:	a2, original value saved on stack (PT_DEPC)
 *   excsave_1:	a3
 *   excsave_1:	dispatch table
 *
 *
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1777,17 +1761,17 @@ ENDPROC(fast_second_level_miss)


ENTRY(fast_store_prohibited)
ENTRY(fast_store_prohibited)


	/* Save a1 and a4. */
	/* Save a1 and a3. */


	s32i	a1, a2, PT_AREG1
	s32i	a1, a2, PT_AREG1
	s32i	a4, a2, PT_AREG4
	s32i	a3, a2, PT_AREG3


	GET_CURRENT(a1,a2)
	GET_CURRENT(a1,a2)
	l32i	a0, a1, TASK_MM		# tsk->mm
	l32i	a0, a1, TASK_MM		# tsk->mm
	beqz	a0, 9f
	beqz	a0, 9f


8:	rsr	a1, excvaddr		# fault address
8:	rsr	a1, excvaddr		# fault address
	_PGD_OFFSET(a0, a1, a4)
	_PGD_OFFSET(a0, a1, a3)
	l32i	a0, a0, 0
	l32i	a0, a0, 0
	beqz	a0, 2f
	beqz	a0, 2f


@@ -1796,39 +1780,37 @@ ENTRY(fast_store_prohibited)
	 * and is not PAGE_NONE. See pgtable.h for possible PTE layouts.
	 * and is not PAGE_NONE. See pgtable.h for possible PTE layouts.
	 */
	 */


	_PTE_OFFSET(a0, a1, a4)
	_PTE_OFFSET(a0, a1, a3)
	l32i	a4, a0, 0		# read pteval
	l32i	a3, a0, 0		# read pteval
	movi	a1, _PAGE_CA_INVALID
	movi	a1, _PAGE_CA_INVALID
	ball	a4, a1, 2f
	ball	a3, a1, 2f
	bbci.l	a4, _PAGE_WRITABLE_BIT, 2f
	bbci.l	a3, _PAGE_WRITABLE_BIT, 2f


	movi	a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
	movi	a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
	or	a4, a4, a1
	or	a3, a3, a1
	rsr	a1, excvaddr
	rsr	a1, excvaddr
	s32i	a4, a0, 0
	s32i	a3, a0, 0


	/* We need to flush the cache if we have page coloring. */
	/* We need to flush the cache if we have page coloring. */
#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
	dhwb	a0, 0
	dhwb	a0, 0
#endif
#endif
	pdtlb	a0, a1
	pdtlb	a0, a1
	wdtlb	a4, a0
	wdtlb	a3, a0


	/* Exit critical section. */
	/* Exit critical section. */


	movi	a0, 0
	movi	a0, 0
	rsr	a3, excsave1
	s32i	a0, a3, EXC_TABLE_FIXUP
	s32i	a0, a3, EXC_TABLE_FIXUP


	/* Restore the working registers, and return. */
	/* Restore the working registers, and return. */


	l32i	a4, a2, PT_AREG4
	l32i	a3, a2, PT_AREG3
	l32i	a1, a2, PT_AREG1
	l32i	a1, a2, PT_AREG1
	l32i	a0, a2, PT_AREG0
	l32i	a0, a2, PT_AREG0
	l32i	a2, a2, PT_DEPC
	l32i	a2, a2, PT_DEPC


	/* Restore excsave1 and a3. */

	xsr	a3, excsave1
	bgeui	a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
	bgeui	a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f


	rsr	a2, depc
	rsr	a2, depc
@@ -1845,11 +1827,8 @@ ENTRY(fast_store_prohibited)


2:	/* If there was a problem, handle fault in C */
2:	/* If there was a problem, handle fault in C */


	rsr	a4, depc	# still holds a2
	rsr	a3, depc	# still holds a2
	xsr	a3, excsave1
	s32i	a3, a2, PT_AREG2
	s32i	a4, a2, PT_AREG2
	s32i	a3, a2, PT_AREG3
	l32i	a4, a2, PT_AREG4
	mov	a1, a2
	mov	a1, a2


	rsr	a2, ps
	rsr	a2, ps
+184 −66
Original line number Original line Diff line number Diff line
@@ -78,6 +78,7 @@ ENTRY(_UserExceptionVector)
	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
	addx4	a0, a0, a3		# find entry in table
	addx4	a0, a0, a3		# find entry in table
	l32i	a0, a0, EXC_TABLE_FAST_USER	# load handler
	l32i	a0, a0, EXC_TABLE_FAST_USER	# load handler
	xsr	a3, excsave1		# restore a3 and dispatch table
	jx	a0
	jx	a0


ENDPROC(_UserExceptionVector)
ENDPROC(_UserExceptionVector)
@@ -104,6 +105,7 @@ ENTRY(_KernelExceptionVector)
	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
	addx4	a0, a0, a3		# find entry in table
	addx4	a0, a0, a3		# find entry in table
	l32i	a0, a0, EXC_TABLE_FAST_KERNEL	# load handler address
	l32i	a0, a0, EXC_TABLE_FAST_KERNEL	# load handler address
	xsr	a3, excsave1		# restore a3 and dispatch table
	jx	a0
	jx	a0


ENDPROC(_KernelExceptionVector)
ENDPROC(_KernelExceptionVector)
@@ -168,7 +170,7 @@ ENDPROC(_KernelExceptionVector)
 *
 *
 *	a0:	   DEPC
 *	a0:	   DEPC
 *	a1: 	   a1
 *	a1: 	   a1
 *	a2:	   trashed, original value in EXC_TABLE_DOUBLE_A2
 *	a2:	   trashed, original value in EXC_TABLE_DOUBLE_SAVE
 *	a3:	   exctable
 *	a3:	   exctable
 *	depc:	   a0
 *	depc:	   a0
 *	excsave_1: a3
 *	excsave_1: a3
@@ -204,47 +206,46 @@ ENDPROC(_KernelExceptionVector)


	.section .DoubleExceptionVector.text, "ax"
	.section .DoubleExceptionVector.text, "ax"
	.begin literal_prefix .DoubleExceptionVector
	.begin literal_prefix .DoubleExceptionVector
	.globl _DoubleExceptionVector_WindowUnderflow
	.globl _DoubleExceptionVector_WindowOverflow


ENTRY(_DoubleExceptionVector)
ENTRY(_DoubleExceptionVector)


	/* Deliberately destroy excsave (don't assume it's value was valid). */
	xsr	a3, excsave1

	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
	wsr	a3, excsave1		# save a3


	/* Check for kernel double exception (usually fatal). */
	/* Check for kernel double exception (usually fatal). */


	rsr	a3, ps
	rsr	a2, ps
	_bbci.l	a3, PS_UM_BIT, .Lksp
	_bbci.l	a2, PS_UM_BIT, .Lksp


	/* Check if we are currently handling a window exception. */
	/* Check if we are currently handling a window exception. */
	/* Note: We don't need to indicate that we enter a critical section. */
	/* Note: We don't need to indicate that we enter a critical section. */


	xsr	a0, depc		# get DEPC, save a0
	xsr	a0, depc		# get DEPC, save a0


	movi	a3, WINDOW_VECTORS_VADDR
	movi	a2, WINDOW_VECTORS_VADDR
	_bltu	a0, a3, .Lfixup
	_bltu	a0, a2, .Lfixup
	addi	a3, a3, WINDOW_VECTORS_SIZE
	addi	a2, a2, WINDOW_VECTORS_SIZE
	_bgeu	a0, a3, .Lfixup
	_bgeu	a0, a2, .Lfixup


	/* Window overflow/underflow exception. Get stack pointer. */
	/* Window overflow/underflow exception. Get stack pointer. */


	mov	a3, a2
	l32i	a2, a3, EXC_TABLE_KSTK
	/* This explicit literal and the following references to it are made
	 * in order to fit DoubleExceptionVector.literals into the available
	 * 16-byte gap before DoubleExceptionVector.text in the absence of
	 * link time relaxation. See kernel/vmlinux.lds.S
	 */
	.literal .Lexc_table, exc_table
	l32r	a2, .Lexc_table
	l32i	a2, a2, EXC_TABLE_KSTK


	/* Check for overflow/underflow exception, jump if overflow. */
	/* Check for overflow/underflow exception, jump if overflow. */


	_bbci.l	a0, 6, .Lovfl
	_bbci.l	a0, 6, _DoubleExceptionVector_WindowOverflow


	/* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3  */
	/*

	 * Restart window underflow exception.
	/* Restart window underflow exception.
	 * Currently:
	 *	depc = orig a0,
	 *	a0 = orig DEPC,
	 *	a2 = new sp based on KSTK from exc_table
	 *	a3 = excsave_1
	 *	excsave_1 = orig a3
	 *
	 * We return to the instruction in user space that caused the window
	 * We return to the instruction in user space that caused the window
	 * underflow exception. Therefore, we change window base to the value
	 * underflow exception. Therefore, we change window base to the value
	 * before we entered the window underflow exception and prepare the
	 * before we entered the window underflow exception and prepare the
@@ -252,10 +253,11 @@ ENTRY(_DoubleExceptionVector)
	 * by changing depc (in a0).
	 * by changing depc (in a0).
	 * Note: We can trash the current window frame (a0...a3) and depc!
	 * Note: We can trash the current window frame (a0...a3) and depc!
	 */
	 */

_DoubleExceptionVector_WindowUnderflow:
	xsr	a3, excsave1
	wsr	a2, depc		# save stack pointer temporarily
	wsr	a2, depc		# save stack pointer temporarily
	rsr	a0, ps
	rsr	a0, ps
	extui	a0, a0, PS_OWB_SHIFT, 4
	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
	wsr	a0, windowbase
	wsr	a0, windowbase
	rsync
	rsync


@@ -263,28 +265,57 @@ ENTRY(_DoubleExceptionVector)


	xsr	a2, depc		# save a2 and get stack pointer
	xsr	a2, depc		# save a2 and get stack pointer
	s32i	a0, a2, PT_AREG0
	s32i	a0, a2, PT_AREG0

	xsr	a3, excsave1
	wsr	a3, excsave1		# save a3
	l32r	a3, .Lexc_table

	rsr	a0, exccause
	rsr	a0, exccause
	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
	addx4	a0, a0, a3
	addx4	a0, a0, a3
	xsr	a3, excsave1
	l32i	a0, a0, EXC_TABLE_FAST_USER
	l32i	a0, a0, EXC_TABLE_FAST_USER
	jx	a0
	jx	a0


.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
	/*
	 * We only allow the ITLB miss exception if we are in kernel space.
	 * All other exceptions are unexpected and thus unrecoverable!
	 */

#ifdef CONFIG_MMU
	.extern fast_second_level_miss_double_kernel

.Lksp:	/* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */

	rsr	a3, exccause
	beqi	a3, EXCCAUSE_ITLB_MISS, 1f
	addi	a3, a3, -EXCCAUSE_DTLB_MISS
	bnez	a3, .Lunrecoverable
1:	movi	a3, fast_second_level_miss_double_kernel
	jx	a3
#else
.equ	.Lksp,	.Lunrecoverable
#endif


	/* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */
	/* Critical! We can't handle this situation. PANIC! */


	l32r	a3, .Lexc_table
	.extern unrecoverable_exception
	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE	# temporary variable

.Lunrecoverable_fixup:
	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
	xsr	a0, depc

.Lunrecoverable:
	rsr	a3, excsave1
	wsr	a0, excsave1
	movi	a0, unrecoverable_exception
	callx0	a0

.Lfixup:/* Check for a fixup handler or if we were in a critical section. */

	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave1: a3 */


	/* Enter critical section. */
	/* Enter critical section. */


	l32i	a2, a3, EXC_TABLE_FIXUP
	l32i	a2, a3, EXC_TABLE_FIXUP
	s32i	a3, a3, EXC_TABLE_FIXUP
	s32i	a3, a3, EXC_TABLE_FIXUP
	beq	a2, a3, .Lunrecoverable_fixup	# critical!
	beq	a2, a3, .Lunrecoverable_fixup	# critical section
	beqz	a2, .Ldflt			# no handler was registered
	beqz	a2, .Ldflt			# no handler was registered


	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
@@ -293,58 +324,145 @@ ENTRY(_DoubleExceptionVector)


.Ldflt:	/* Get stack pointer. */
.Ldflt:	/* Get stack pointer. */


	l32i	a3, a3, EXC_TABLE_DOUBLE_SAVE
	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
	addi	a2, a3, -PT_USER_SIZE
	addi	a2, a2, -PT_USER_SIZE

.Lovfl:	/* Jump to default handlers. */


	/* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */
	/* a0: depc, a1: a1, a2: kstk, a3: exctable, depc: a0, excsave: a3 */


	xsr	a3, depc
	s32i	a0, a2, PT_DEPC
	s32i	a0, a2, PT_DEPC
	s32i	a3, a2, PT_AREG0
	l32i	a0, a3, EXC_TABLE_DOUBLE_SAVE
	xsr	a0, depc
	s32i	a0, a2, PT_AREG0


	/* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */
	/* a0: avail, a1: a1, a2: kstk, a3: exctable, depc: a2, excsave: a3 */


	l32r	a3, .Lexc_table
	rsr	a0, exccause
	rsr	a0, exccause
	addx4	a0, a0, a3
	addx4	a0, a0, a3
	xsr	a3, excsave1
	l32i	a0, a0, EXC_TABLE_FAST_USER
	l32i	a0, a0, EXC_TABLE_FAST_USER
	jx	a0
	jx	a0


	/*
	/*
	 * We only allow the ITLB miss exception if we are in kernel space.
	 * Restart window OVERFLOW exception.
	 * All other exceptions are unexpected and thus unrecoverable!
	 * Currently:
	 *	depc = orig a0,
	 *	a0 = orig DEPC,
	 *	a2 = new sp based on KSTK from exc_table
	 *	a3 = EXCSAVE_1
	 *	excsave_1 = orig a3
	 *
	 * We return to the instruction in user space that caused the window
	 * overflow exception. Therefore, we change window base to the value
	 * before we entered the window overflow exception and prepare the
	 * registers to return as if we were coming from a regular exception
	 * by changing DEPC (in a0).
	 *
	 * NOTE: We CANNOT trash the current window frame (a0...a3), but we
	 * can clobber depc.
	 *
	 * The tricky part here is that overflow8 and overflow12 handlers
	 * save a0, then clobber a0.  To restart the handler, we have to restore
	 * a0 if the double exception was past the point where a0 was clobbered.
	 *
	 * To keep things simple, we take advantage of the fact all overflow
	 * handlers save a0 in their very first instruction.  If DEPC was past
	 * that instruction, we can safely restore a0 from where it was saved
	 * on the stack.
	 *
	 * a0: depc, a1: a1, a2: kstk, a3: exc_table, depc: a0, excsave1: a3
	 */
	 */
_DoubleExceptionVector_WindowOverflow:
	extui	a2, a0, 0, 6	# get offset into 64-byte vector handler
	beqz	a2, 1f		# if at start of vector, don't restore


#ifdef CONFIG_MMU
	addi	a0, a0, -128
	.extern fast_second_level_miss_double_kernel
	bbsi	a0, 8, 1f	# don't restore except for overflow 8 and 12
	bbsi	a0, 7, 2f


.Lksp:	/* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
	/*
	 * 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).
	 */


	rsr	a3, exccause
	l32e	a2, a9, -16
	beqi	a3, EXCCAUSE_ITLB_MISS, 1f
	wsr	a2, depc	# replace the saved a0
	addi	a3, a3, -EXCCAUSE_DTLB_MISS
	j	1f
	bnez	a3, .Lunrecoverable
1:	movi	a3, fast_second_level_miss_double_kernel
	jx	a3
#else
.equ	.Lksp,	.Lunrecoverable
#endif


	/* Critical! We can't handle this situation. PANIC! */
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).
	 */


	.extern unrecoverable_exception
	l32e	a2, a13, -16
	wsr	a2, depc	# replace the saved a0
1:
	/*
	 * Restore WindowBase while leaving all address registers restored.
	 * We have to use ROTW for this, because WSR.WINDOWBASE requires
	 * an address register (which would prevent restore).
	 *
	 * Window Base goes from 0 ... 7 (Module 8)
	 * Window Start is 8 bits; Ex: (0b1010 1010):0x55 from series of call4s
	 */

	rsr	a0, ps
	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
	rsr	a2, windowbase
	sub	a0, a2, a0
	extui	a0, a0, 0, 3


.Lunrecoverable_fixup:
	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
	xsr	a0, depc
	xsr	a3, excsave1
	beqi	a0, 1, .L1pane
	beqi	a0, 3, .L3pane


.Lunrecoverable:
	rsr	a0, depc
	rsr	a3, excsave1
	rotw	-2
	wsr	a0, excsave1

	movi	a0, unrecoverable_exception
	/*
	callx0	a0
	 * We are now in the user code's original window frame.
	 * Process the exception as a user exception as if it was
	 * taken by the user code.
	 *
	 * This is similar to the user exception vector,
	 * except that PT_DEPC isn't set to EXCCAUSE.
	 */
1:
	xsr	a3, excsave1
	wsr	a2, depc
	l32i	a2, a3, EXC_TABLE_KSTK
	s32i	a0, a2, PT_AREG0
	rsr	a0, exccause

	s32i	a0, a2, PT_DEPC

	addx4	a0, a0, a3
	l32i	a0, a0, EXC_TABLE_FAST_USER
	xsr	a3, excsave1
	jx	a0

.L1pane:
	rsr	a0, depc
	rotw	-1
	j	1b

.L3pane:
	rsr	a0, depc
	rotw	-3
	j	1b


	.end literal_prefix
	.end literal_prefix