📄 entry.s
字号:
kernel_exception_exit: /* Disable interrupts (a3 holds PT_PS) */ wsr a3, PS#ifdef PREEMPTIBLE_KERNEL#ifdef CONFIG_PREEMPT /* * Note: We've just returned from a call4, so we have * at least 4 addt'l regs. */ /* Check current_thread_info->preempt_count */ GET_THREAD_INFO(a2) l32i a3, a2, TI_PREEMPT bnez a3, 1f l32i a2, a2, TI_FLAGS1:#endif#endif /* Check if we have to do a movsp. * * We only have to do a movsp if the previous window-frame has * been spilled to the *temporary* exception stack instead of the * task's stack. This is the case if the corresponding bit in * WINDOWSTART for the previous window-frame was set before * (not spilled) but is zero now (spilled). * If this bit is zero, all other bits except the one for the * current window frame are also zero. So, we can use a simple test: * 'and' WINDOWSTART and WINDOWSTART-1: * * (XXXXXX1[0]* - 1) AND XXXXXX1[0]* = XXXXXX0[0]* * * The result is zero only if one bit was set. * * (Note: We might have gone through several task switches before * we come back to the current task, so WINDOWBASE might be * different from the time the exception occurred.) */ /* Test WINDOWSTART before and after the exception. * We actually have WMASK, so we only have to test if it is 1 or not. */ l32i a2, a1, PT_WMASK _beqi a2, 1, common_exception_exit # Spilled before exception,jump /* Test WINDOWSTART now. If spilled, do the movsp */ rsr a3, WINDOWSTART addi a0, a3, -1 and a3, a3, a0 _bnez a3, common_exception_exit /* Do a movsp (we returned from a call4, so we have at least a0..a7) */ addi a0, a1, -16 l32i a3, a0, 0 l32i a4, a0, 4 s32i a3, a1, PT_SIZE+0 s32i a4, a1, PT_SIZE+4 l32i a3, a0, 8 l32i a4, a0, 12 s32i a3, a1, PT_SIZE+8 s32i a4, a1, PT_SIZE+12 /* Common exception exit. * We restore the special register and the current window frame, and * return from the exception. * * Note: We expect a2 to hold PT_WMASK */common_exception_exit: _bbsi.l a2, 1, 1f l32i a4, a1, PT_AREG4 l32i a5, a1, PT_AREG5 l32i a6, a1, PT_AREG6 l32i a7, a1, PT_AREG7 _bbsi.l a2, 2, 1f l32i a8, a1, PT_AREG8 l32i a9, a1, PT_AREG9 l32i a10, a1, PT_AREG10 l32i a11, a1, PT_AREG11 _bbsi.l a2, 3, 1f l32i a12, a1, PT_AREG12 l32i a13, a1, PT_AREG13 l32i a14, a1, PT_AREG14 l32i a15, a1, PT_AREG15 /* Restore PC, SAR */1: l32i a2, a1, PT_PC l32i a3, a1, PT_SAR wsr a2, EPC_1 wsr a3, SAR /* Restore LBEG, LEND, LCOUNT */ l32i a2, a1, PT_LBEG l32i a3, a1, PT_LEND wsr a2, LBEG l32i a2, a1, PT_LCOUNT wsr a3, LEND wsr a2, LCOUNT /* We control single stepping through the ICOUNTLEVEL register. */ l32i a2, a1, PT_ICOUNTLEVEL movi a3, -2 wsr a2, ICOUNTLEVEL wsr a3, ICOUNT /* Check if it was double exception. */ l32i a0, a1, PT_DEPC l32i a3, a1, PT_AREG3 l32i a2, a1, PT_AREG2 _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f /* Restore a0...a3 and return */ l32i a0, a1, PT_AREG0 l32i a1, a1, PT_AREG1 rfe1: wsr a0, DEPC l32i a0, a1, PT_AREG0 l32i a1, a1, PT_AREG1 rfde/* * Debug exception handler. * * Currently, we don't support KGDB, so only user application can be debugged. * * When we get here, a0 is trashed and saved to excsave[debuglevel] */ENTRY(debug_exception) rsr a0, EPS + XCHAL_DEBUGLEVEL bbsi.l a0, PS_EXCM_BIT, 1f # exception mode /* Set EPC_1 and EXCCAUSE */ wsr a2, DEPC # save a2 temporarily rsr a2, EPC + XCHAL_DEBUGLEVEL wsr a2, EPC_1 movi a2, EXCCAUSE_MAPPED_DEBUG wsr a2, EXCCAUSE /* Restore PS to the value before the debug exc but with PS.EXCM set.*/ movi a2, 1 << PS_EXCM_BIT or a2, a0, a2 movi a0, debug_exception # restore a3, debug jump vector wsr a2, PS xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL /* Switch to kernel/user stack, restore jump vector, and save a0 */ bbsi.l a2, PS_UM_BIT, 2f # jump if user mode addi a2, a1, -16-PT_SIZE # assume kernel stack s32i a0, a2, PT_AREG0 movi a0, 0 s32i a1, a2, PT_AREG1 s32i a0, a2, PT_DEPC # mark it as a regular exception xsr a0, DEPC s32i a3, a2, PT_AREG3 s32i a0, a2, PT_AREG2 mov a1, a2 j _kernel_exception2: rsr a2, EXCSAVE_1 l32i a2, a2, EXC_TABLE_KSTK # load kernel stack pointer s32i a0, a2, PT_AREG0 movi a0, 0 s32i a1, a2, PT_AREG1 s32i a0, a2, PT_DEPC xsr a0, DEPC s32i a3, a2, PT_AREG3 s32i a0, a2, PT_AREG2 mov a1, a2 j _user_exception /* Debug exception while in exception mode. */1: j 1b // FIXME!!/* * We get here in case of an unrecoverable exception. * The only thing we can do is to be nice and print a panic message. * We only produce a single stack frame for panic, so ??? * * * Entry conditions: * * - a0 contains the caller address; original value saved in excsave1. * - the original a0 contains a valid return address (backtrace) or 0. * - a2 contains a valid stackpointer * * Notes: * * - If the stack pointer could be invalid, the caller has to setup a * dummy stack pointer (e.g. the stack of the init_task) * * - If the return address could be invalid, the caller has to set it * to 0, so the backtrace would stop. * */ .align 4unrecoverable_text: .ascii "Unrecoverable error in exception handler\0"ENTRY(unrecoverable_exception) movi a0, 1 movi a1, 0 wsr a0, WINDOWSTART wsr a1, WINDOWBASE rsync movi a1, (1 << PS_WOE_BIT) | 1 wsr a1, PS rsync movi a1, init_task movi a0, 0 addi a1, a1, PT_REGS_OFFSET movi a4, panic movi a6, unrecoverable_text callx4 a41: j 1b/* -------------------------- FAST EXCEPTION HANDLERS ----------------------- *//* * Fast-handler for alloca exceptions * * The ALLOCA handler is entered when user code executes the MOVSP * instruction and the caller's frame is not in the register file. * In this case, the caller frame's a0..a3 are on the stack just * below sp (a1), and this handler moves them. * * For "MOVSP <ar>,<as>" without destination register a1, this routine * simply moves the value from <as> to <ar> without moving the save area. * * Entry condition: * * 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 */#if XCHAL_HAVE_BE#define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 4, 4#define _EXTUI_MOVSP_DST(ar) extui ar, ar, 0, 4#else#define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 0, 4#define _EXTUI_MOVSP_DST(ar) extui ar, ar, 4, 4#endifENTRY(fast_alloca) /* We shouldn't be in a double exception. */ l32i a0, a2, PT_DEPC _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, .Lunhandled_double rsr a0, DEPC # get a2 s32i a4, a2, PT_AREG4 # save a4 and s32i a0, a2, PT_AREG2 # a2 to stack /* Exit critical section. */ movi a0, 0 s32i a0, a3, EXC_TABLE_FIXUP /* Restore a3, excsave_1 */ xsr a3, EXCSAVE_1 # make sure excsave_1 is valid for dbl. rsr a4, EPC_1 # get exception address s32i a3, a2, PT_AREG3 # save a3 to stack#ifdef ALLOCA_EXCEPTION_IN_IRAM#error iram not supported#else /* Note: l8ui not allowed in IRAM/IROM!! */ l8ui a0, a4, 1 # read as(src) from MOVSP instruction#endif movi a3, .Lmovsp_src _EXTUI_MOVSP_SRC(a0) # extract source register number addx8 a3, a0, a3 jx a3.Lunhandled_double: wsr a0, EXCSAVE_1 movi a0, unrecoverable_exception callx0 a0 .align 8.Lmovsp_src: l32i a3, a2, PT_AREG0; _j 1f; .align 8 mov a3, a1; _j 1f; .align 8 l32i a3, a2, PT_AREG2; _j 1f; .align 8 l32i a3, a2, PT_AREG3; _j 1f; .align 8 l32i a3, a2, PT_AREG4; _j 1f; .align 8 mov a3, a5; _j 1f; .align 8 mov a3, a6; _j 1f; .align 8 mov a3, a7; _j 1f; .align 8 mov a3, a8; _j 1f; .align 8 mov a3, a9; _j 1f; .align 8 mov a3, a10; _j 1f; .align 8 mov a3, a11; _j 1f; .align 8 mov a3, a12; _j 1f; .align 8 mov a3, a13; _j 1f; .align 8 mov a3, a14; _j 1f; .align 8 mov a3, a15; _j 1f; .align 81:#ifdef ALLOCA_EXCEPTION_IN_IRAM#error iram not supported#else l8ui a0, a4, 0 # read ar(dst) from MOVSP instruction#endif addi a4, a4, 3 # step over movsp _EXTUI_MOVSP_DST(a0) # extract destination register wsr a4, EPC_1 # save new epc_1 _bnei a0, 1, 1f # no 'movsp a1, ax': jump /* Move the save area. This implies the use of the L32E * and S32E instructions, because this move must be done with * the user's PS.RING privilege levels, not with ring 0 * (kernel's) privileges currently active with PS.EXCM * set. Note that we have stil registered a fixup routine with the * double exception vector in case a double exception occurs. */ /* a0,a4:avail a1:old user stack a2:exc. stack a3:new user stack. */ l32e a0, a1, -16 l32e a4, a1, -12 s32e a0, a3, -16 s32e a4, a3, -12 l32e a0, a1, -8 l32e a4, a1, -4 s32e a0, a3, -8 s32e a4, a3, -4 /* Restore stack-pointer and all the other saved registers. */ mov a1, a3 l32i a4, a2, PT_AREG4 l32i a3, a2, PT_AREG3 l32i a0, a2, PT_AREG0 l32i a2, a2, PT_AREG2 rfe /* MOVSP <at>,<as> was invoked with <at> != a1. * Because the stack pointer is not being modified, * we should be able to just modify the pointer * without moving any save area. * The processor only traps these occurrences if the * caller window isn't live, so unfortunately we can't * use this as an alternate trap mechanism. * So we just do the move. This requires that we * resolve the destination register, not just the source, * so there's some extra work. * (PERHAPS NOT REALLY NEEDED, BUT CLEANER...) */ /* a0 dst-reg, a1 user-stack, a2 stack, a3 value of src reg. */1: movi a4, .Lmovsp_dst addx8 a4, a0, a4 jx a4 .align 8.Lmovsp_dst: s32i a3, a2, PT_AREG0; _j 1f; .align 8 mov a1, a3; _j 1f; .align 8 s32i a3, a2, PT_AREG2; _j 1f; .align 8 s32i a3, a2, PT_AREG3; _j 1f; .align 8 s32i a3, a2, PT_AREG4; _j 1f; .align 8 mov a5, a3; _j 1f; .align 8 mov a6, a3; _j 1f; .align 8 mov a7, a3; _j 1f; .align 8 mov a8, a3; _j 1f; .align 8 mov a9, a3; _j 1f; .align 8 mov a10, a3; _j 1f; .align 8 mov a11, a3; _j 1f; .align 8 mov a12, a3; _j 1f; .align 8 mov a13, a3; _j 1f; .align 8 mov a14, a3; _j 1f; .align 8 mov a15, a3; _j 1f; .align 81: l32i a4, a2, PT_AREG4 l32i a3, a2, PT_AREG3 l32i a0, a2, PT_AREG0 l32i a2, a2, PT_AREG2 rfe/* * fast system calls. * * WARNING: The kernel doesn't save the entire user context before * handling a fast system call. These functions are small and short, * usually offering some functionality not available to user tasks. * * BE CAREFUL TO PRESERVE THE USER'S CONTEXT. * * Entry condition: * * 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 */ENTRY(fast_syscall_kernel) /* Skip syscall. */ rsr a0, EPC_1 addi a0, a0, 3 wsr a0, EPC_1 l32i a0, a2, PT_DEPC bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable rsr a0, DEPC # get syscall-nr _beqz a0, fast_syscall_spill_registers _beqi a0, __NR_xtensa, fast_syscall_xtensa j kernel_exceptionENTRY(fast_syscall_user) /* Skip syscall. */ rsr a0, EPC_1 addi a0, a0, 3 wsr a0, EPC_1 l32i a0, a2, PT_DEPC bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable rsr a0, DEPC # get syscall-nr _beqz a0, fast_syscall_spill_registers _beqi a0, __NR_xtensa, fast_syscall_xtensa j user_exceptionENTRY(fast_syscall_unrecoverable) /* Restore all states. */ l32i a0, a2, PT_AREG0 # restore a0 xsr a2, DEPC # restore a2, depc rsr a3, EXCSAVE_1 wsr a0, EXCSAVE_1 movi a0, unrecoverable_exception callx0 a0/* * sysxtensa syscall handler * * int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused); * int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused); * int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused); * int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval); * a2 a6 a3 a4 a5 * * Entry condition: * * a0: a2 (syscall-nr), original value saved on stack (PT_AREG0) * a1: a1 * a2: new stack pointer, original in a0 and DEPC * a3: dispatch table, original in excsave_1 * a4..a15: unchanged * 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 * * Note: we don't have to save a2; a2 holds the return value * * We use the two macros TRY and CATCH: * * TRY adds an entry to the __ex_table fixup table for the immediately * following instruction. * * CATCH catches any exception that occurred at one of the preceeding TRY * statements and continues from there * * Usage TRY l32i a0, a1, 0 * <other code> * done: rfe * CATCH <set return code> * j done */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -