cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vectors.S (22407B)


      1/*
      2 * arch/xtensa/kernel/vectors.S
      3 *
      4 * This file contains all exception vectors (user, kernel, and double),
      5 * as well as the window vectors (overflow and underflow), and the debug
      6 * vector. These are the primary vectors executed by the processor if an
      7 * exception occurs.
      8 *
      9 * This file is subject to the terms and conditions of the GNU General
     10 * Public License.  See the file "COPYING" in the main directory of
     11 * this archive for more details.
     12 *
     13 * Copyright (C) 2005 - 2008 Tensilica, Inc.
     14 *
     15 * Chris Zankel <chris@zankel.net>
     16 *
     17 */
     18
     19/*
     20 * We use a two-level table approach. The user and kernel exception vectors
     21 * use a first-level dispatch table to dispatch the exception to a registered
     22 * fast handler or the default handler, if no fast handler was registered.
     23 * The default handler sets up a C-stack and dispatches the exception to a
     24 * registerd C handler in the second-level dispatch table.
     25 *
     26 * Fast handler entry condition:
     27 *
     28 *   a0:	trashed, original value saved on stack (PT_AREG0)
     29 *   a1:	a1
     30 *   a2:	new stack pointer, original value in depc
     31 *   a3:	dispatch table
     32 *   depc:	a2, original value saved on stack (PT_DEPC)
     33 *   excsave_1:	a3
     34 *
     35 * The value for PT_DEPC saved to stack also functions as a boolean to
     36 * indicate that the exception is either a double or a regular exception:
     37 *
     38 *   PT_DEPC	>= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception
     39 *		<  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
     40 *
     41 * Note:  Neither the kernel nor the user exception handler generate literals.
     42 *
     43 */
     44
     45#include <linux/linkage.h>
     46#include <linux/pgtable.h>
     47#include <asm/asmmacro.h>
     48#include <asm/ptrace.h>
     49#include <asm/current.h>
     50#include <asm/asm-offsets.h>
     51#include <asm/processor.h>
     52#include <asm/page.h>
     53#include <asm/thread_info.h>
     54#include <asm/vectors.h>
     55
     56#define WINDOW_VECTORS_SIZE   0x180
     57
     58
     59/*
     60 * User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0)
     61 *
     62 * We get here when an exception occurred while we were in userland.
     63 * We switch to the kernel stack and jump to the first level handler
     64 * associated to the exception cause.
     65 *
     66 * Note: the saved kernel stack pointer (EXC_TABLE_KSTK) is already
     67 *       decremented by PT_USER_SIZE.
     68 */
     69
     70	.section .UserExceptionVector.text, "ax"
     71
     72ENTRY(_UserExceptionVector)
     73
     74	xsr	a3, excsave1		# save a3 and get dispatch table
     75	wsr	a2, depc		# save a2
     76	l32i	a2, a3, EXC_TABLE_KSTK	# load kernel stack to a2
     77	s32i	a0, a2, PT_AREG0	# save a0 to ESF
     78	rsr	a0, exccause		# retrieve exception cause
     79	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
     80	addx4	a0, a0, a3		# find entry in table
     81	l32i	a0, a0, EXC_TABLE_FAST_USER	# load handler
     82	xsr	a3, excsave1		# restore a3 and dispatch table
     83	jx	a0
     84
     85ENDPROC(_UserExceptionVector)
     86
     87/*
     88 * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0)
     89 *
     90 * We get this exception when we were already in kernel space.
     91 * We decrement the current stack pointer (kernel) by PT_KERNEL_SIZE and
     92 * jump to the first-level handler associated with the exception cause.
     93 *
     94 * Note: we need to preserve space for the spill region.
     95 */
     96
     97	.section .KernelExceptionVector.text, "ax"
     98
     99ENTRY(_KernelExceptionVector)
    100
    101	xsr	a3, excsave1		# save a3, and get dispatch table
    102	wsr	a2, depc		# save a2
    103	addi	a2, a1, -16 - PT_KERNEL_SIZE	# adjust stack pointer
    104	s32i	a0, a2, PT_AREG0	# save a0 to ESF
    105	rsr	a0, exccause		# retrieve exception cause
    106	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
    107	addx4	a0, a0, a3		# find entry in table
    108	l32i	a0, a0, EXC_TABLE_FAST_KERNEL	# load handler address
    109	xsr	a3, excsave1		# restore a3 and dispatch table
    110	jx	a0
    111
    112ENDPROC(_KernelExceptionVector)
    113
    114/*
    115 * Double exception vector (Exceptions with PS.EXCM == 1)
    116 * We get this exception when another exception occurs while were are
    117 * already in an exception, such as window overflow/underflow exception,
    118 * or 'expected' exceptions, for example memory exception when we were trying
    119 * to read data from an invalid address in user space.
    120 *
    121 * Note that this vector is never invoked for level-1 interrupts, because such
    122 * interrupts are disabled (masked) when PS.EXCM is set.
    123 *
    124 * We decode the exception and take the appropriate action.  However, the
    125 * double exception vector is much more careful, because a lot more error
    126 * cases go through the double exception vector than through the user and
    127 * kernel exception vectors.
    128 *
    129 * Occasionally, the kernel expects a double exception to occur.  This usually
    130 * happens when accessing user-space memory with the user's permissions
    131 * (l32e/s32e instructions).  The kernel state, though, is not always suitable
    132 * for immediate transfer of control to handle_double, where "normal" exception
    133 * processing occurs. Also in kernel mode, TLB misses can occur if accessing
    134 * vmalloc memory, possibly requiring repair in a double exception handler.
    135 *
    136 * The variable at TABLE_FIXUP offset from the pointer in EXCSAVE_1 doubles as
    137 * a boolean variable and a pointer to a fixup routine. If the variable
    138 * EXC_TABLE_FIXUP is non-zero, this handler jumps to that address. A value of
    139 * zero indicates to use the default kernel/user exception handler.
    140 * There is only one exception, when the value is identical to the exc_table
    141 * label, the kernel is in trouble. This mechanism is used to protect critical
    142 * sections, mainly when the handler writes to the stack to assert the stack
    143 * pointer is valid. Once the fixup/default handler leaves that area, the
    144 * EXC_TABLE_FIXUP variable is reset to the fixup handler or zero.
    145 *
    146 * Procedures wishing to use this mechanism should set EXC_TABLE_FIXUP to the
    147 * nonzero address of a fixup routine before it could cause a double exception
    148 * and reset it before it returns.
    149 *
    150 * Some other things to take care of when a fast exception handler doesn't
    151 * specify a particular fixup handler but wants to use the default handlers:
    152 *
    153 *  - The original stack pointer (in a1) must not be modified. The fast
    154 *    exception handler should only use a2 as the stack pointer.
    155 *
    156 *  - If the fast handler manipulates the stack pointer (in a2), it has to
    157 *    register a valid fixup handler and cannot use the default handlers.
    158 *
    159 *  - The handler can use any other generic register from a3 to a15, but it
    160 *    must save the content of these registers to stack (PT_AREG3...PT_AREGx)
    161 *
    162 *  - These registers must be saved before a double exception can occur.
    163 *
    164 *  - If we ever implement handling signals while in double exceptions, the
    165 *    number of registers a fast handler has saved (excluding a0 and a1) must
    166 *    be written to  PT_AREG1. (1 if only a3 is used, 2 for a3 and a4, etc. )
    167 *
    168 * The fixup handlers are special handlers:
    169 *
    170 *  - Fixup entry conditions differ from regular exceptions:
    171 *
    172 *	a0:	   DEPC
    173 *	a1: 	   a1
    174 *	a2:	   trashed, original value in EXC_TABLE_DOUBLE_SAVE
    175 *	a3:	   exctable
    176 *	depc:	   a0
    177 *	excsave_1: a3
    178 *
    179 *  - When the kernel enters the fixup handler, it still assumes it is in a
    180 *    critical section, so EXC_TABLE_FIXUP variable is set to exc_table.
    181 *    The fixup handler, therefore, has to re-register itself as the fixup
    182 *    handler before it returns from the double exception.
    183 *
    184 *  - Fixup handler can share the same exception frame with the fast handler.
    185 *    The kernel stack pointer is not changed when entering the fixup handler.
    186 *
    187 *  - Fixup handlers can jump to the default kernel and user exception
    188 *    handlers. Before it jumps, though, it has to setup a exception frame
    189 *    on stack. Because the default handler resets the register fixup handler
    190 *    the fixup handler must make sure that the default handler returns to
    191 *    it instead of the exception address, so it can re-register itself as
    192 *    the fixup handler.
    193 *
    194 * In case of a critical condition where the kernel cannot recover, we jump
    195 * to unrecoverable_exception with the following entry conditions.
    196 * All registers a0...a15 are unchanged from the last exception, except:
    197 *
    198 *	a0:	   last address before we jumped to the unrecoverable_exception.
    199 *	excsave_1: a0
    200 *
    201 *
    202 * See the handle_alloca_user and spill_registers routines for example clients.
    203 *
    204 * FIXME: Note: we currently don't allow signal handling coming from a double
    205 *        exception, so the item markt with (*) is not required.
    206 */
    207
    208	.section .DoubleExceptionVector.text, "ax"
    209
    210ENTRY(_DoubleExceptionVector)
    211
    212	xsr	a3, excsave1
    213	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    214
    215	/* Check for kernel double exception (usually fatal). */
    216
    217	rsr	a2, ps
    218	_bbsi.l	a2, PS_UM_BIT, 1f
    219	j	.Lksp
    220
    221	.align	4
    222	.literal_position
    2231:
    224	/* Check if we are currently handling a window exception. */
    225	/* Note: We don't need to indicate that we enter a critical section. */
    226
    227	xsr	a0, depc		# get DEPC, save a0
    228
    229#ifdef SUPPORT_WINDOWED
    230	movi	a2, WINDOW_VECTORS_VADDR
    231	_bltu	a0, a2, .Lfixup
    232	addi	a2, a2, WINDOW_VECTORS_SIZE
    233	_bgeu	a0, a2, .Lfixup
    234
    235	/* Window overflow/underflow exception. Get stack pointer. */
    236
    237	l32i	a2, a3, EXC_TABLE_KSTK
    238
    239	/* Check for overflow/underflow exception, jump if overflow. */
    240
    241	bbci.l	a0, 6, _DoubleExceptionVector_WindowOverflow
    242
    243	/*
    244	 * Restart window underflow exception.
    245	 * Currently:
    246	 *	depc = orig a0,
    247	 *	a0 = orig DEPC,
    248	 *	a2 = new sp based on KSTK from exc_table
    249	 *	a3 = excsave_1
    250	 *	excsave_1 = orig a3
    251	 *
    252	 * We return to the instruction in user space that caused the window
    253	 * underflow exception. Therefore, we change window base to the value
    254	 * before we entered the window underflow exception and prepare the
    255	 * registers to return as if we were coming from a regular exception
    256	 * by changing depc (in a0).
    257	 * Note: We can trash the current window frame (a0...a3) and depc!
    258	 */
    259_DoubleExceptionVector_WindowUnderflow:
    260	xsr	a3, excsave1
    261	wsr	a2, depc		# save stack pointer temporarily
    262	rsr	a0, ps
    263	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
    264	wsr	a0, windowbase
    265	rsync
    266
    267	/* We are now in the previous window frame. Save registers again. */
    268
    269	xsr	a2, depc		# save a2 and get stack pointer
    270	s32i	a0, a2, PT_AREG0
    271	xsr	a3, excsave1
    272	rsr	a0, exccause
    273	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
    274	addx4	a0, a0, a3
    275	xsr	a3, excsave1
    276	l32i	a0, a0, EXC_TABLE_FAST_USER
    277	jx	a0
    278
    279#else
    280	j	.Lfixup
    281#endif
    282
    283	/*
    284	 * We only allow the ITLB miss exception if we are in kernel space.
    285	 * All other exceptions are unexpected and thus unrecoverable!
    286	 */
    287
    288#ifdef CONFIG_MMU
    289	.extern fast_second_level_miss_double_kernel
    290
    291.Lksp:	/* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
    292
    293	rsr	a3, exccause
    294	beqi	a3, EXCCAUSE_ITLB_MISS, 1f
    295	addi	a3, a3, -EXCCAUSE_DTLB_MISS
    296	bnez	a3, .Lunrecoverable
    2971:	movi	a3, fast_second_level_miss_double_kernel
    298	jx	a3
    299#else
    300.equ	.Lksp,	.Lunrecoverable
    301#endif
    302
    303	/* Critical! We can't handle this situation. PANIC! */
    304
    305	.extern unrecoverable_exception
    306
    307.Lunrecoverable_fixup:
    308	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    309	xsr	a0, depc
    310
    311.Lunrecoverable:
    312	rsr	a3, excsave1
    313	wsr	a0, excsave1
    314	call0	unrecoverable_exception
    315
    316.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
    317
    318	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave1: a3 */
    319
    320	/* Enter critical section. */
    321
    322	l32i	a2, a3, EXC_TABLE_FIXUP
    323	s32i	a3, a3, EXC_TABLE_FIXUP
    324	beq	a2, a3, .Lunrecoverable_fixup	# critical section
    325	beqz	a2, .Ldflt			# no handler was registered
    326
    327	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
    328
    329	jx	a2
    330
    331.Ldflt:	/* Get stack pointer. */
    332
    333	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    334	addi	a2, a2, -PT_USER_SIZE
    335
    336	/* a0: depc, a1: a1, a2: kstk, a3: exctable, depc: a0, excsave: a3 */
    337
    338	s32i	a0, a2, PT_DEPC
    339	l32i	a0, a3, EXC_TABLE_DOUBLE_SAVE
    340	xsr	a0, depc
    341	s32i	a0, a2, PT_AREG0
    342
    343	/* a0: avail, a1: a1, a2: kstk, a3: exctable, depc: a2, excsave: a3 */
    344
    345	rsr	a0, exccause
    346	addx4	a0, a0, a3
    347	xsr	a3, excsave1
    348	l32i	a0, a0, EXC_TABLE_FAST_USER
    349	jx	a0
    350
    351#ifdef SUPPORT_WINDOWED
    352	/*
    353	 * Restart window OVERFLOW exception.
    354	 * Currently:
    355	 *	depc = orig a0,
    356	 *	a0 = orig DEPC,
    357	 *	a2 = new sp based on KSTK from exc_table
    358	 *	a3 = EXCSAVE_1
    359	 *	excsave_1 = orig a3
    360	 *
    361	 * We return to the instruction in user space that caused the window
    362	 * overflow exception. Therefore, we change window base to the value
    363	 * before we entered the window overflow exception and prepare the
    364	 * registers to return as if we were coming from a regular exception
    365	 * by changing DEPC (in a0).
    366	 *
    367	 * NOTE: We CANNOT trash the current window frame (a0...a3), but we
    368	 * can clobber depc.
    369	 *
    370	 * The tricky part here is that overflow8 and overflow12 handlers
    371	 * save a0, then clobber a0.  To restart the handler, we have to restore
    372	 * a0 if the double exception was past the point where a0 was clobbered.
    373	 *
    374	 * To keep things simple, we take advantage of the fact all overflow
    375	 * handlers save a0 in their very first instruction.  If DEPC was past
    376	 * that instruction, we can safely restore a0 from where it was saved
    377	 * on the stack.
    378	 *
    379	 * a0: depc, a1: a1, a2: kstk, a3: exc_table, depc: a0, excsave1: a3
    380	 */
    381_DoubleExceptionVector_WindowOverflow:
    382	extui	a2, a0, 0, 6	# get offset into 64-byte vector handler
    383	beqz	a2, 1f		# if at start of vector, don't restore
    384
    385	addi	a0, a0, -128
    386	bbsi.l	a0, 8, 1f	# don't restore except for overflow 8 and 12
    387
    388	/*
    389	 * This fixup handler is for the extremely unlikely case where the
    390	 * overflow handler's reference thru a0 gets a hardware TLB refill
    391	 * that bumps out the (distinct, aliasing) TLB entry that mapped its
    392	 * prior references thru a9/a13, and where our reference now thru
    393	 * a9/a13 gets a 2nd-level miss exception (not hardware TLB refill).
    394	 */
    395	movi	a2, window_overflow_restore_a0_fixup
    396	s32i	a2, a3, EXC_TABLE_FIXUP
    397	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    398	xsr	a3, excsave1
    399
    400	bbsi.l	a0, 7, 2f
    401
    402	/*
    403	 * Restore a0 as saved by _WindowOverflow8().
    404	 */
    405
    406	l32e	a0, a9, -16
    407	wsr	a0, depc	# replace the saved a0
    408	j	3f
    409
    4102:
    411	/*
    412	 * Restore a0 as saved by _WindowOverflow12().
    413	 */
    414
    415	l32e	a0, a13, -16
    416	wsr	a0, depc	# replace the saved a0
    4173:
    418	xsr	a3, excsave1
    419	movi	a0, 0
    420	s32i	a0, a3, EXC_TABLE_FIXUP
    421	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    4221:
    423	/*
    424	 * Restore WindowBase while leaving all address registers restored.
    425	 * We have to use ROTW for this, because WSR.WINDOWBASE requires
    426	 * an address register (which would prevent restore).
    427	 *
    428	 * Window Base goes from 0 ... 7 (Module 8)
    429	 * Window Start is 8 bits; Ex: (0b1010 1010):0x55 from series of call4s
    430	 */
    431
    432	rsr	a0, ps
    433	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
    434	rsr	a2, windowbase
    435	sub	a0, a2, a0
    436	extui	a0, a0, 0, 3
    437
    438	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    439	xsr	a3, excsave1
    440	beqi	a0, 1, .L1pane
    441	beqi	a0, 3, .L3pane
    442
    443	rsr	a0, depc
    444	rotw	-2
    445
    446	/*
    447	 * We are now in the user code's original window frame.
    448	 * Process the exception as a user exception as if it was
    449	 * taken by the user code.
    450	 *
    451	 * This is similar to the user exception vector,
    452	 * except that PT_DEPC isn't set to EXCCAUSE.
    453	 */
    4541:
    455	xsr	a3, excsave1
    456	wsr	a2, depc
    457	l32i	a2, a3, EXC_TABLE_KSTK
    458	s32i	a0, a2, PT_AREG0
    459	rsr	a0, exccause
    460
    461	s32i	a0, a2, PT_DEPC
    462
    463_DoubleExceptionVector_handle_exception:
    464	addi	a0, a0, -EXCCAUSE_UNALIGNED
    465	beqz	a0, 2f
    466	addx4	a0, a0, a3
    467	l32i	a0, a0, EXC_TABLE_FAST_USER + 4 * EXCCAUSE_UNALIGNED
    468	xsr	a3, excsave1
    469	jx	a0
    4702:
    471	movi	a0, user_exception
    472	xsr	a3, excsave1
    473	jx	a0
    474
    475.L1pane:
    476	rsr	a0, depc
    477	rotw	-1
    478	j	1b
    479
    480.L3pane:
    481	rsr	a0, depc
    482	rotw	-3
    483	j	1b
    484#endif
    485
    486ENDPROC(_DoubleExceptionVector)
    487
    488#ifdef SUPPORT_WINDOWED
    489
    490/*
    491 * Fixup handler for TLB miss in double exception handler for window owerflow.
    492 * We get here with windowbase set to the window that was being spilled and
    493 * a0 trashed. a0 bit 7 determines if this is a call8 (bit clear) or call12
    494 * (bit set) window.
    495 *
    496 * We do the following here:
    497 * - go to the original window retaining a0 value;
    498 * - set up exception stack to return back to appropriate a0 restore code
    499 *   (we'll need to rotate window back and there's no place to save this
    500 *    information, use different return address for that);
    501 * - handle the exception;
    502 * - go to the window that was being spilled;
    503 * - set up window_overflow_restore_a0_fixup as a fixup routine;
    504 * - reload a0;
    505 * - restore the original window;
    506 * - reset the default fixup routine;
    507 * - return to user. By the time we get to this fixup handler all information
    508 *   about the conditions of the original double exception that happened in
    509 *   the window overflow handler is lost, so we just return to userspace to
    510 *   retry overflow from start.
    511 *
    512 * a0: value of depc, original value in depc
    513 * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
    514 * a3: exctable, original value in excsave1
    515 */
    516
    517	__XTENSA_HANDLER
    518	.literal_position
    519
    520ENTRY(window_overflow_restore_a0_fixup)
    521
    522	rsr	a0, ps
    523	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
    524	rsr	a2, windowbase
    525	sub	a0, a2, a0
    526	extui	a0, a0, 0, 3
    527	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    528	xsr	a3, excsave1
    529
    530	_beqi	a0, 1, .Lhandle_1
    531	_beqi	a0, 3, .Lhandle_3
    532
    533	.macro	overflow_fixup_handle_exception_pane n
    534
    535	rsr	a0, depc
    536	rotw	-\n
    537
    538	xsr	a3, excsave1
    539	wsr	a2, depc
    540	l32i	a2, a3, EXC_TABLE_KSTK
    541	s32i	a0, a2, PT_AREG0
    542
    543	movi	a0, .Lrestore_\n
    544	s32i	a0, a2, PT_DEPC
    545	rsr	a0, exccause
    546	j	_DoubleExceptionVector_handle_exception
    547
    548	.endm
    549
    550	overflow_fixup_handle_exception_pane 2
    551.Lhandle_1:
    552	overflow_fixup_handle_exception_pane 1
    553.Lhandle_3:
    554	overflow_fixup_handle_exception_pane 3
    555
    556	.macro	overflow_fixup_restore_a0_pane n
    557
    558	rotw	\n
    559	/* Need to preserve a0 value here to be able to handle exception
    560	 * that may occur on a0 reload from stack. It may occur because
    561	 * TLB miss handler may not be atomic and pointer to page table
    562	 * may be lost before we get here. There are no free registers,
    563	 * so we need to use EXC_TABLE_DOUBLE_SAVE area.
    564	 */
    565	xsr	a3, excsave1
    566	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    567	movi	a2, window_overflow_restore_a0_fixup
    568	s32i	a2, a3, EXC_TABLE_FIXUP
    569	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    570	xsr	a3, excsave1
    571	bbsi.l	a0, 7, 1f
    572	l32e	a0, a9, -16
    573	j	2f
    5741:
    575	l32e	a0, a13, -16
    5762:
    577	rotw	-\n
    578
    579	.endm
    580
    581.Lrestore_2:
    582	overflow_fixup_restore_a0_pane 2
    583
    584.Lset_default_fixup:
    585	xsr	a3, excsave1
    586	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    587	movi	a2, 0
    588	s32i	a2, a3, EXC_TABLE_FIXUP
    589	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
    590	xsr	a3, excsave1
    591	rfe
    592
    593.Lrestore_1:
    594	overflow_fixup_restore_a0_pane 1
    595	j	.Lset_default_fixup
    596.Lrestore_3:
    597	overflow_fixup_restore_a0_pane 3
    598	j	.Lset_default_fixup
    599
    600ENDPROC(window_overflow_restore_a0_fixup)
    601
    602#endif
    603
    604/*
    605 * Debug interrupt vector
    606 *
    607 * There is not much space here, so simply jump to another handler.
    608 * EXCSAVE[DEBUGLEVEL] has been set to that handler.
    609 */
    610
    611	.section .DebugInterruptVector.text, "ax"
    612
    613ENTRY(_DebugInterruptVector)
    614
    615	xsr	a3, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
    616	s32i	a0, a3, DT_DEBUG_SAVE
    617	l32i	a0, a3, DT_DEBUG_EXCEPTION
    618	jx	a0
    619
    620ENDPROC(_DebugInterruptVector)
    621
    622
    623
    624/*
    625 * Medium priority level interrupt vectors
    626 *
    627 * Each takes less than 16 (0x10) bytes, no literals, by placing
    628 * the extra 8 bytes that would otherwise be required in the window
    629 * vectors area where there is space.  With relocatable vectors,
    630 * all vectors are within ~ 4 kB range of each other, so we can
    631 * simply jump (J) to another vector without having to use JX.
    632 *
    633 * common_exception code gets current IRQ level in PS.INTLEVEL
    634 * and preserves it for the IRQ handling time.
    635 */
    636
    637	.macro	irq_entry_level level
    638
    639	.if	XCHAL_EXCM_LEVEL >= \level
    640	.section .Level\level\()InterruptVector.text, "ax"
    641ENTRY(_Level\level\()InterruptVector)
    642	wsr	a0, excsave2
    643	rsr	a0, epc\level
    644	wsr	a0, epc1
    645	.if	\level <= LOCKLEVEL
    646	movi	a0, EXCCAUSE_LEVEL1_INTERRUPT
    647	.else
    648	movi	a0, EXCCAUSE_MAPPED_NMI
    649	.endif
    650	wsr	a0, exccause
    651	rsr	a0, eps\level
    652					# branch to user or kernel vector
    653	j	_SimulateUserKernelVectorException
    654	.endif
    655
    656	.endm
    657
    658	irq_entry_level 2
    659	irq_entry_level 3
    660	irq_entry_level 4
    661	irq_entry_level 5
    662	irq_entry_level 6
    663
    664#if XCHAL_EXCM_LEVEL >= 2
    665	/*
    666	 *  Continuation of medium priority interrupt dispatch code.
    667	 *  On entry here, a0 contains PS, and EPC2 contains saved a0:
    668	 */
    669	__XTENSA_HANDLER
    670	.align 4
    671_SimulateUserKernelVectorException:
    672	addi	a0, a0, (1 << PS_EXCM_BIT)
    673#if !XTENSA_FAKE_NMI
    674	wsr	a0, ps
    675#endif
    676	bbsi.l	a0, PS_UM_BIT, 1f	# branch if user mode
    677	xsr	a0, excsave2		# restore a0
    678	j	_KernelExceptionVector	# simulate kernel vector exception
    6791:	xsr	a0, excsave2		# restore a0
    680	j	_UserExceptionVector	# simulate user vector exception
    681#endif
    682
    683
    684/* Window overflow and underflow handlers.
    685 * The handlers must be 64 bytes apart, first starting with the underflow
    686 * handlers underflow-4 to underflow-12, then the overflow handlers
    687 * overflow-4 to overflow-12.
    688 *
    689 * Note: We rerun the underflow handlers if we hit an exception, so
    690 *	 we try to access any page that would cause a page fault early.
    691 */
    692
    693#define ENTRY_ALIGN64(name)	\
    694	.globl name;		\
    695	.align 64;		\
    696	name:
    697
    698	.section		.WindowVectors.text, "ax"
    699
    700
    701#ifdef SUPPORT_WINDOWED
    702
    703/* 4-Register Window Overflow Vector (Handler) */
    704
    705ENTRY_ALIGN64(_WindowOverflow4)
    706
    707	s32e	a0, a5, -16
    708	s32e	a1, a5, -12
    709	s32e	a2, a5,  -8
    710	s32e	a3, a5,  -4
    711	rfwo
    712
    713ENDPROC(_WindowOverflow4)
    714
    715/* 4-Register Window Underflow Vector (Handler) */
    716
    717ENTRY_ALIGN64(_WindowUnderflow4)
    718
    719	l32e	a0, a5, -16
    720	l32e	a1, a5, -12
    721	l32e	a2, a5,  -8
    722	l32e	a3, a5,  -4
    723	rfwu
    724
    725ENDPROC(_WindowUnderflow4)
    726
    727/* 8-Register Window Overflow Vector (Handler) */
    728
    729ENTRY_ALIGN64(_WindowOverflow8)
    730
    731	s32e	a0, a9, -16
    732	l32e	a0, a1, -12
    733	s32e	a2, a9,  -8
    734	s32e	a1, a9, -12
    735	s32e	a3, a9,  -4
    736	s32e	a4, a0, -32
    737	s32e	a5, a0, -28
    738	s32e	a6, a0, -24
    739	s32e	a7, a0, -20
    740	rfwo
    741
    742ENDPROC(_WindowOverflow8)
    743
    744/* 8-Register Window Underflow Vector (Handler) */
    745
    746ENTRY_ALIGN64(_WindowUnderflow8)
    747
    748	l32e	a1, a9, -12
    749	l32e	a0, a9, -16
    750	l32e	a7, a1, -12
    751	l32e	a2, a9,  -8
    752	l32e	a4, a7, -32
    753	l32e	a3, a9,  -4
    754	l32e	a5, a7, -28
    755	l32e	a6, a7, -24
    756	l32e	a7, a7, -20
    757	rfwu
    758
    759ENDPROC(_WindowUnderflow8)
    760
    761/* 12-Register Window Overflow Vector (Handler) */
    762
    763ENTRY_ALIGN64(_WindowOverflow12)
    764
    765	s32e	a0,  a13, -16
    766	l32e	a0,  a1,  -12
    767	s32e	a1,  a13, -12
    768	s32e	a2,  a13,  -8
    769	s32e	a3,  a13,  -4
    770	s32e	a4,  a0,  -48
    771	s32e	a5,  a0,  -44
    772	s32e	a6,  a0,  -40
    773	s32e	a7,  a0,  -36
    774	s32e	a8,  a0,  -32
    775	s32e	a9,  a0,  -28
    776	s32e	a10, a0,  -24
    777	s32e	a11, a0,  -20
    778	rfwo
    779
    780ENDPROC(_WindowOverflow12)
    781
    782/* 12-Register Window Underflow Vector (Handler) */
    783
    784ENTRY_ALIGN64(_WindowUnderflow12)
    785
    786	l32e	a1,  a13, -12
    787	l32e	a0,  a13, -16
    788	l32e	a11, a1,  -12
    789	l32e	a2,  a13,  -8
    790	l32e	a4,  a11, -48
    791	l32e	a8,  a11, -32
    792	l32e	a3,  a13,  -4
    793	l32e	a5,  a11, -44
    794	l32e	a6,  a11, -40
    795	l32e	a7,  a11, -36
    796	l32e	a9,  a11, -28
    797	l32e	a10, a11, -24
    798	l32e	a11, a11, -20
    799	rfwu
    800
    801ENDPROC(_WindowUnderflow12)
    802
    803#endif
    804
    805	.text