Lucas De MarchiFix common misspellings25985ed15 years agoHistory
1960 lines · 45.1 KB · Assembly
RawDownload
/* * arch/xtensa/kernel/entry.S * * Low-level exception handling * * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2004-2007 by Tensilica Inc. * * Chris Zankel <chris@zankel.net> * */ #include <linux/linkage.h>#include <asm/asm-offsets.h>#include <asm/processor.h>#include <asm/coprocessor.h>#include <asm/thread_info.h>#include <asm/uaccess.h>#include <asm/unistd.h>#include <asm/ptrace.h>#include <asm/current.h>#include <asm/pgtable.h>#include <asm/page.h>#include <asm/signal.h>#include <asm/tlbflush.h>#include <variant/tie-asm.h> /* Unimplemented features. */ #undef KERNEL_STACK_OVERFLOW_CHECK#undef PREEMPTIBLE_KERNEL#undef ALLOCA_EXCEPTION_IN_IRAM /* Not well tested. * * - fast_coprocessor */ /* * Macro to find first bit set in WINDOWBASE from the left + 1 * * 100....0 -> 1 * 010....0 -> 2 * 000....1 -> WSBITS */ 	.macro ffs_ws bit mask #if XCHAL_HAVE_NSA	nsau    \bit, \mask			# 32-WSBITS ... 31 (32 iff 0)	addi    \bit, \bit, WSBITS - 32 + 1   	# uppest bit set -> return 1#else	movi    \bit, WSBITS#if WSBITS > 16	_bltui  \mask, 0x10000, 99f	addi    \bit, \bit, -16	extui   \mask, \mask, 16, 16#endif#if WSBITS > 899:	_bltui  \mask, 0x100, 99f	addi    \bit, \bit, -8	srli    \mask, \mask, 8#endif99:	_bltui  \mask, 0x10, 99f	addi    \bit, \bit, -4	srli    \mask, \mask, 499:	_bltui  \mask, 0x4, 99f	addi    \bit, \bit, -2	srli    \mask, \mask, 299:	_bltui  \mask, 0x2, 99f	addi    \bit, \bit, -199: #endif	.endm /* ----------------- DEFAULT FIRST LEVEL EXCEPTION HANDLERS ----------------- */ /* * First-level exception handler for user exceptions. * Save some special registers, extra states and all registers in the AR * register file that were in use in the user task, and jump to the common * exception code. * We save SAR (used to calculate WMASK), and WB and WS (we don't have to * save them for kernel exceptions). * * Entry condition for user_exception: * *   a0:	trashed, original value saved on stack (PT_AREG0) *   a1:	a1 *   a2:	new stack pointer, original value in depc *   a3:	dispatch table *   depc:	a2, original value saved on stack (PT_DEPC) *   excsave1:	a3 * *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception * * Entry condition for _user_exception: * *   a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC *   excsave has been restored, and *   stack pointer (a1) has been set. * * Note: _user_exception might be at an odd address. Don't use call0..call12 */ ENTRY(user_exception) 	/* Save a2, a3, and depc, restore excsave_1 and set SP. */ 	xsr	a3, EXCSAVE_1	rsr	a0, DEPC	s32i	a1, a2, PT_AREG1	s32i	a0, a2, PT_AREG2	s32i	a3, a2, PT_AREG3	mov	a1, a2 	.globl _user_exception_user_exception: 	/* Save SAR and turn off single stepping */ 	movi	a2, 0	rsr	a3, SAR	xsr	a2, ICOUNTLEVEL	s32i	a3, a1, PT_SAR	s32i	a2, a1, PT_ICOUNTLEVEL 	/* Rotate ws so that the current windowbase is at bit0. */	/* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ 	rsr	a2, WINDOWBASE	rsr	a3, WINDOWSTART	ssr	a2	s32i	a2, a1, PT_WINDOWBASE	s32i	a3, a1, PT_WINDOWSTART	slli	a2, a3, 32-WSBITS	src	a2, a3, a2	srli	a2, a2, 32-WSBITS	s32i	a2, a1, PT_WMASK	# needed for restoring registers 	/* Save only live registers. */ 	_bbsi.l	a2, 1, 1f	s32i	a4, a1, PT_AREG4	s32i	a5, a1, PT_AREG5	s32i	a6, a1, PT_AREG6	s32i	a7, a1, PT_AREG7	_bbsi.l	a2, 2, 1f	s32i	a8, a1, PT_AREG8	s32i	a9, a1, PT_AREG9	s32i	a10, a1, PT_AREG10	s32i	a11, a1, PT_AREG11	_bbsi.l	a2, 3, 1f	s32i	a12, a1, PT_AREG12	s32i	a13, a1, PT_AREG13	s32i	a14, a1, PT_AREG14	s32i	a15, a1, PT_AREG15	_bnei	a2, 1, 1f		# only one valid frame? 	/* Only one valid frame, skip saving regs. */ 	j	2f 	/* Save the remaining registers.	 * We have to save all registers up to the first '1' from	 * the right, except the current frame (bit 0).	 * Assume a2 is:  001001000110001	 * All register frames starting from the top field to the marked '1'	 * must be saved.	 */ 1:	addi	a3, a2, -1		# eliminate '1' in bit 0: yyyyxxww0	neg	a3, a3			# yyyyxxww0 -> YYYYXXWW1+1	and	a3, a3, a2		# max. only one bit is set 	/* Find number of frames to save */ 	ffs_ws	a0, a3			# number of frames to the '1' from left 	/* Store information into WMASK:	 * bits 0..3: xxx1 masked lower 4 bits of the rotated windowstart,	 * bits 4...: number of valid 4-register frames	 */ 	slli	a3, a0, 4		# number of frames to save in bits 8..4	extui	a2, a2, 0, 4		# mask for the first 16 registers	or	a2, a3, a2	s32i	a2, a1, PT_WMASK	# needed when we restore the reg-file 	/* Save 4 registers at a time */ 1:	rotw	-1	s32i	a0, a5, PT_AREG_END - 16	s32i	a1, a5, PT_AREG_END - 12	s32i	a2, a5, PT_AREG_END - 8	s32i	a3, a5, PT_AREG_END - 4	addi	a0, a4, -1	addi	a1, a5, -16	_bnez	a0, 1b 	/* WINDOWBASE still in SAR! */ 	rsr	a2, SAR			# original WINDOWBASE	movi	a3, 1	ssl	a2	sll	a3, a3	wsr	a3, WINDOWSTART		# set corresponding WINDOWSTART bit	wsr	a2, WINDOWBASE		# and WINDOWSTART	rsync 	/* We are back to the original stack pointer (a1) */ 2:	/* Now, jump to the common exception handler. */ 	j	common_exception  /* * First-level exit handler for kernel exceptions * Save special registers and the live window frame. * Note: Even though we changes the stack pointer, we don't have to do a *	 MOVSP here, as we do that when we return from the exception. *	 (See comment in the kernel exception exit code) * * Entry condition for kernel_exception: * *   a0:	trashed, original value saved on stack (PT_AREG0) *   a1:	a1 *   a2:	new stack pointer, original in DEPC *   a3:	dispatch table *   depc:	a2, original value saved on stack (PT_DEPC) *   excsave_1:	a3 * *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception * * Entry condition for _kernel_exception: * *   a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC *   excsave has been restored, and *   stack pointer (a1) has been set. * * Note: _kernel_exception might be at an odd address. Don't use call0..call12 */ ENTRY(kernel_exception) 	/* Save a0, a2, a3, DEPC and set SP. */ 	xsr	a3, EXCSAVE_1		# restore a3, excsave_1	rsr	a0, DEPC		# get a2	s32i	a1, a2, PT_AREG1	s32i	a0, a2, PT_AREG2	s32i	a3, a2, PT_AREG3	mov	a1, a2 	.globl _kernel_exception_kernel_exception: 	/* Save SAR and turn off single stepping */ 	movi	a2, 0	rsr	a3, SAR	xsr	a2, ICOUNTLEVEL	s32i	a3, a1, PT_SAR	s32i	a2, a1, PT_ICOUNTLEVEL 	/* Rotate ws so that the current windowbase is at bit0. */	/* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */ 	rsr	a2, WINDOWBASE		# don't need to save these, we only	rsr	a3, WINDOWSTART		# need shifted windowstart: windowmask	ssr	a2	slli	a2, a3, 32-WSBITS	src	a2, a3, a2	srli	a2, a2, 32-WSBITS	s32i	a2, a1, PT_WMASK	# needed for kernel_exception_exit 	/* Save only the live window-frame */ 	_bbsi.l	a2, 1, 1f	s32i	a4, a1, PT_AREG4	s32i	a5, a1, PT_AREG5	s32i	a6, a1, PT_AREG6	s32i	a7, a1, PT_AREG7	_bbsi.l	a2, 2, 1f	s32i	a8, a1, PT_AREG8	s32i	a9, a1, PT_AREG9	s32i	a10, a1, PT_AREG10	s32i	a11, a1, PT_AREG11	_bbsi.l	a2, 3, 1f	s32i	a12, a1, PT_AREG12	s32i	a13, a1, PT_AREG13	s32i	a14, a1, PT_AREG14	s32i	a15, a1, PT_AREG15 1: #ifdef KERNEL_STACK_OVERFLOW_CHECK 	/*  Stack overflow check, for debugging  */	extui	a2, a1, TASK_SIZE_BITS,XX	movi	a3, SIZE??	_bge	a2, a3, out_of_stack_panic #endif /* * This is the common exception handler. * We get here from the user exception handler or simply by falling through * from the kernel exception handler. * Save the remaining special registers, switch to kernel mode, and jump * to the second-level exception handler. * */ common_exception: 	/* Save some registers, disable loops and clear the syscall flag. */ 	rsr	a2, DEBUGCAUSE	rsr	a3, EPC_1	s32i	a2, a1, PT_DEBUGCAUSE	s32i	a3, a1, PT_PC 	movi	a2, -1	rsr	a3, EXCVADDR	s32i	a2, a1, PT_SYSCALL	movi	a2, 0	s32i	a3, a1, PT_EXCVADDR	xsr	a2, LCOUNT	s32i	a2, a1, PT_LCOUNT 	/* It is now save to restore the EXC_TABLE_FIXUP variable. */ 	rsr	a0, EXCCAUSE	movi	a3, 0	rsr	a2, EXCSAVE_1	s32i	a0, a1, PT_EXCCAUSE	s32i	a3, a2, EXC_TABLE_FIXUP 	/* All unrecoverable states are saved on stack, now, and a1 is valid,	 * so we can allow exceptions and interrupts (*) again.	 * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)	 *	 * (*) We only allow interrupts if PS.INTLEVEL was not set to 1 before	 *     (interrupts disabled) and if this exception is not an interrupt.	 */ 	rsr	a3, PS	addi	a0, a0, -4	movi	a2, 1	extui	a3, a3, 0, 1		# a3 = PS.INTLEVEL[0]	moveqz	a3, a2, a0		# a3 = 1 iff interrupt exception	movi	a2, 1 << PS_WOE_BIT	or	a3, a3, a2	rsr	a0, EXCCAUSE	xsr	a3, PS 	s32i	a3, a1, PT_PS		# save ps 	/* Save LBEG, LEND */ 	rsr	a2, LBEG	rsr	a3, LEND	s32i	a2, a1, PT_LBEG	s32i	a3, a1, PT_LEND 	/* Save optional registers. */ 	save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT		/* Go to second-level dispatcher. Set up parameters to pass to the	 * exception handler and call the exception handler.	 */ 	movi	a4, exc_table	mov	a6, a1			# pass stack frame	mov	a7, a0			# pass EXCCAUSE	addx4	a4, a0, a4	l32i	a4, a4, EXC_TABLE_DEFAULT		# load handler 	/* Call the second-level handler */ 	callx4	a4 	/* Jump here for exception exit */ common_exception_return: 	/* Jump if we are returning from kernel exceptions. */ 1:	l32i	a3, a1, PT_PS	_bbci.l	a3, PS_UM_BIT, 4f 	/* Specific to a user exception exit:	 * We need to check some flags for signal handling and rescheduling,	 * and have to restore WB and WS, extra states, and all registers	 * in the register file that were in use in the user task.	 * Note that we don't disable interrupts here. 	 */ 	GET_THREAD_INFO(a2,a1)	l32i	a4, a2, TI_FLAGS 	_bbsi.l	a4, TIF_NEED_RESCHED, 3f	_bbci.l	a4, TIF_SIGPENDING, 4f 	l32i	a4, a1, PT_DEPC	bgeui	a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f 	/* Call do_signal() */ 	movi	a4, do_signal	# int do_signal(struct pt_regs*, sigset_t*)	mov	a6, a1	movi	a7, 0	callx4	a4	j	1b 3:	/* Reschedule */ 	movi	a4, schedule	# void schedule (void)	callx4	a4	j	1b 4:	/* Restore optional registers. */ 	load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT 	wsr	a3, PS		/* disable interrupts */ 	_bbci.l	a3, PS_UM_BIT, kernel_exception_exit user_exception_exit: 	/* Restore the state of the task and return from the exception. */ 	/* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */ 	l32i	a2, a1, PT_WINDOWBASE	l32i	a3, a1, PT_WINDOWSTART	wsr	a1, DEPC		# use DEPC as temp storage	wsr	a3, WINDOWSTART		# restore WINDOWSTART	ssr	a2			# preserve user's WB in the SAR	wsr	a2, WINDOWBASE		# switch to user's saved WB	rsync	rsr	a1, DEPC		# restore stack pointer	l32i	a2, a1, PT_WMASK	# register frames saved (in bits 4...9)	rotw	-1			# we restore a4..a7	_bltui	a6, 16, 1f		# only have to restore current window? 	/* The working registers are a0 and a3.  We are restoring to	 * a4..a7.  Be careful not to destroy what we have just restored.	 * Note: wmask has the format YYYYM:	 *       Y: number of registers saved in groups of 4	 *       M: 4 bit mask of first 16 registers	 */ 	mov	a2, a6	mov	a3, a5 2:	rotw	-1			# a0..a3 become a4..a7	addi	a3, a7, -4*4		# next iteration	addi	a2, a6, -16		# decrementing Y in WMASK	l32i	a4, a3, PT_AREG_END + 0	l32i	a5, a3, PT_AREG_END + 4	l32i	a6, a3, PT_AREG_END + 8	l32i	a7, a3, PT_AREG_END + 12	_bgeui	a2, 16, 2b 	/* Clear unrestored registers (don't leak anything to user-land */ 1:	rsr	a0, WINDOWBASE	rsr	a3, SAR	sub	a3, a0, a3	beqz	a3, 2f	extui	a3, a3, 0, WBBITS 1:	rotw	-1	addi	a3, a7, -1	movi	a4, 0	movi	a5, 0	movi	a6, 0	movi	a7, 0	bgei	a3, 1, 1b 	/* We are back were we were when we started.	 * Note: a2 still contains WMASK (if we've returned to the original	 *	 frame where we had loaded a2), or at least the lower 4 bits	 *	 (if we have restored WSBITS-1 frames).	 */ 2:	j	common_exception_exit 	/* This is the kernel exception exit.

Lines 1–500 of 1960.