?? entry.s
字號(hào):
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, a52: 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, WBBITS1: 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. * We avoided to do a MOVSP when we entered the exception, but we * have to do it here. */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 /* 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_SHIFT, 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_SHIFT 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_SHIFT, 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, PS_WOE_MASK | 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
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -