/*1* arch/xtensa/kernel/entry.S2*3* Low-level exception handling4*5* This file is subject to the terms and conditions of the GNU General Public6* License. See the file "COPYING" in the main directory of this archive7* for more details.8*9* Copyright (C) 2004-2007 by Tensilica Inc.10*11* Chris Zankel <[email protected]>12*13*/1415#include <linux/linkage.h>16#include <asm/asm-offsets.h>17#include <asm/processor.h>18#include <asm/coprocessor.h>19#include <asm/thread_info.h>20#include <asm/uaccess.h>21#include <asm/unistd.h>22#include <asm/ptrace.h>23#include <asm/current.h>24#include <asm/pgtable.h>25#include <asm/page.h>26#include <asm/signal.h>27#include <asm/tlbflush.h>28#include <variant/tie-asm.h>2930/* Unimplemented features. */3132#undef KERNEL_STACK_OVERFLOW_CHECK33#undef PREEMPTIBLE_KERNEL34#undef ALLOCA_EXCEPTION_IN_IRAM3536/* Not well tested.37*38* - fast_coprocessor39*/4041/*42* Macro to find first bit set in WINDOWBASE from the left + 143*44* 100....0 -> 145* 010....0 -> 246* 000....1 -> WSBITS47*/4849.macro ffs_ws bit mask5051#if XCHAL_HAVE_NSA52nsau \bit, \mask # 32-WSBITS ... 31 (32 iff 0)53addi \bit, \bit, WSBITS - 32 + 1 # uppest bit set -> return 154#else55movi \bit, WSBITS56#if WSBITS > 1657_bltui \mask, 0x10000, 99f58addi \bit, \bit, -1659extui \mask, \mask, 16, 1660#endif61#if WSBITS > 86299: _bltui \mask, 0x100, 99f63addi \bit, \bit, -864srli \mask, \mask, 865#endif6699: _bltui \mask, 0x10, 99f67addi \bit, \bit, -468srli \mask, \mask, 46999: _bltui \mask, 0x4, 99f70addi \bit, \bit, -271srli \mask, \mask, 27299: _bltui \mask, 0x2, 99f73addi \bit, \bit, -17499:7576#endif77.endm7879/* ----------------- DEFAULT FIRST LEVEL EXCEPTION HANDLERS ----------------- */8081/*82* First-level exception handler for user exceptions.83* Save some special registers, extra states and all registers in the AR84* register file that were in use in the user task, and jump to the common85* exception code.86* We save SAR (used to calculate WMASK), and WB and WS (we don't have to87* save them for kernel exceptions).88*89* Entry condition for user_exception:90*91* a0: trashed, original value saved on stack (PT_AREG0)92* a1: a193* a2: new stack pointer, original value in depc94* a3: dispatch table95* depc: a2, original value saved on stack (PT_DEPC)96* excsave1: a397*98* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC99* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception100*101* Entry condition for _user_exception:102*103* a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC104* excsave has been restored, and105* stack pointer (a1) has been set.106*107* Note: _user_exception might be at an odd address. Don't use call0..call12108*/109110ENTRY(user_exception)111112/* Save a2, a3, and depc, restore excsave_1 and set SP. */113114xsr a3, EXCSAVE_1115rsr a0, DEPC116s32i a1, a2, PT_AREG1117s32i a0, a2, PT_AREG2118s32i a3, a2, PT_AREG3119mov a1, a2120121.globl _user_exception122_user_exception:123124/* Save SAR and turn off single stepping */125126movi a2, 0127rsr a3, SAR128xsr a2, ICOUNTLEVEL129s32i a3, a1, PT_SAR130s32i a2, a1, PT_ICOUNTLEVEL131132/* Rotate ws so that the current windowbase is at bit0. */133/* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */134135rsr a2, WINDOWBASE136rsr a3, WINDOWSTART137ssr a2138s32i a2, a1, PT_WINDOWBASE139s32i a3, a1, PT_WINDOWSTART140slli a2, a3, 32-WSBITS141src a2, a3, a2142srli a2, a2, 32-WSBITS143s32i a2, a1, PT_WMASK # needed for restoring registers144145/* Save only live registers. */146147_bbsi.l a2, 1, 1f148s32i a4, a1, PT_AREG4149s32i a5, a1, PT_AREG5150s32i a6, a1, PT_AREG6151s32i a7, a1, PT_AREG7152_bbsi.l a2, 2, 1f153s32i a8, a1, PT_AREG8154s32i a9, a1, PT_AREG9155s32i a10, a1, PT_AREG10156s32i a11, a1, PT_AREG11157_bbsi.l a2, 3, 1f158s32i a12, a1, PT_AREG12159s32i a13, a1, PT_AREG13160s32i a14, a1, PT_AREG14161s32i a15, a1, PT_AREG15162_bnei a2, 1, 1f # only one valid frame?163164/* Only one valid frame, skip saving regs. */165166j 2f167168/* Save the remaining registers.169* We have to save all registers up to the first '1' from170* the right, except the current frame (bit 0).171* Assume a2 is: 001001000110001172* All register frames starting from the top field to the marked '1'173* must be saved.174*/1751761: addi a3, a2, -1 # eliminate '1' in bit 0: yyyyxxww0177neg a3, a3 # yyyyxxww0 -> YYYYXXWW1+1178and a3, a3, a2 # max. only one bit is set179180/* Find number of frames to save */181182ffs_ws a0, a3 # number of frames to the '1' from left183184/* Store information into WMASK:185* bits 0..3: xxx1 masked lower 4 bits of the rotated windowstart,186* bits 4...: number of valid 4-register frames187*/188189slli a3, a0, 4 # number of frames to save in bits 8..4190extui a2, a2, 0, 4 # mask for the first 16 registers191or a2, a3, a2192s32i a2, a1, PT_WMASK # needed when we restore the reg-file193194/* Save 4 registers at a time */1951961: rotw -1197s32i a0, a5, PT_AREG_END - 16198s32i a1, a5, PT_AREG_END - 12199s32i a2, a5, PT_AREG_END - 8200s32i a3, a5, PT_AREG_END - 4201addi a0, a4, -1202addi a1, a5, -16203_bnez a0, 1b204205/* WINDOWBASE still in SAR! */206207rsr a2, SAR # original WINDOWBASE208movi a3, 1209ssl a2210sll a3, a3211wsr a3, WINDOWSTART # set corresponding WINDOWSTART bit212wsr a2, WINDOWBASE # and WINDOWSTART213rsync214215/* We are back to the original stack pointer (a1) */2162172: /* Now, jump to the common exception handler. */218219j common_exception220221222/*223* First-level exit handler for kernel exceptions224* Save special registers and the live window frame.225* Note: Even though we changes the stack pointer, we don't have to do a226* MOVSP here, as we do that when we return from the exception.227* (See comment in the kernel exception exit code)228*229* Entry condition for kernel_exception:230*231* a0: trashed, original value saved on stack (PT_AREG0)232* a1: a1233* a2: new stack pointer, original in DEPC234* a3: dispatch table235* depc: a2, original value saved on stack (PT_DEPC)236* excsave_1: a3237*238* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC239* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception240*241* Entry condition for _kernel_exception:242*243* a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC244* excsave has been restored, and245* stack pointer (a1) has been set.246*247* Note: _kernel_exception might be at an odd address. Don't use call0..call12248*/249250ENTRY(kernel_exception)251252/* Save a0, a2, a3, DEPC and set SP. */253254xsr a3, EXCSAVE_1 # restore a3, excsave_1255rsr a0, DEPC # get a2256s32i a1, a2, PT_AREG1257s32i a0, a2, PT_AREG2258s32i a3, a2, PT_AREG3259mov a1, a2260261.globl _kernel_exception262_kernel_exception:263264/* Save SAR and turn off single stepping */265266movi a2, 0267rsr a3, SAR268xsr a2, ICOUNTLEVEL269s32i a3, a1, PT_SAR270s32i a2, a1, PT_ICOUNTLEVEL271272/* Rotate ws so that the current windowbase is at bit0. */273/* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */274275rsr a2, WINDOWBASE # don't need to save these, we only276rsr a3, WINDOWSTART # need shifted windowstart: windowmask277ssr a2278slli a2, a3, 32-WSBITS279src a2, a3, a2280srli a2, a2, 32-WSBITS281s32i a2, a1, PT_WMASK # needed for kernel_exception_exit282283/* Save only the live window-frame */284285_bbsi.l a2, 1, 1f286s32i a4, a1, PT_AREG4287s32i a5, a1, PT_AREG5288s32i a6, a1, PT_AREG6289s32i a7, a1, PT_AREG7290_bbsi.l a2, 2, 1f291s32i a8, a1, PT_AREG8292s32i a9, a1, PT_AREG9293s32i a10, a1, PT_AREG10294s32i a11, a1, PT_AREG11295_bbsi.l a2, 3, 1f296s32i a12, a1, PT_AREG12297s32i a13, a1, PT_AREG13298s32i a14, a1, PT_AREG14299s32i a15, a1, PT_AREG153003011:302303#ifdef KERNEL_STACK_OVERFLOW_CHECK304305/* Stack overflow check, for debugging */306extui a2, a1, TASK_SIZE_BITS,XX307movi a3, SIZE??308_bge a2, a3, out_of_stack_panic309310#endif311312/*313* This is the common exception handler.314* We get here from the user exception handler or simply by falling through315* from the kernel exception handler.316* Save the remaining special registers, switch to kernel mode, and jump317* to the second-level exception handler.318*319*/320321common_exception:322323/* Save some registers, disable loops and clear the syscall flag. */324325rsr a2, DEBUGCAUSE326rsr a3, EPC_1327s32i a2, a1, PT_DEBUGCAUSE328s32i a3, a1, PT_PC329330movi a2, -1331rsr a3, EXCVADDR332s32i a2, a1, PT_SYSCALL333movi a2, 0334s32i a3, a1, PT_EXCVADDR335xsr a2, LCOUNT336s32i a2, a1, PT_LCOUNT337338/* It is now save to restore the EXC_TABLE_FIXUP variable. */339340rsr a0, EXCCAUSE341movi a3, 0342rsr a2, EXCSAVE_1343s32i a0, a1, PT_EXCCAUSE344s32i a3, a2, EXC_TABLE_FIXUP345346/* All unrecoverable states are saved on stack, now, and a1 is valid,347* so we can allow exceptions and interrupts (*) again.348* Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)349*350* (*) We only allow interrupts if PS.INTLEVEL was not set to 1 before351* (interrupts disabled) and if this exception is not an interrupt.352*/353354rsr a3, PS355addi a0, a0, -4356movi a2, 1357extui a3, a3, 0, 1 # a3 = PS.INTLEVEL[0]358moveqz a3, a2, a0 # a3 = 1 iff interrupt exception359movi a2, 1 << PS_WOE_BIT360or a3, a3, a2361rsr a0, EXCCAUSE362xsr a3, PS363364s32i a3, a1, PT_PS # save ps365366/* Save LBEG, LEND */367368rsr a2, LBEG369rsr a3, LEND370s32i a2, a1, PT_LBEG371s32i a3, a1, PT_LEND372373/* Save optional registers. */374375save_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT376377/* Go to second-level dispatcher. Set up parameters to pass to the378* exception handler and call the exception handler.379*/380381movi a4, exc_table382mov a6, a1 # pass stack frame383mov a7, a0 # pass EXCCAUSE384addx4 a4, a0, a4385l32i a4, a4, EXC_TABLE_DEFAULT # load handler386387/* Call the second-level handler */388389callx4 a4390391/* Jump here for exception exit */392393common_exception_return:394395/* Jump if we are returning from kernel exceptions. */3963971: l32i a3, a1, PT_PS398_bbci.l a3, PS_UM_BIT, 4f399400/* Specific to a user exception exit:401* We need to check some flags for signal handling and rescheduling,402* and have to restore WB and WS, extra states, and all registers403* in the register file that were in use in the user task.404* Note that we don't disable interrupts here.405*/406407GET_THREAD_INFO(a2,a1)408l32i a4, a2, TI_FLAGS409410_bbsi.l a4, TIF_NEED_RESCHED, 3f411_bbci.l a4, TIF_SIGPENDING, 4f412413l32i a4, a1, PT_DEPC414bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f415416/* Call do_signal() */417418movi a4, do_signal # int do_signal(struct pt_regs*, sigset_t*)419mov a6, a1420movi a7, 0421callx4 a4422j 1b4234243: /* Reschedule */425426movi a4, schedule # void schedule (void)427callx4 a4428j 1b4294304: /* Restore optional registers. */431432load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT433434wsr a3, PS /* disable interrupts */435436_bbci.l a3, PS_UM_BIT, kernel_exception_exit437438user_exception_exit:439440/* Restore the state of the task and return from the exception. */441442/* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */443444l32i a2, a1, PT_WINDOWBASE445l32i a3, a1, PT_WINDOWSTART446wsr a1, DEPC # use DEPC as temp storage447wsr a3, WINDOWSTART # restore WINDOWSTART448ssr a2 # preserve user's WB in the SAR449wsr a2, WINDOWBASE # switch to user's saved WB450rsync451rsr a1, DEPC # restore stack pointer452l32i a2, a1, PT_WMASK # register frames saved (in bits 4...9)453rotw -1 # we restore a4..a7454_bltui a6, 16, 1f # only have to restore current window?455456/* The working registers are a0 and a3. We are restoring to457* a4..a7. Be careful not to destroy what we have just restored.458* Note: wmask has the format YYYYM:459* Y: number of registers saved in groups of 4460* M: 4 bit mask of first 16 registers461*/462463mov a2, a6464mov a3, a54654662: rotw -1 # a0..a3 become a4..a7467addi a3, a7, -4*4 # next iteration468addi a2, a6, -16 # decrementing Y in WMASK469l32i a4, a3, PT_AREG_END + 0470l32i a5, a3, PT_AREG_END + 4471l32i a6, a3, PT_AREG_END + 8472l32i a7, a3, PT_AREG_END + 12473_bgeui a2, 16, 2b474475/* Clear unrestored registers (don't leak anything to user-land */4764771: rsr a0, WINDOWBASE478rsr a3, SAR479sub a3, a0, a3480beqz a3, 2f481extui a3, a3, 0, WBBITS4824831: rotw -1484addi a3, a7, -1485movi a4, 0486movi a5, 0487movi a6, 0488movi a7, 0489bgei a3, 1, 1b490491/* We are back were we were when we started.492* Note: a2 still contains WMASK (if we've returned to the original493* frame where we had loaded a2), or at least the lower 4 bits494* (if we have restored WSBITS-1 frames).495*/4964972: j common_exception_exit498499/* This is the kernel exception exit.500* We avoided to do a MOVSP when we entered the exception, but we501* have to do it here.502*/503504kernel_exception_exit:505506#ifdef PREEMPTIBLE_KERNEL507508#ifdef CONFIG_PREEMPT509510/*511* Note: We've just returned from a call4, so we have512* at least 4 addt'l regs.513*/514515/* Check current_thread_info->preempt_count */516517GET_THREAD_INFO(a2)518l32i a3, a2, TI_PREEMPT519bnez a3, 1f520521l32i a2, a2, TI_FLAGS5225231:524525#endif526527#endif528529/* Check if we have to do a movsp.530*531* We only have to do a movsp if the previous window-frame has532* been spilled to the *temporary* exception stack instead of the533* task's stack. This is the case if the corresponding bit in534* WINDOWSTART for the previous window-frame was set before535* (not spilled) but is zero now (spilled).536* If this bit is zero, all other bits except the one for the537* current window frame are also zero. So, we can use a simple test:538* 'and' WINDOWSTART and WINDOWSTART-1:539*540* (XXXXXX1[0]* - 1) AND XXXXXX1[0]* = XXXXXX0[0]*541*542* The result is zero only if one bit was set.543*544* (Note: We might have gone through several task switches before545* we come back to the current task, so WINDOWBASE might be546* different from the time the exception occurred.)547*/548549/* Test WINDOWSTART before and after the exception.550* We actually have WMASK, so we only have to test if it is 1 or not.551*/552553l32i a2, a1, PT_WMASK554_beqi a2, 1, common_exception_exit # Spilled before exception,jump555556/* Test WINDOWSTART now. If spilled, do the movsp */557558rsr a3, WINDOWSTART559addi a0, a3, -1560and a3, a3, a0561_bnez a3, common_exception_exit562563/* Do a movsp (we returned from a call4, so we have at least a0..a7) */564565addi a0, a1, -16566l32i a3, a0, 0567l32i a4, a0, 4568s32i a3, a1, PT_SIZE+0569s32i a4, a1, PT_SIZE+4570l32i a3, a0, 8571l32i a4, a0, 12572s32i a3, a1, PT_SIZE+8573s32i a4, a1, PT_SIZE+12574575/* Common exception exit.576* We restore the special register and the current window frame, and577* return from the exception.578*579* Note: We expect a2 to hold PT_WMASK580*/581582common_exception_exit:583584/* Restore address registers. */585586_bbsi.l a2, 1, 1f587l32i a4, a1, PT_AREG4588l32i a5, a1, PT_AREG5589l32i a6, a1, PT_AREG6590l32i a7, a1, PT_AREG7591_bbsi.l a2, 2, 1f592l32i a8, a1, PT_AREG8593l32i a9, a1, PT_AREG9594l32i a10, a1, PT_AREG10595l32i a11, a1, PT_AREG11596_bbsi.l a2, 3, 1f597l32i a12, a1, PT_AREG12598l32i a13, a1, PT_AREG13599l32i a14, a1, PT_AREG14600l32i a15, a1, PT_AREG15601602/* Restore PC, SAR */6036041: l32i a2, a1, PT_PC605l32i a3, a1, PT_SAR606wsr a2, EPC_1607wsr a3, SAR608609/* Restore LBEG, LEND, LCOUNT */610611l32i a2, a1, PT_LBEG612l32i a3, a1, PT_LEND613wsr a2, LBEG614l32i a2, a1, PT_LCOUNT615wsr a3, LEND616wsr a2, LCOUNT617618/* We control single stepping through the ICOUNTLEVEL register. */619620l32i a2, a1, PT_ICOUNTLEVEL621movi a3, -2622wsr a2, ICOUNTLEVEL623wsr a3, ICOUNT624625/* Check if it was double exception. */626627l32i a0, a1, PT_DEPC628l32i a3, a1, PT_AREG3629l32i a2, a1, PT_AREG2630_bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f631632/* Restore a0...a3 and return */633634l32i a0, a1, PT_AREG0635l32i a1, a1, PT_AREG1636rfe6376381: wsr a0, DEPC639l32i a0, a1, PT_AREG0640l32i a1, a1, PT_AREG1641rfde642643/*644* Debug exception handler.645*646* Currently, we don't support KGDB, so only user application can be debugged.647*648* When we get here, a0 is trashed and saved to excsave[debuglevel]649*/650651ENTRY(debug_exception)652653rsr a0, EPS + XCHAL_DEBUGLEVEL654bbsi.l a0, PS_EXCM_BIT, 1f # exception mode655656/* Set EPC_1 and EXCCAUSE */657658wsr a2, DEPC # save a2 temporarily659rsr a2, EPC + XCHAL_DEBUGLEVEL660wsr a2, EPC_1661662movi a2, EXCCAUSE_MAPPED_DEBUG663wsr a2, EXCCAUSE664665/* Restore PS to the value before the debug exc but with PS.EXCM set.*/666667movi a2, 1 << PS_EXCM_BIT668or a2, a0, a2669movi a0, debug_exception # restore a3, debug jump vector670wsr a2, PS671xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL672673/* Switch to kernel/user stack, restore jump vector, and save a0 */674675bbsi.l a2, PS_UM_BIT, 2f # jump if user mode676677addi a2, a1, -16-PT_SIZE # assume kernel stack678s32i a0, a2, PT_AREG0679movi a0, 0680s32i a1, a2, PT_AREG1681s32i a0, a2, PT_DEPC # mark it as a regular exception682xsr a0, DEPC683s32i a3, a2, PT_AREG3684s32i a0, a2, PT_AREG2685mov a1, a2686j _kernel_exception6876882: rsr a2, EXCSAVE_1689l32i a2, a2, EXC_TABLE_KSTK # load kernel stack pointer690s32i a0, a2, PT_AREG0691movi a0, 0692s32i a1, a2, PT_AREG1693s32i a0, a2, PT_DEPC694xsr a0, DEPC695s32i a3, a2, PT_AREG3696s32i a0, a2, PT_AREG2697mov a1, a2698j _user_exception699700/* Debug exception while in exception mode. */7011: j 1b // FIXME!!702703704/*705* We get here in case of an unrecoverable exception.706* The only thing we can do is to be nice and print a panic message.707* We only produce a single stack frame for panic, so ???708*709*710* Entry conditions:711*712* - a0 contains the caller address; original value saved in excsave1.713* - the original a0 contains a valid return address (backtrace) or 0.714* - a2 contains a valid stackpointer715*716* Notes:717*718* - If the stack pointer could be invalid, the caller has to setup a719* dummy stack pointer (e.g. the stack of the init_task)720*721* - If the return address could be invalid, the caller has to set it722* to 0, so the backtrace would stop.723*724*/725.align 4726unrecoverable_text:727.ascii "Unrecoverable error in exception handler\0"728729ENTRY(unrecoverable_exception)730731movi a0, 1732movi a1, 0733734wsr a0, WINDOWSTART735wsr a1, WINDOWBASE736rsync737738movi a1, (1 << PS_WOE_BIT) | 1739wsr a1, PS740rsync741742movi a1, init_task743movi a0, 0744addi a1, a1, PT_REGS_OFFSET745746movi a4, panic747movi a6, unrecoverable_text748749callx4 a47507511: j 1b752753754/* -------------------------- FAST EXCEPTION HANDLERS ----------------------- */755756/*757* Fast-handler for alloca exceptions758*759* The ALLOCA handler is entered when user code executes the MOVSP760* instruction and the caller's frame is not in the register file.761* In this case, the caller frame's a0..a3 are on the stack just762* below sp (a1), and this handler moves them.763*764* For "MOVSP <ar>,<as>" without destination register a1, this routine765* simply moves the value from <as> to <ar> without moving the save area.766*767* Entry condition:768*769* a0: trashed, original value saved on stack (PT_AREG0)770* a1: a1771* a2: new stack pointer, original in DEPC772* a3: dispatch table773* depc: a2, original value saved on stack (PT_DEPC)774* excsave_1: a3775*776* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC777* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception778*/779780#if XCHAL_HAVE_BE781#define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 4, 4782#define _EXTUI_MOVSP_DST(ar) extui ar, ar, 0, 4783#else784#define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 0, 4785#define _EXTUI_MOVSP_DST(ar) extui ar, ar, 4, 4786#endif787788ENTRY(fast_alloca)789790/* We shouldn't be in a double exception. */791792l32i a0, a2, PT_DEPC793_bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, .Lunhandled_double794795rsr a0, DEPC # get a2796s32i a4, a2, PT_AREG4 # save a4 and797s32i a0, a2, PT_AREG2 # a2 to stack798799/* Exit critical section. */800801movi a0, 0802s32i a0, a3, EXC_TABLE_FIXUP803804/* Restore a3, excsave_1 */805806xsr a3, EXCSAVE_1 # make sure excsave_1 is valid for dbl.807rsr a4, EPC_1 # get exception address808s32i a3, a2, PT_AREG3 # save a3 to stack809810#ifdef ALLOCA_EXCEPTION_IN_IRAM811#error iram not supported812#else813/* Note: l8ui not allowed in IRAM/IROM!! */814l8ui a0, a4, 1 # read as(src) from MOVSP instruction815#endif816movi a3, .Lmovsp_src817_EXTUI_MOVSP_SRC(a0) # extract source register number818addx8 a3, a0, a3819jx a3820821.Lunhandled_double:822wsr a0, EXCSAVE_1823movi a0, unrecoverable_exception824callx0 a0825826.align 8827.Lmovsp_src:828l32i a3, a2, PT_AREG0; _j 1f; .align 8829mov a3, a1; _j 1f; .align 8830l32i a3, a2, PT_AREG2; _j 1f; .align 8831l32i a3, a2, PT_AREG3; _j 1f; .align 8832l32i a3, a2, PT_AREG4; _j 1f; .align 8833mov a3, a5; _j 1f; .align 8834mov a3, a6; _j 1f; .align 8835mov a3, a7; _j 1f; .align 8836mov a3, a8; _j 1f; .align 8837mov a3, a9; _j 1f; .align 8838mov a3, a10; _j 1f; .align 8839mov a3, a11; _j 1f; .align 8840mov a3, a12; _j 1f; .align 8841mov a3, a13; _j 1f; .align 8842mov a3, a14; _j 1f; .align 8843mov a3, a15; _j 1f; .align 88448451:846847#ifdef ALLOCA_EXCEPTION_IN_IRAM848#error iram not supported849#else850l8ui a0, a4, 0 # read ar(dst) from MOVSP instruction851#endif852addi a4, a4, 3 # step over movsp853_EXTUI_MOVSP_DST(a0) # extract destination register854wsr a4, EPC_1 # save new epc_1855856_bnei a0, 1, 1f # no 'movsp a1, ax': jump857858/* Move the save area. This implies the use of the L32E859* and S32E instructions, because this move must be done with860* the user's PS.RING privilege levels, not with ring 0861* (kernel's) privileges currently active with PS.EXCM862* set. Note that we have stil registered a fixup routine with the863* double exception vector in case a double exception occurs.864*/865866/* a0,a4:avail a1:old user stack a2:exc. stack a3:new user stack. */867868l32e a0, a1, -16869l32e a4, a1, -12870s32e a0, a3, -16871s32e a4, a3, -12872l32e a0, a1, -8873l32e a4, a1, -4874s32e a0, a3, -8875s32e a4, a3, -4876877/* Restore stack-pointer and all the other saved registers. */878879mov a1, a3880881l32i a4, a2, PT_AREG4882l32i a3, a2, PT_AREG3883l32i a0, a2, PT_AREG0884l32i a2, a2, PT_AREG2885rfe886887/* MOVSP <at>,<as> was invoked with <at> != a1.888* Because the stack pointer is not being modified,889* we should be able to just modify the pointer890* without moving any save area.891* The processor only traps these occurrences if the892* caller window isn't live, so unfortunately we can't893* use this as an alternate trap mechanism.894* So we just do the move. This requires that we895* resolve the destination register, not just the source,896* so there's some extra work.897* (PERHAPS NOT REALLY NEEDED, BUT CLEANER...)898*/899900/* a0 dst-reg, a1 user-stack, a2 stack, a3 value of src reg. */9019021: movi a4, .Lmovsp_dst903addx8 a4, a0, a4904jx a4905906.align 8907.Lmovsp_dst:908s32i a3, a2, PT_AREG0; _j 1f; .align 8909mov a1, a3; _j 1f; .align 8910s32i a3, a2, PT_AREG2; _j 1f; .align 8911s32i a3, a2, PT_AREG3; _j 1f; .align 8912s32i a3, a2, PT_AREG4; _j 1f; .align 8913mov a5, a3; _j 1f; .align 8914mov a6, a3; _j 1f; .align 8915mov a7, a3; _j 1f; .align 8916mov a8, a3; _j 1f; .align 8917mov a9, a3; _j 1f; .align 8918mov a10, a3; _j 1f; .align 8919mov a11, a3; _j 1f; .align 8920mov a12, a3; _j 1f; .align 8921mov a13, a3; _j 1f; .align 8922mov a14, a3; _j 1f; .align 8923mov a15, a3; _j 1f; .align 89249251: l32i a4, a2, PT_AREG4926l32i a3, a2, PT_AREG3927l32i a0, a2, PT_AREG0928l32i a2, a2, PT_AREG2929rfe930931932/*933* fast system calls.934*935* WARNING: The kernel doesn't save the entire user context before936* handling a fast system call. These functions are small and short,937* usually offering some functionality not available to user tasks.938*939* BE CAREFUL TO PRESERVE THE USER'S CONTEXT.940*941* Entry condition:942*943* a0: trashed, original value saved on stack (PT_AREG0)944* a1: a1945* a2: new stack pointer, original in DEPC946* a3: dispatch table947* depc: a2, original value saved on stack (PT_DEPC)948* excsave_1: a3949*/950951ENTRY(fast_syscall_kernel)952953/* Skip syscall. */954955rsr a0, EPC_1956addi a0, a0, 3957wsr a0, EPC_1958959l32i a0, a2, PT_DEPC960bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable961962rsr a0, DEPC # get syscall-nr963_beqz a0, fast_syscall_spill_registers964_beqi a0, __NR_xtensa, fast_syscall_xtensa965966j kernel_exception967968ENTRY(fast_syscall_user)969970/* Skip syscall. */971972rsr a0, EPC_1973addi a0, a0, 3974wsr a0, EPC_1975976l32i a0, a2, PT_DEPC977bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable978979rsr a0, DEPC # get syscall-nr980_beqz a0, fast_syscall_spill_registers981_beqi a0, __NR_xtensa, fast_syscall_xtensa982983j user_exception984985ENTRY(fast_syscall_unrecoverable)986987/* Restore all states. */988989l32i a0, a2, PT_AREG0 # restore a0990xsr a2, DEPC # restore a2, depc991rsr a3, EXCSAVE_1992993wsr a0, EXCSAVE_1994movi a0, unrecoverable_exception995callx0 a0996997998999/*1000* sysxtensa syscall handler1001*1002* int sysxtensa (SYS_XTENSA_ATOMIC_SET, ptr, val, unused);1003* int sysxtensa (SYS_XTENSA_ATOMIC_ADD, ptr, val, unused);1004* int sysxtensa (SYS_XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);1005* int sysxtensa (SYS_XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);1006* a2 a6 a3 a4 a51007*1008* Entry condition:1009*1010* a0: a2 (syscall-nr), original value saved on stack (PT_AREG0)1011* a1: a11012* a2: new stack pointer, original in a0 and DEPC1013* a3: dispatch table, original in excsave_11014* a4..a15: unchanged1015* depc: a2, original value saved on stack (PT_DEPC)1016* excsave_1: a31017*1018* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC1019* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception1020*1021* Note: we don't have to save a2; a2 holds the return value1022*1023* We use the two macros TRY and CATCH:1024*1025* TRY adds an entry to the __ex_table fixup table for the immediately1026* following instruction.1027*1028* CATCH catches any exception that occurred at one of the preceding TRY1029* statements and continues from there1030*1031* Usage TRY l32i a0, a1, 01032* <other code>1033* done: rfe1034* CATCH <set return code>1035* j done1036*/10371038#define TRY \1039.section __ex_table, "a"; \1040.word 66f, 67f; \1041.text; \104266:10431044#define CATCH \104567:10461047ENTRY(fast_syscall_xtensa)10481049xsr a3, EXCSAVE_1 # restore a3, excsave110501051s32i a7, a2, PT_AREG7 # we need an additional register1052movi a7, 4 # sizeof(unsigned int)1053access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp10541055addi a6, a6, -1 # assuming SYS_XTENSA_ATOMIC_SET = 11056_bgeui a6, SYS_XTENSA_COUNT - 1, .Lill1057_bnei a6, SYS_XTENSA_ATOMIC_CMP_SWP - 1, .Lnswp10581059/* Fall through for ATOMIC_CMP_SWP. */10601061.Lswp: /* Atomic compare and swap */10621063TRY l32i a0, a3, 0 # read old value1064bne a0, a4, 1f # same as old value? jump1065TRY s32i a5, a3, 0 # different, modify value1066l32i a7, a2, PT_AREG7 # restore a71067l32i a0, a2, PT_AREG0 # restore a01068movi a2, 1 # and return 11069addi a6, a6, 1 # restore a6 (really necessary?)1070rfe107110721: l32i a7, a2, PT_AREG7 # restore a71073l32i a0, a2, PT_AREG0 # restore a01074movi a2, 0 # return 0 (note that we cannot set1075addi a6, a6, 1 # restore a6 (really necessary?)1076rfe10771078.Lnswp: /* Atomic set, add, and exg_add. */10791080TRY l32i a7, a3, 0 # orig1081add a0, a4, a7 # + arg1082moveqz a0, a4, a6 # set1083TRY s32i a0, a3, 0 # write new value10841085mov a0, a21086mov a2, a71087l32i a7, a0, PT_AREG7 # restore a71088l32i a0, a0, PT_AREG0 # restore a01089addi a6, a6, 1 # restore a6 (really necessary?)1090rfe10911092CATCH1093.Leac: l32i a7, a2, PT_AREG7 # restore a71094l32i a0, a2, PT_AREG0 # restore a01095movi a2, -EFAULT1096rfe10971098.Lill: l32i a7, a2, PT_AREG0 # restore a71099l32i a0, a2, PT_AREG0 # restore a01100movi a2, -EINVAL1101rfe11021103110411051106/* fast_syscall_spill_registers.1107*1108* Entry condition:1109*1110* a0: trashed, original value saved on stack (PT_AREG0)1111* a1: a11112* a2: new stack pointer, original in DEPC1113* a3: dispatch table1114* depc: a2, original value saved on stack (PT_DEPC)1115* excsave_1: a31116*1117* Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.1118*/11191120ENTRY(fast_syscall_spill_registers)11211122/* Register a FIXUP handler (pass current wb as a parameter) */11231124movi a0, fast_syscall_spill_registers_fixup1125s32i a0, a3, EXC_TABLE_FIXUP1126rsr a0, WINDOWBASE1127s32i a0, a3, EXC_TABLE_PARAM11281129/* Save a3 and SAR on stack. */11301131rsr a0, SAR1132xsr a3, EXCSAVE_1 # restore a3 and excsave_11133s32i a3, a2, PT_AREG31134s32i a4, a2, PT_AREG41135s32i a0, a2, PT_AREG5 # store SAR to PT_AREG511361137/* The spill routine might clobber a7, a11, and a15. */11381139s32i a7, a2, PT_AREG71140s32i a11, a2, PT_AREG111141s32i a15, a2, PT_AREG1511421143call0 _spill_registers # destroys a3, a4, and SAR11441145/* Advance PC, restore registers and SAR, and return from exception. */11461147l32i a3, a2, PT_AREG51148l32i a4, a2, PT_AREG41149l32i a0, a2, PT_AREG01150wsr a3, SAR1151l32i a3, a2, PT_AREG311521153/* Restore clobbered registers. */11541155l32i a7, a2, PT_AREG71156l32i a11, a2, PT_AREG111157l32i a15, a2, PT_AREG1511581159movi a2, 01160rfe11611162/* Fixup handler.1163*1164* We get here if the spill routine causes an exception, e.g. tlb miss.1165* We basically restore WINDOWBASE and WINDOWSTART to the condition when1166* we entered the spill routine and jump to the user exception handler.1167*1168* a0: value of depc, original value in depc1169* a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE1170* a3: exctable, original value in excsave11171*/11721173fast_syscall_spill_registers_fixup:11741175rsr a2, WINDOWBASE # get current windowbase (a2 is saved)1176xsr a0, DEPC # restore depc and a01177ssl a2 # set shift (32 - WB)11781179/* We need to make sure the current registers (a0-a3) are preserved.1180* To do this, we simply set the bit for the current window frame1181* in WS, so that the exception handlers save them to the task stack.1182*/11831184rsr a3, EXCSAVE_1 # get spill-mask1185slli a2, a3, 1 # shift left by one11861187slli a3, a2, 32-WSBITS1188src a2, a2, a3 # a1 = xxwww1yyxxxwww1yy......1189wsr a2, WINDOWSTART # set corrected windowstart11901191movi a3, exc_table1192l32i a2, a3, EXC_TABLE_DOUBLE_SAVE # restore a21193l32i a3, a3, EXC_TABLE_PARAM # original WB (in user task)11941195/* Return to the original (user task) WINDOWBASE.1196* We leave the following frame behind:1197* a0, a1, a2 same1198* a3: trashed (saved in excsave_1)1199* depc: depc (we have to return to that address)1200* excsave_1: a31201*/12021203wsr a3, WINDOWBASE1204rsync12051206/* We are now in the original frame when we entered _spill_registers:1207* a0: return address1208* a1: used, stack pointer1209* a2: kernel stack pointer1210* a3: available, saved in EXCSAVE_11211* depc: exception address1212* excsave: a31213* Note: This frame might be the same as above.1214*/12151216/* Setup stack pointer. */12171218addi a2, a2, -PT_USER_SIZE1219s32i a0, a2, PT_AREG012201221/* Make sure we return to this fixup handler. */12221223movi a3, fast_syscall_spill_registers_fixup_return1224s32i a3, a2, PT_DEPC # setup depc12251226/* Jump to the exception handler. */12271228movi a3, exc_table1229rsr a0, EXCCAUSE1230addx4 a0, a0, a3 # find entry in table1231l32i a0, a0, EXC_TABLE_FAST_USER # load handler1232jx a012331234fast_syscall_spill_registers_fixup_return:12351236/* When we return here, all registers have been restored (a2: DEPC) */12371238wsr a2, DEPC # exception address12391240/* Restore fixup handler. */12411242xsr a3, EXCSAVE_11243movi a2, fast_syscall_spill_registers_fixup1244s32i a2, a3, EXC_TABLE_FIXUP1245rsr a2, WINDOWBASE1246s32i a2, a3, EXC_TABLE_PARAM1247l32i a2, a3, EXC_TABLE_KSTK12481249/* Load WB at the time the exception occurred. */12501251rsr a3, SAR # WB is still in SAR1252neg a3, a31253wsr a3, WINDOWBASE1254rsync12551256/* Restore a3 and return. */12571258movi a3, exc_table1259xsr a3, EXCSAVE_112601261rfde126212631264/*1265* spill all registers.1266*1267* This is not a real function. The following conditions must be met:1268*1269* - must be called with call0.1270* - uses a3, a4 and SAR.1271* - the last 'valid' register of each frame are clobbered.1272* - the caller must have registered a fixup handler1273* (or be inside a critical section)1274* - PS_EXCM must be set (PS_WOE cleared?)1275*/12761277ENTRY(_spill_registers)12781279/*1280* Rotate ws so that the current windowbase is at bit 0.1281* Assume ws = xxxwww1yy (www1 current window frame).1282* Rotate ws right so that a4 = yyxxxwww1.1283*/12841285rsr a4, WINDOWBASE1286rsr a3, WINDOWSTART # a3 = xxxwww1yy1287ssr a4 # holds WB1288slli a4, a3, WSBITS1289or a3, a3, a4 # a3 = xxxwww1yyxxxwww1yy1290srl a3, a3 # a3 = 00xxxwww1yyxxxwww112911292/* We are done if there are no more than the current register frame. */12931294extui a3, a3, 1, WSBITS-1 # a3 = 0yyxxxwww1295movi a4, (1 << (WSBITS-1))1296_beqz a3, .Lnospill # only one active frame? jump12971298/* We want 1 at the top, so that we return to the current windowbase */12991300or a3, a3, a4 # 1yyxxxwww13011302/* Skip empty frames - get 'oldest' WINDOWSTART-bit. */13031304wsr a3, WINDOWSTART # save shifted windowstart1305neg a4, a31306and a3, a4, a3 # first bit set from right: 00001000013071308ffs_ws a4, a3 # a4: shifts to skip empty frames1309movi a3, WSBITS1310sub a4, a3, a4 # WSBITS-a4:number of 0-bits from right1311ssr a4 # save in SAR for later.13121313rsr a3, WINDOWBASE1314add a3, a3, a41315wsr a3, WINDOWBASE1316rsync13171318rsr a3, WINDOWSTART1319srl a3, a3 # shift windowstart13201321/* WB is now just one frame below the oldest frame in the register1322window. WS is shifted so the oldest frame is in bit 0, thus, WB1323and WS differ by one 4-register frame. */13241325/* Save frames. Depending what call was used (call4, call8, call12),1326* we have to save 4,8. or 12 registers.1327*/13281329_bbsi.l a3, 1, .Lc41330_bbsi.l a3, 2, .Lc813311332/* Special case: we have a call12-frame starting at a4. */13331334_bbci.l a3, 3, .Lc12 # bit 3 shouldn't be zero! (Jump to Lc12 first)13351336s32e a4, a1, -16 # a1 is valid with an empty spill area1337l32e a4, a5, -121338s32e a8, a4, -481339mov a8, a41340l32e a4, a1, -161341j .Lc12c13421343.Lnospill:1344ret13451346.Lloop: _bbsi.l a3, 1, .Lc41347_bbci.l a3, 2, .Lc1213481349.Lc8: s32e a4, a13, -161350l32e a4, a5, -121351s32e a8, a4, -321352s32e a5, a13, -121353s32e a6, a13, -81354s32e a7, a13, -41355s32e a9, a4, -281356s32e a10, a4, -241357s32e a11, a4, -2013581359srli a11, a3, 2 # shift windowbase by 21360rotw 21361_bnei a3, 1, .Lloop13621363.Lexit: /* Done. Do the final rotation, set WS, and return. */13641365rotw 11366rsr a3, WINDOWBASE1367ssl a31368movi a3, 11369sll a3, a31370wsr a3, WINDOWSTART1371ret13721373.Lc4: s32e a4, a9, -161374s32e a5, a9, -121375s32e a6, a9, -81376s32e a7, a9, -413771378srli a7, a3, 11379rotw 11380_bnei a3, 1, .Lloop1381j .Lexit13821383.Lc12: _bbci.l a3, 3, .Linvalid_mask # bit 2 shouldn't be zero!13841385/* 12-register frame (call12) */13861387l32e a2, a5, -121388s32e a8, a2, -481389mov a8, a213901391.Lc12c: s32e a9, a8, -441392s32e a10, a8, -401393s32e a11, a8, -361394s32e a12, a8, -321395s32e a13, a8, -281396s32e a14, a8, -241397s32e a15, a8, -201398srli a15, a3, 313991400/* The stack pointer for a4..a7 is out of reach, so we rotate the1401* window, grab the stackpointer, and rotate back.1402* Alternatively, we could also use the following approach, but that1403* makes the fixup routine much more complicated:1404* rotw 11405* s32e a0, a13, -161406* ...1407* rotw 21408*/14091410rotw 11411mov a5, a131412rotw -114131414s32e a4, a9, -161415s32e a5, a9, -121416s32e a6, a9, -81417s32e a7, a9, -414181419rotw 314201421_beqi a3, 1, .Lexit1422j .Lloop14231424.Linvalid_mask:14251426/* We get here because of an unrecoverable error in the window1427* registers. If we are in user space, we kill the application,1428* however, this condition is unrecoverable in kernel space.1429*/14301431rsr a0, PS1432_bbci.l a0, PS_UM_BIT, 1f14331434/* User space: Setup a dummy frame and kill application.1435* Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.1436*/14371438movi a0, 11439movi a1, 014401441wsr a0, WINDOWSTART1442wsr a1, WINDOWBASE1443rsync14441445movi a0, 014461447movi a3, exc_table1448l32i a1, a3, EXC_TABLE_KSTK1449wsr a3, EXCSAVE_114501451movi a4, (1 << PS_WOE_BIT) | 11452wsr a4, PS1453rsync14541455movi a6, SIGSEGV1456movi a4, do_exit1457callx4 a4145814591: /* Kernel space: PANIC! */14601461wsr a0, EXCSAVE_11462movi a0, unrecoverable_exception1463callx0 a0 # should not return14641: j 1b14651466#ifdef CONFIG_MMU1467/*1468* We should never get here. Bail out!1469*/14701471ENTRY(fast_second_level_miss_double_kernel)147214731: movi a0, unrecoverable_exception1474callx0 a0 # should not return14751: j 1b14761477/* First-level entry handler for user, kernel, and double 2nd-level1478* TLB miss exceptions. Note that for now, user and kernel miss1479* exceptions share the same entry point and are handled identically.1480*1481* An old, less-efficient C version of this function used to exist.1482* We include it below, interleaved as comments, for reference.1483*1484* Entry condition:1485*1486* a0: trashed, original value saved on stack (PT_AREG0)1487* a1: a11488* a2: new stack pointer, original in DEPC1489* a3: dispatch table1490* depc: a2, original value saved on stack (PT_DEPC)1491* excsave_1: a31492*1493* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC1494* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception1495*/14961497ENTRY(fast_second_level_miss)14981499/* Save a1. Note: we don't expect a double exception. */15001501s32i a1, a2, PT_AREG115021503/* We need to map the page of PTEs for the user task. Find1504* the pointer to that page. Also, it's possible for tsk->mm1505* to be NULL while tsk->active_mm is nonzero if we faulted on1506* a vmalloc address. In that rare case, we must use1507* active_mm instead to avoid a fault in this handler. See1508*1509* http://mail.nl.linux.org/linux-mm/2002-08/msg00258.html1510* (or search Internet on "mm vs. active_mm")1511*1512* if (!mm)1513* mm = tsk->active_mm;1514* pgd = pgd_offset (mm, regs->excvaddr);1515* pmd = pmd_offset (pgd, regs->excvaddr);1516* pmdval = *pmd;1517*/15181519GET_CURRENT(a1,a2)1520l32i a0, a1, TASK_MM # tsk->mm1521beqz a0, 9f152215231524/* We deliberately destroy a3 that holds the exception table. */152515268: rsr a3, EXCVADDR # fault address1527_PGD_OFFSET(a0, a3, a1)1528l32i a0, a0, 0 # read pmdval1529beqz a0, 2f15301531/* Read ptevaddr and convert to top of page-table page.1532*1533* vpnval = read_ptevaddr_register() & PAGE_MASK;1534* vpnval += DTLB_WAY_PGTABLE;1535* pteval = mk_pte (virt_to_page(pmd_val(pmdval)), PAGE_KERNEL);1536* write_dtlb_entry (pteval, vpnval);1537*1538* The messy computation for 'pteval' above really simplifies1539* into the following:1540*1541* pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY1542*/15431544movi a1, -PAGE_OFFSET1545add a0, a0, a1 # pmdval - PAGE_OFFSET1546extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK1547xor a0, a0, a115481549movi a1, _PAGE_DIRECTORY1550or a0, a0, a1 # ... | PAGE_DIRECTORY15511552/*1553* We utilize all three wired-ways (7-9) to hold pmd translations.1554* Memory regions are mapped to the DTLBs according to bits 28 and 29.1555* This allows to map the three most common regions to three different1556* DTLBs:1557* 0,1 -> way 7 program (0040.0000) and virtual (c000.0000)1558* 2 -> way 8 shared libaries (2000.0000)1559* 3 -> way 0 stack (3000.0000)1560*/15611562extui a3, a3, 28, 2 # addr. bit 28 and 29 0,1,2,31563rsr a1, PTEVADDR1564addx2 a3, a3, a3 # -> 0,3,6,91565srli a1, a1, PAGE_SHIFT1566extui a3, a3, 2, 2 # -> 0,0,1,21567slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK1568addi a3, a3, DTLB_WAY_PGD1569add a1, a1, a3 # ... + way_number157015713: wdtlb a0, a11572dsync15731574/* Exit critical section. */157515764: movi a3, exc_table # restore a31577movi a0, 01578s32i a0, a3, EXC_TABLE_FIXUP15791580/* Restore the working registers, and return. */15811582l32i a0, a2, PT_AREG01583l32i a1, a2, PT_AREG11584l32i a2, a2, PT_DEPC1585xsr a3, EXCSAVE_115861587bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f15881589/* Restore excsave1 and return. */15901591rsr a2, DEPC1592rfe15931594/* Return from double exception. */159515961: xsr a2, DEPC1597esync1598rfde159916009: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 01601j 8b16021603#if (DCACHE_WAY_SIZE > PAGE_SIZE)160416052: /* Special case for cache aliasing.1606* We (should) only get here if a clear_user_page, copy_user_page1607* or the aliased cache flush functions got preemptively interrupted1608* by another task. Re-establish temporary mapping to the1609* TLBTEMP_BASE areas.1610*/16111612/* We shouldn't be in a double exception */16131614l32i a0, a2, PT_DEPC1615bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 2f16161617/* Make sure the exception originated in the special functions */16181619movi a0, __tlbtemp_mapping_start1620rsr a3, EPC_11621bltu a3, a0, 2f1622movi a0, __tlbtemp_mapping_end1623bgeu a3, a0, 2f16241625/* Check if excvaddr was in one of the TLBTEMP_BASE areas. */16261627movi a3, TLBTEMP_BASE_11628rsr a0, EXCVADDR1629bltu a0, a3, 2f16301631addi a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT))1632bgeu a1, a3, 2f16331634/* Check if we have to restore an ITLB mapping. */16351636movi a1, __tlbtemp_mapping_itlb1637rsr a3, EPC_11638sub a3, a3, a116391640/* Calculate VPN */16411642movi a1, PAGE_MASK1643and a1, a1, a016441645/* Jump for ITLB entry */16461647bgez a3, 1f16481649/* We can use up to two TLBTEMP areas, one for src and one for dst. */16501651extui a3, a0, PAGE_SHIFT + DCACHE_ALIAS_ORDER, 11652add a1, a3, a116531654/* PPN is in a6 for the first TLBTEMP area and in a7 for the second. */16551656mov a0, a61657movnez a0, a7, a31658j 3b16591660/* ITLB entry. We only use dst in a6. */166116621: witlb a6, a11663isync1664j 4b166516661667#endif // DCACHE_WAY_SIZE > PAGE_SIZE1668166916702: /* Invalid PGD, default exception handling */16711672movi a3, exc_table1673rsr a1, DEPC1674xsr a3, EXCSAVE_11675s32i a1, a2, PT_AREG21676s32i a3, a2, PT_AREG31677mov a1, a216781679rsr a2, PS1680bbsi.l a2, PS_UM_BIT, 1f1681j _kernel_exception16821: j _user_exception168316841685/*1686* StoreProhibitedException1687*1688* Update the pte and invalidate the itlb mapping for this pte.1689*1690* Entry condition:1691*1692* a0: trashed, original value saved on stack (PT_AREG0)1693* a1: a11694* a2: new stack pointer, original in DEPC1695* a3: dispatch table1696* depc: a2, original value saved on stack (PT_DEPC)1697* excsave_1: a31698*1699* PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC1700* < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception1701*/17021703ENTRY(fast_store_prohibited)17041705/* Save a1 and a4. */17061707s32i a1, a2, PT_AREG11708s32i a4, a2, PT_AREG417091710GET_CURRENT(a1,a2)1711l32i a0, a1, TASK_MM # tsk->mm1712beqz a0, 9f171317148: rsr a1, EXCVADDR # fault address1715_PGD_OFFSET(a0, a1, a4)1716l32i a0, a0, 01717beqz a0, 2f17181719/* Note that we assume _PAGE_WRITABLE_BIT is only set if pte is valid.*/17201721_PTE_OFFSET(a0, a1, a4)1722l32i a4, a0, 0 # read pteval1723bbci.l a4, _PAGE_WRITABLE_BIT, 2f17241725movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE1726or a4, a4, a11727rsr a1, EXCVADDR1728s32i a4, a0, 017291730/* We need to flush the cache if we have page coloring. */1731#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK1732dhwb a0, 01733#endif1734pdtlb a0, a11735wdtlb a4, a017361737/* Exit critical section. */17381739movi a0, 01740s32i a0, a3, EXC_TABLE_FIXUP17411742/* Restore the working registers, and return. */17431744l32i a4, a2, PT_AREG41745l32i a1, a2, PT_AREG11746l32i a0, a2, PT_AREG01747l32i a2, a2, PT_DEPC17481749/* Restore excsave1 and a3. */17501751xsr a3, EXCSAVE_11752bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f17531754rsr a2, DEPC1755rfe17561757/* Double exception. Restore FIXUP handler and return. */175817591: xsr a2, DEPC1760esync1761rfde176217639: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 01764j 8b176517662: /* If there was a problem, handle fault in C */17671768rsr a4, DEPC # still holds a21769xsr a3, EXCSAVE_11770s32i a4, a2, PT_AREG21771s32i a3, a2, PT_AREG31772l32i a4, a2, PT_AREG41773mov a1, a217741775rsr a2, PS1776bbsi.l a2, PS_UM_BIT, 1f1777j _kernel_exception17781: j _user_exception1779#endif /* CONFIG_MMU */17801781/*1782* System Calls.1783*1784* void system_call (struct pt_regs* regs, int exccause)1785* a2 a31786*/17871788ENTRY(system_call)1789entry a1, 3217901791/* regs->syscall = regs->areg[2] */17921793l32i a3, a2, PT_AREG21794mov a6, a21795movi a4, do_syscall_trace_enter1796s32i a3, a2, PT_SYSCALL1797callx4 a417981799/* syscall = sys_call_table[syscall_nr] */18001801movi a4, sys_call_table;1802movi a5, __NR_syscall_count1803movi a6, -ENOSYS1804bgeu a3, a5, 1f18051806addx4 a4, a3, a41807l32i a4, a4, 01808movi a5, sys_ni_syscall;1809beq a4, a5, 1f18101811/* Load args: arg0 - arg5 are passed via regs. */18121813l32i a6, a2, PT_AREG61814l32i a7, a2, PT_AREG31815l32i a8, a2, PT_AREG41816l32i a9, a2, PT_AREG51817l32i a10, a2, PT_AREG81818l32i a11, a2, PT_AREG918191820/* Pass one additional argument to the syscall: pt_regs (on stack) */1821s32i a2, a1, 018221823callx4 a4182418251: /* regs->areg[2] = return_value */18261827s32i a6, a2, PT_AREG21828movi a4, do_syscall_trace_leave1829mov a6, a21830callx4 a41831retw183218331834/*1835* Create a kernel thread1836*1837* int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)1838* a2 a2 a3 a41839*/18401841ENTRY(kernel_thread)1842entry a1, 1618431844mov a5, a2 # preserve fn over syscall1845mov a7, a3 # preserve args over syscall18461847movi a3, _CLONE_VM | _CLONE_UNTRACED1848movi a2, __NR_clone1849or a6, a4, a3 # arg0: flags1850mov a3, a1 # arg1: sp1851syscall18521853beq a3, a1, 1f # branch if parent1854mov a6, a7 # args1855callx4 a5 # fn(args)18561857movi a2, __NR_exit1858syscall # return value of fn(args) still in a6185918601: retw18611862/*1863* Do a system call from kernel instead of calling sys_execve, so we end up1864* with proper pt_regs.1865*1866* int kernel_execve(const char *fname, char *const argv[], charg *const envp[])1867* a2 a2 a3 a41868*/18691870ENTRY(kernel_execve)1871entry a1, 161872mov a6, a2 # arg0 is in a61873movi a2, __NR_execve1874syscall18751876retw18771878/*1879* Task switch.1880*1881* struct task* _switch_to (struct task* prev, struct task* next)1882* a2 a2 a31883*/18841885ENTRY(_switch_to)18861887entry a1, 1618881889mov a12, a2 # preserve 'prev' (a2)1890mov a13, a3 # and 'next' (a3)18911892l32i a4, a2, TASK_THREAD_INFO1893l32i a5, a3, TASK_THREAD_INFO18941895save_xtregs_user a4 a6 a8 a9 a10 a11 THREAD_XTREGS_USER18961897s32i a0, a12, THREAD_RA # save return address1898s32i a1, a12, THREAD_SP # save stack pointer18991900/* Disable ints while we manipulate the stack pointer. */19011902movi a14, (1 << PS_EXCM_BIT) | LOCKLEVEL1903xsr a14, PS1904rsr a3, EXCSAVE_11905rsync1906s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */19071908/* Switch CPENABLE */19091910#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)1911l32i a3, a5, THREAD_CPENABLE1912xsr a3, CPENABLE1913s32i a3, a4, THREAD_CPENABLE1914#endif19151916/* Flush register file. */19171918call0 _spill_registers # destroys a3, a4, and SAR19191920/* Set kernel stack (and leave critical section)1921* Note: It's save to set it here. The stack will not be overwritten1922* because the kernel stack will only be loaded again after1923* we return from kernel space.1924*/19251926rsr a3, EXCSAVE_1 # exc_table1927movi a6, 01928addi a7, a5, PT_REGS_OFFSET1929s32i a6, a3, EXC_TABLE_FIXUP1930s32i a7, a3, EXC_TABLE_KSTK19311932/* restore context of the task that 'next' addresses */19331934l32i a0, a13, THREAD_RA # restore return address1935l32i a1, a13, THREAD_SP # restore stack pointer19361937load_xtregs_user a5 a6 a8 a9 a10 a11 THREAD_XTREGS_USER19381939wsr a14, PS1940mov a2, a12 # return 'prev'1941rsync19421943retw194419451946ENTRY(ret_from_fork)19471948/* void schedule_tail (struct task_struct *prev)1949* Note: prev is still in a6 (return value from fake call4 frame)1950*/1951movi a4, schedule_tail1952callx4 a419531954movi a4, do_syscall_trace_leave1955mov a6, a11956callx4 a419571958j common_exception_return1959196019611962