xref: /openbmc/linux/arch/xtensa/kernel/vectors.S (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
15a0015d6SChris Zankel/*
25a0015d6SChris Zankel * arch/xtensa/kernel/vectors.S
35a0015d6SChris Zankel *
45a0015d6SChris Zankel * This file contains all exception vectors (user, kernel, and double),
55a0015d6SChris Zankel * as well as the window vectors (overflow and underflow), and the debug
65a0015d6SChris Zankel * vector. These are the primary vectors executed by the processor if an
75a0015d6SChris Zankel * exception occurs.
85a0015d6SChris Zankel *
95a0015d6SChris Zankel * This file is subject to the terms and conditions of the GNU General
105a0015d6SChris Zankel * Public License.  See the file "COPYING" in the main directory of
115a0015d6SChris Zankel * this archive for more details.
125a0015d6SChris Zankel *
132d1c645cSMarc Gauthier * Copyright (C) 2005 - 2008 Tensilica, Inc.
145a0015d6SChris Zankel *
155a0015d6SChris Zankel * Chris Zankel <chris@zankel.net>
165a0015d6SChris Zankel *
175a0015d6SChris Zankel */
185a0015d6SChris Zankel
195a0015d6SChris Zankel/*
205a0015d6SChris Zankel * We use a two-level table approach. The user and kernel exception vectors
215a0015d6SChris Zankel * use a first-level dispatch table to dispatch the exception to a registered
225a0015d6SChris Zankel * fast handler or the default handler, if no fast handler was registered.
235a0015d6SChris Zankel * The default handler sets up a C-stack and dispatches the exception to a
245a0015d6SChris Zankel * registerd C handler in the second-level dispatch table.
255a0015d6SChris Zankel *
265a0015d6SChris Zankel * Fast handler entry condition:
275a0015d6SChris Zankel *
285a0015d6SChris Zankel *   a0:	trashed, original value saved on stack (PT_AREG0)
295a0015d6SChris Zankel *   a1:	a1
305a0015d6SChris Zankel *   a2:	new stack pointer, original value in depc
315a0015d6SChris Zankel *   a3:	dispatch table
325a0015d6SChris Zankel *   depc:	a2, original value saved on stack (PT_DEPC)
335a0015d6SChris Zankel *   excsave_1:	a3
345a0015d6SChris Zankel *
355a0015d6SChris Zankel * The value for PT_DEPC saved to stack also functions as a boolean to
365a0015d6SChris Zankel * indicate that the exception is either a double or a regular exception:
375a0015d6SChris Zankel *
385a0015d6SChris Zankel *   PT_DEPC	>= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception
395a0015d6SChris Zankel *		<  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
405a0015d6SChris Zankel *
415a0015d6SChris Zankel * Note:  Neither the kernel nor the user exception handler generate literals.
425a0015d6SChris Zankel *
435a0015d6SChris Zankel */
445a0015d6SChris Zankel
455a0015d6SChris Zankel#include <linux/linkage.h>
4665fddcfcSMike Rapoport#include <linux/pgtable.h>
4750722f0bSMax Filippov#include <asm/asmmacro.h>
485a0015d6SChris Zankel#include <asm/ptrace.h>
495a0015d6SChris Zankel#include <asm/current.h>
500013a854SSam Ravnborg#include <asm/asm-offsets.h>
515a0015d6SChris Zankel#include <asm/processor.h>
525a0015d6SChris Zankel#include <asm/page.h>
535a0015d6SChris Zankel#include <asm/thread_info.h>
54e85e335fSMax Filippov#include <asm/vectors.h>
555a0015d6SChris Zankel
56173d6681SChris Zankel#define WINDOW_VECTORS_SIZE   0x180
57173d6681SChris Zankel
585a0015d6SChris Zankel
595a0015d6SChris Zankel/*
605a0015d6SChris Zankel * User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0)
615a0015d6SChris Zankel *
625a0015d6SChris Zankel * We get here when an exception occurred while we were in userland.
635a0015d6SChris Zankel * We switch to the kernel stack and jump to the first level handler
645a0015d6SChris Zankel * associated to the exception cause.
655a0015d6SChris Zankel *
665a0015d6SChris Zankel * Note: the saved kernel stack pointer (EXC_TABLE_KSTK) is already
675a0015d6SChris Zankel *       decremented by PT_USER_SIZE.
685a0015d6SChris Zankel */
695a0015d6SChris Zankel
705a0015d6SChris Zankel	.section .UserExceptionVector.text, "ax"
715a0015d6SChris Zankel
725a0015d6SChris ZankelENTRY(_UserExceptionVector)
735a0015d6SChris Zankel
74bc5378fcSMax Filippov	xsr	a3, excsave1		# save a3 and get dispatch table
75bc5378fcSMax Filippov	wsr	a2, depc		# save a2
765a0015d6SChris Zankel	l32i	a2, a3, EXC_TABLE_KSTK	# load kernel stack to a2
775a0015d6SChris Zankel	s32i	a0, a2, PT_AREG0	# save a0 to ESF
78bc5378fcSMax Filippov	rsr	a0, exccause		# retrieve exception cause
795a0015d6SChris Zankel	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
805a0015d6SChris Zankel	addx4	a0, a0, a3		# find entry in table
815a0015d6SChris Zankel	l32i	a0, a0, EXC_TABLE_FAST_USER	# load handler
8299d5040eSMax Filippov	xsr	a3, excsave1		# restore a3 and dispatch table
835a0015d6SChris Zankel	jx	a0
845a0015d6SChris Zankel
85d1538c46SChris ZankelENDPROC(_UserExceptionVector)
86d1538c46SChris Zankel
875a0015d6SChris Zankel/*
885a0015d6SChris Zankel * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0)
895a0015d6SChris Zankel *
905a0015d6SChris Zankel * We get this exception when we were already in kernel space.
91*6fad9ddcSMax Filippov * We decrement the current stack pointer (kernel) by PT_KERNEL_SIZE and
925a0015d6SChris Zankel * jump to the first-level handler associated with the exception cause.
935a0015d6SChris Zankel *
945a0015d6SChris Zankel * Note: we need to preserve space for the spill region.
955a0015d6SChris Zankel */
965a0015d6SChris Zankel
975a0015d6SChris Zankel	.section .KernelExceptionVector.text, "ax"
985a0015d6SChris Zankel
995a0015d6SChris ZankelENTRY(_KernelExceptionVector)
1005a0015d6SChris Zankel
101bc5378fcSMax Filippov	xsr	a3, excsave1		# save a3, and get dispatch table
102bc5378fcSMax Filippov	wsr	a2, depc		# save a2
103*6fad9ddcSMax Filippov	addi	a2, a1, -16 - PT_KERNEL_SIZE	# adjust stack pointer
1045a0015d6SChris Zankel	s32i	a0, a2, PT_AREG0	# save a0 to ESF
105bc5378fcSMax Filippov	rsr	a0, exccause		# retrieve exception cause
1065a0015d6SChris Zankel	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
1075a0015d6SChris Zankel	addx4	a0, a0, a3		# find entry in table
1085a0015d6SChris Zankel	l32i	a0, a0, EXC_TABLE_FAST_KERNEL	# load handler address
10999d5040eSMax Filippov	xsr	a3, excsave1		# restore a3 and dispatch table
1105a0015d6SChris Zankel	jx	a0
1115a0015d6SChris Zankel
112d1538c46SChris ZankelENDPROC(_KernelExceptionVector)
1135a0015d6SChris Zankel
1145a0015d6SChris Zankel/*
1155a0015d6SChris Zankel * Double exception vector (Exceptions with PS.EXCM == 1)
1165a0015d6SChris Zankel * We get this exception when another exception occurs while were are
1175a0015d6SChris Zankel * already in an exception, such as window overflow/underflow exception,
1185a0015d6SChris Zankel * or 'expected' exceptions, for example memory exception when we were trying
1195a0015d6SChris Zankel * to read data from an invalid address in user space.
1205a0015d6SChris Zankel *
1215a0015d6SChris Zankel * Note that this vector is never invoked for level-1 interrupts, because such
1225a0015d6SChris Zankel * interrupts are disabled (masked) when PS.EXCM is set.
1235a0015d6SChris Zankel *
1245a0015d6SChris Zankel * We decode the exception and take the appropriate action.  However, the
1255a0015d6SChris Zankel * double exception vector is much more careful, because a lot more error
1265a0015d6SChris Zankel * cases go through the double exception vector than through the user and
1275a0015d6SChris Zankel * kernel exception vectors.
1285a0015d6SChris Zankel *
1295a0015d6SChris Zankel * Occasionally, the kernel expects a double exception to occur.  This usually
1305a0015d6SChris Zankel * happens when accessing user-space memory with the user's permissions
1315a0015d6SChris Zankel * (l32e/s32e instructions).  The kernel state, though, is not always suitable
1325a0015d6SChris Zankel * for immediate transfer of control to handle_double, where "normal" exception
1335a0015d6SChris Zankel * processing occurs. Also in kernel mode, TLB misses can occur if accessing
1345a0015d6SChris Zankel * vmalloc memory, possibly requiring repair in a double exception handler.
1355a0015d6SChris Zankel *
1365a0015d6SChris Zankel * The variable at TABLE_FIXUP offset from the pointer in EXCSAVE_1 doubles as
1375a0015d6SChris Zankel * a boolean variable and a pointer to a fixup routine. If the variable
1385a0015d6SChris Zankel * EXC_TABLE_FIXUP is non-zero, this handler jumps to that address. A value of
1395a0015d6SChris Zankel * zero indicates to use the default kernel/user exception handler.
1405a0015d6SChris Zankel * There is only one exception, when the value is identical to the exc_table
1415a0015d6SChris Zankel * label, the kernel is in trouble. This mechanism is used to protect critical
1425a0015d6SChris Zankel * sections, mainly when the handler writes to the stack to assert the stack
1435a0015d6SChris Zankel * pointer is valid. Once the fixup/default handler leaves that area, the
1445a0015d6SChris Zankel * EXC_TABLE_FIXUP variable is reset to the fixup handler or zero.
1455a0015d6SChris Zankel *
1465a0015d6SChris Zankel * Procedures wishing to use this mechanism should set EXC_TABLE_FIXUP to the
1475a0015d6SChris Zankel * nonzero address of a fixup routine before it could cause a double exception
1485a0015d6SChris Zankel * and reset it before it returns.
1495a0015d6SChris Zankel *
1505a0015d6SChris Zankel * Some other things to take care of when a fast exception handler doesn't
1515a0015d6SChris Zankel * specify a particular fixup handler but wants to use the default handlers:
1525a0015d6SChris Zankel *
1535a0015d6SChris Zankel *  - The original stack pointer (in a1) must not be modified. The fast
1545a0015d6SChris Zankel *    exception handler should only use a2 as the stack pointer.
1555a0015d6SChris Zankel *
1565a0015d6SChris Zankel *  - If the fast handler manipulates the stack pointer (in a2), it has to
1575a0015d6SChris Zankel *    register a valid fixup handler and cannot use the default handlers.
1585a0015d6SChris Zankel *
1595a0015d6SChris Zankel *  - The handler can use any other generic register from a3 to a15, but it
1605a0015d6SChris Zankel *    must save the content of these registers to stack (PT_AREG3...PT_AREGx)
1615a0015d6SChris Zankel *
1625a0015d6SChris Zankel *  - These registers must be saved before a double exception can occur.
1635a0015d6SChris Zankel *
1645a0015d6SChris Zankel *  - If we ever implement handling signals while in double exceptions, the
1655a0015d6SChris Zankel *    number of registers a fast handler has saved (excluding a0 and a1) must
1665a0015d6SChris Zankel *    be written to  PT_AREG1. (1 if only a3 is used, 2 for a3 and a4, etc. )
1675a0015d6SChris Zankel *
1685a0015d6SChris Zankel * The fixup handlers are special handlers:
1695a0015d6SChris Zankel *
1705a0015d6SChris Zankel *  - Fixup entry conditions differ from regular exceptions:
1715a0015d6SChris Zankel *
1725a0015d6SChris Zankel *	a0:	   DEPC
1735a0015d6SChris Zankel *	a1: 	   a1
17499d5040eSMax Filippov *	a2:	   trashed, original value in EXC_TABLE_DOUBLE_SAVE
1755a0015d6SChris Zankel *	a3:	   exctable
1765a0015d6SChris Zankel *	depc:	   a0
1775a0015d6SChris Zankel *	excsave_1: a3
1785a0015d6SChris Zankel *
1795a0015d6SChris Zankel *  - When the kernel enters the fixup handler, it still assumes it is in a
1805a0015d6SChris Zankel *    critical section, so EXC_TABLE_FIXUP variable is set to exc_table.
1815a0015d6SChris Zankel *    The fixup handler, therefore, has to re-register itself as the fixup
1825a0015d6SChris Zankel *    handler before it returns from the double exception.
1835a0015d6SChris Zankel *
1845a0015d6SChris Zankel *  - Fixup handler can share the same exception frame with the fast handler.
1855a0015d6SChris Zankel *    The kernel stack pointer is not changed when entering the fixup handler.
1865a0015d6SChris Zankel *
1875a0015d6SChris Zankel *  - Fixup handlers can jump to the default kernel and user exception
1885a0015d6SChris Zankel *    handlers. Before it jumps, though, it has to setup a exception frame
1895a0015d6SChris Zankel *    on stack. Because the default handler resets the register fixup handler
1905a0015d6SChris Zankel *    the fixup handler must make sure that the default handler returns to
1915a0015d6SChris Zankel *    it instead of the exception address, so it can re-register itself as
1925a0015d6SChris Zankel *    the fixup handler.
1935a0015d6SChris Zankel *
1945a0015d6SChris Zankel * In case of a critical condition where the kernel cannot recover, we jump
1955a0015d6SChris Zankel * to unrecoverable_exception with the following entry conditions.
1965a0015d6SChris Zankel * All registers a0...a15 are unchanged from the last exception, except:
1975a0015d6SChris Zankel *
1985a0015d6SChris Zankel *	a0:	   last address before we jumped to the unrecoverable_exception.
1995a0015d6SChris Zankel *	excsave_1: a0
2005a0015d6SChris Zankel *
2015a0015d6SChris Zankel *
2025a0015d6SChris Zankel * See the handle_alloca_user and spill_registers routines for example clients.
2035a0015d6SChris Zankel *
2045a0015d6SChris Zankel * FIXME: Note: we currently don't allow signal handling coming from a double
2055a0015d6SChris Zankel *        exception, so the item markt with (*) is not required.
2065a0015d6SChris Zankel */
2075a0015d6SChris Zankel
2085a0015d6SChris Zankel	.section .DoubleExceptionVector.text, "ax"
2095a0015d6SChris Zankel
2105a0015d6SChris ZankelENTRY(_DoubleExceptionVector)
2115a0015d6SChris Zankel
21299d5040eSMax Filippov	xsr	a3, excsave1
21399d5040eSMax Filippov	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
2145a0015d6SChris Zankel
2155a0015d6SChris Zankel	/* Check for kernel double exception (usually fatal). */
2165a0015d6SChris Zankel
21799d5040eSMax Filippov	rsr	a2, ps
218f8f02ca7SMax Filippov	_bbsi.l	a2, PS_UM_BIT, 1f
219f8f02ca7SMax Filippov	j	.Lksp
2205a0015d6SChris Zankel
221f8f02ca7SMax Filippov	.align	4
222f8f02ca7SMax Filippov	.literal_position
223f8f02ca7SMax Filippov1:
2245a0015d6SChris Zankel	/* Check if we are currently handling a window exception. */
2255a0015d6SChris Zankel	/* Note: We don't need to indicate that we enter a critical section. */
2265a0015d6SChris Zankel
227bc5378fcSMax Filippov	xsr	a0, depc		# get DEPC, save a0
2285a0015d6SChris Zankel
229da0a4e5cSMax Filippov#ifdef SUPPORT_WINDOWED
23099d5040eSMax Filippov	movi	a2, WINDOW_VECTORS_VADDR
23199d5040eSMax Filippov	_bltu	a0, a2, .Lfixup
23299d5040eSMax Filippov	addi	a2, a2, WINDOW_VECTORS_SIZE
23399d5040eSMax Filippov	_bgeu	a0, a2, .Lfixup
2345a0015d6SChris Zankel
2355a0015d6SChris Zankel	/* Window overflow/underflow exception. Get stack pointer. */
2365a0015d6SChris Zankel
23799d5040eSMax Filippov	l32i	a2, a3, EXC_TABLE_KSTK
2385a0015d6SChris Zankel
2395a0015d6SChris Zankel	/* Check for overflow/underflow exception, jump if overflow. */
2405a0015d6SChris Zankel
241c0e50d41SChris Zankel	bbci.l	a0, 6, _DoubleExceptionVector_WindowOverflow
2425a0015d6SChris Zankel
24399d5040eSMax Filippov	/*
24499d5040eSMax Filippov	 * Restart window underflow exception.
24599d5040eSMax Filippov	 * Currently:
24699d5040eSMax Filippov	 *	depc = orig a0,
24799d5040eSMax Filippov	 *	a0 = orig DEPC,
24899d5040eSMax Filippov	 *	a2 = new sp based on KSTK from exc_table
24999d5040eSMax Filippov	 *	a3 = excsave_1
25099d5040eSMax Filippov	 *	excsave_1 = orig a3
25199d5040eSMax Filippov	 *
2525a0015d6SChris Zankel	 * We return to the instruction in user space that caused the window
2535a0015d6SChris Zankel	 * underflow exception. Therefore, we change window base to the value
2545a0015d6SChris Zankel	 * before we entered the window underflow exception and prepare the
2555a0015d6SChris Zankel	 * registers to return as if we were coming from a regular exception
2565a0015d6SChris Zankel	 * by changing depc (in a0).
2575a0015d6SChris Zankel	 * Note: We can trash the current window frame (a0...a3) and depc!
2585a0015d6SChris Zankel	 */
25999d5040eSMax Filippov_DoubleExceptionVector_WindowUnderflow:
26099d5040eSMax Filippov	xsr	a3, excsave1
261bc5378fcSMax Filippov	wsr	a2, depc		# save stack pointer temporarily
262bc5378fcSMax Filippov	rsr	a0, ps
26399d5040eSMax Filippov	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
264bc5378fcSMax Filippov	wsr	a0, windowbase
2655a0015d6SChris Zankel	rsync
2665a0015d6SChris Zankel
2675a0015d6SChris Zankel	/* We are now in the previous window frame. Save registers again. */
2685a0015d6SChris Zankel
269bc5378fcSMax Filippov	xsr	a2, depc		# save a2 and get stack pointer
2705a0015d6SChris Zankel	s32i	a0, a2, PT_AREG0
27199d5040eSMax Filippov	xsr	a3, excsave1
272bc5378fcSMax Filippov	rsr	a0, exccause
2735a0015d6SChris Zankel	s32i	a0, a2, PT_DEPC		# mark it as a regular exception
2745a0015d6SChris Zankel	addx4	a0, a0, a3
27599d5040eSMax Filippov	xsr	a3, excsave1
2765a0015d6SChris Zankel	l32i	a0, a0, EXC_TABLE_FAST_USER
2775a0015d6SChris Zankel	jx	a0
2785a0015d6SChris Zankel
279da0a4e5cSMax Filippov#else
280da0a4e5cSMax Filippov	j	.Lfixup
281da0a4e5cSMax Filippov#endif
282da0a4e5cSMax Filippov
2835a0015d6SChris Zankel	/*
2845a0015d6SChris Zankel	 * We only allow the ITLB miss exception if we are in kernel space.
2855a0015d6SChris Zankel	 * All other exceptions are unexpected and thus unrecoverable!
2865a0015d6SChris Zankel	 */
2875a0015d6SChris Zankel
288e5083a63SJohannes Weiner#ifdef CONFIG_MMU
2895a0015d6SChris Zankel	.extern fast_second_level_miss_double_kernel
2905a0015d6SChris Zankel
2915a0015d6SChris Zankel.Lksp:	/* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
2925a0015d6SChris Zankel
293bc5378fcSMax Filippov	rsr	a3, exccause
294173d6681SChris Zankel	beqi	a3, EXCCAUSE_ITLB_MISS, 1f
295173d6681SChris Zankel	addi	a3, a3, -EXCCAUSE_DTLB_MISS
2965a0015d6SChris Zankel	bnez	a3, .Lunrecoverable
2975a0015d6SChris Zankel1:	movi	a3, fast_second_level_miss_double_kernel
2985a0015d6SChris Zankel	jx	a3
299e5083a63SJohannes Weiner#else
300e5083a63SJohannes Weiner.equ	.Lksp,	.Lunrecoverable
301e5083a63SJohannes Weiner#endif
3025a0015d6SChris Zankel
3035a0015d6SChris Zankel	/* Critical! We can't handle this situation. PANIC! */
3045a0015d6SChris Zankel
3055a0015d6SChris Zankel	.extern unrecoverable_exception
3065a0015d6SChris Zankel
3075a0015d6SChris Zankel.Lunrecoverable_fixup:
3085a0015d6SChris Zankel	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
309bc5378fcSMax Filippov	xsr	a0, depc
3105a0015d6SChris Zankel
3115a0015d6SChris Zankel.Lunrecoverable:
312bc5378fcSMax Filippov	rsr	a3, excsave1
313bc5378fcSMax Filippov	wsr	a0, excsave1
3142da03d41SMax Filippov	call0	unrecoverable_exception
3155a0015d6SChris Zankel
31699d5040eSMax Filippov.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
31799d5040eSMax Filippov
31899d5040eSMax Filippov	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave1: a3 */
31999d5040eSMax Filippov
32099d5040eSMax Filippov	/* Enter critical section. */
32199d5040eSMax Filippov
32299d5040eSMax Filippov	l32i	a2, a3, EXC_TABLE_FIXUP
32399d5040eSMax Filippov	s32i	a3, a3, EXC_TABLE_FIXUP
32499d5040eSMax Filippov	beq	a2, a3, .Lunrecoverable_fixup	# critical section
32599d5040eSMax Filippov	beqz	a2, .Ldflt			# no handler was registered
32699d5040eSMax Filippov
32799d5040eSMax Filippov	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
32899d5040eSMax Filippov
32999d5040eSMax Filippov	jx	a2
33099d5040eSMax Filippov
33199d5040eSMax Filippov.Ldflt:	/* Get stack pointer. */
33299d5040eSMax Filippov
33399d5040eSMax Filippov	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
33499d5040eSMax Filippov	addi	a2, a2, -PT_USER_SIZE
33599d5040eSMax Filippov
33699d5040eSMax Filippov	/* a0: depc, a1: a1, a2: kstk, a3: exctable, depc: a0, excsave: a3 */
33799d5040eSMax Filippov
33899d5040eSMax Filippov	s32i	a0, a2, PT_DEPC
33999d5040eSMax Filippov	l32i	a0, a3, EXC_TABLE_DOUBLE_SAVE
34099d5040eSMax Filippov	xsr	a0, depc
34199d5040eSMax Filippov	s32i	a0, a2, PT_AREG0
34299d5040eSMax Filippov
34399d5040eSMax Filippov	/* a0: avail, a1: a1, a2: kstk, a3: exctable, depc: a2, excsave: a3 */
34499d5040eSMax Filippov
34599d5040eSMax Filippov	rsr	a0, exccause
34699d5040eSMax Filippov	addx4	a0, a0, a3
34799d5040eSMax Filippov	xsr	a3, excsave1
34899d5040eSMax Filippov	l32i	a0, a0, EXC_TABLE_FAST_USER
34999d5040eSMax Filippov	jx	a0
35099d5040eSMax Filippov
351da0a4e5cSMax Filippov#ifdef SUPPORT_WINDOWED
35299d5040eSMax Filippov	/*
35399d5040eSMax Filippov	 * Restart window OVERFLOW exception.
35499d5040eSMax Filippov	 * Currently:
35599d5040eSMax Filippov	 *	depc = orig a0,
35699d5040eSMax Filippov	 *	a0 = orig DEPC,
35799d5040eSMax Filippov	 *	a2 = new sp based on KSTK from exc_table
35899d5040eSMax Filippov	 *	a3 = EXCSAVE_1
35999d5040eSMax Filippov	 *	excsave_1 = orig a3
36099d5040eSMax Filippov	 *
36199d5040eSMax Filippov	 * We return to the instruction in user space that caused the window
36299d5040eSMax Filippov	 * overflow exception. Therefore, we change window base to the value
36399d5040eSMax Filippov	 * before we entered the window overflow exception and prepare the
36499d5040eSMax Filippov	 * registers to return as if we were coming from a regular exception
36599d5040eSMax Filippov	 * by changing DEPC (in a0).
36699d5040eSMax Filippov	 *
36799d5040eSMax Filippov	 * NOTE: We CANNOT trash the current window frame (a0...a3), but we
36899d5040eSMax Filippov	 * can clobber depc.
36999d5040eSMax Filippov	 *
37099d5040eSMax Filippov	 * The tricky part here is that overflow8 and overflow12 handlers
37199d5040eSMax Filippov	 * save a0, then clobber a0.  To restart the handler, we have to restore
37299d5040eSMax Filippov	 * a0 if the double exception was past the point where a0 was clobbered.
37399d5040eSMax Filippov	 *
37499d5040eSMax Filippov	 * To keep things simple, we take advantage of the fact all overflow
37599d5040eSMax Filippov	 * handlers save a0 in their very first instruction.  If DEPC was past
37699d5040eSMax Filippov	 * that instruction, we can safely restore a0 from where it was saved
37799d5040eSMax Filippov	 * on the stack.
37899d5040eSMax Filippov	 *
37999d5040eSMax Filippov	 * a0: depc, a1: a1, a2: kstk, a3: exc_table, depc: a0, excsave1: a3
38099d5040eSMax Filippov	 */
38199d5040eSMax Filippov_DoubleExceptionVector_WindowOverflow:
38299d5040eSMax Filippov	extui	a2, a0, 0, 6	# get offset into 64-byte vector handler
38399d5040eSMax Filippov	beqz	a2, 1f		# if at start of vector, don't restore
38499d5040eSMax Filippov
38599d5040eSMax Filippov	addi	a0, a0, -128
38617290231SMax Filippov	bbsi.l	a0, 8, 1f	# don't restore except for overflow 8 and 12
38717290231SMax Filippov
38817290231SMax Filippov	/*
38917290231SMax Filippov	 * This fixup handler is for the extremely unlikely case where the
39017290231SMax Filippov	 * overflow handler's reference thru a0 gets a hardware TLB refill
39117290231SMax Filippov	 * that bumps out the (distinct, aliasing) TLB entry that mapped its
39217290231SMax Filippov	 * prior references thru a9/a13, and where our reference now thru
39317290231SMax Filippov	 * a9/a13 gets a 2nd-level miss exception (not hardware TLB refill).
39417290231SMax Filippov	 */
39517290231SMax Filippov	movi	a2, window_overflow_restore_a0_fixup
39617290231SMax Filippov	s32i	a2, a3, EXC_TABLE_FIXUP
39717290231SMax Filippov	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
39817290231SMax Filippov	xsr	a3, excsave1
39917290231SMax Filippov
40017290231SMax Filippov	bbsi.l	a0, 7, 2f
40199d5040eSMax Filippov
40299d5040eSMax Filippov	/*
40399d5040eSMax Filippov	 * Restore a0 as saved by _WindowOverflow8().
40499d5040eSMax Filippov	 */
40599d5040eSMax Filippov
40617290231SMax Filippov	l32e	a0, a9, -16
40717290231SMax Filippov	wsr	a0, depc	# replace the saved a0
40817290231SMax Filippov	j	3f
40999d5040eSMax Filippov
41099d5040eSMax Filippov2:
41199d5040eSMax Filippov	/*
41299d5040eSMax Filippov	 * Restore a0 as saved by _WindowOverflow12().
41399d5040eSMax Filippov	 */
41499d5040eSMax Filippov
41517290231SMax Filippov	l32e	a0, a13, -16
41617290231SMax Filippov	wsr	a0, depc	# replace the saved a0
41717290231SMax Filippov3:
41817290231SMax Filippov	xsr	a3, excsave1
41917290231SMax Filippov	movi	a0, 0
42017290231SMax Filippov	s32i	a0, a3, EXC_TABLE_FIXUP
42117290231SMax Filippov	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
42299d5040eSMax Filippov1:
42399d5040eSMax Filippov	/*
42499d5040eSMax Filippov	 * Restore WindowBase while leaving all address registers restored.
42599d5040eSMax Filippov	 * We have to use ROTW for this, because WSR.WINDOWBASE requires
42699d5040eSMax Filippov	 * an address register (which would prevent restore).
42799d5040eSMax Filippov	 *
42899d5040eSMax Filippov	 * Window Base goes from 0 ... 7 (Module 8)
42999d5040eSMax Filippov	 * Window Start is 8 bits; Ex: (0b1010 1010):0x55 from series of call4s
43099d5040eSMax Filippov	 */
43199d5040eSMax Filippov
43299d5040eSMax Filippov	rsr	a0, ps
43399d5040eSMax Filippov	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
43499d5040eSMax Filippov	rsr	a2, windowbase
43599d5040eSMax Filippov	sub	a0, a2, a0
43699d5040eSMax Filippov	extui	a0, a0, 0, 3
43799d5040eSMax Filippov
43899d5040eSMax Filippov	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
43999d5040eSMax Filippov	xsr	a3, excsave1
44099d5040eSMax Filippov	beqi	a0, 1, .L1pane
44199d5040eSMax Filippov	beqi	a0, 3, .L3pane
44299d5040eSMax Filippov
44399d5040eSMax Filippov	rsr	a0, depc
44499d5040eSMax Filippov	rotw	-2
44599d5040eSMax Filippov
44699d5040eSMax Filippov	/*
44799d5040eSMax Filippov	 * We are now in the user code's original window frame.
44899d5040eSMax Filippov	 * Process the exception as a user exception as if it was
44999d5040eSMax Filippov	 * taken by the user code.
45099d5040eSMax Filippov	 *
45199d5040eSMax Filippov	 * This is similar to the user exception vector,
45299d5040eSMax Filippov	 * except that PT_DEPC isn't set to EXCCAUSE.
45399d5040eSMax Filippov	 */
45499d5040eSMax Filippov1:
45599d5040eSMax Filippov	xsr	a3, excsave1
45699d5040eSMax Filippov	wsr	a2, depc
45799d5040eSMax Filippov	l32i	a2, a3, EXC_TABLE_KSTK
45899d5040eSMax Filippov	s32i	a0, a2, PT_AREG0
45999d5040eSMax Filippov	rsr	a0, exccause
46099d5040eSMax Filippov
46199d5040eSMax Filippov	s32i	a0, a2, PT_DEPC
46299d5040eSMax Filippov
46317290231SMax Filippov_DoubleExceptionVector_handle_exception:
4643cfc096eSMax Filippov	addi	a0, a0, -EXCCAUSE_UNALIGNED
4653cfc096eSMax Filippov	beqz	a0, 2f
46699d5040eSMax Filippov	addx4	a0, a0, a3
4673cfc096eSMax Filippov	l32i	a0, a0, EXC_TABLE_FAST_USER + 4 * EXCCAUSE_UNALIGNED
4683cfc096eSMax Filippov	xsr	a3, excsave1
4693cfc096eSMax Filippov	jx	a0
4703cfc096eSMax Filippov2:
4713cfc096eSMax Filippov	movi	a0, user_exception
47299d5040eSMax Filippov	xsr	a3, excsave1
47399d5040eSMax Filippov	jx	a0
47499d5040eSMax Filippov
47599d5040eSMax Filippov.L1pane:
47699d5040eSMax Filippov	rsr	a0, depc
47799d5040eSMax Filippov	rotw	-1
47899d5040eSMax Filippov	j	1b
47999d5040eSMax Filippov
48099d5040eSMax Filippov.L3pane:
48199d5040eSMax Filippov	rsr	a0, depc
48299d5040eSMax Filippov	rotw	-3
48399d5040eSMax Filippov	j	1b
484da0a4e5cSMax Filippov#endif
48599d5040eSMax Filippov
486d1538c46SChris ZankelENDPROC(_DoubleExceptionVector)
4875a0015d6SChris Zankel
488da0a4e5cSMax Filippov#ifdef SUPPORT_WINDOWED
489da0a4e5cSMax Filippov
4905a0015d6SChris Zankel/*
49117290231SMax Filippov * Fixup handler for TLB miss in double exception handler for window owerflow.
49217290231SMax Filippov * We get here with windowbase set to the window that was being spilled and
49317290231SMax Filippov * a0 trashed. a0 bit 7 determines if this is a call8 (bit clear) or call12
49417290231SMax Filippov * (bit set) window.
49517290231SMax Filippov *
49617290231SMax Filippov * We do the following here:
49717290231SMax Filippov * - go to the original window retaining a0 value;
49817290231SMax Filippov * - set up exception stack to return back to appropriate a0 restore code
49917290231SMax Filippov *   (we'll need to rotate window back and there's no place to save this
50017290231SMax Filippov *    information, use different return address for that);
50117290231SMax Filippov * - handle the exception;
50217290231SMax Filippov * - go to the window that was being spilled;
50317290231SMax Filippov * - set up window_overflow_restore_a0_fixup as a fixup routine;
50417290231SMax Filippov * - reload a0;
50517290231SMax Filippov * - restore the original window;
50617290231SMax Filippov * - reset the default fixup routine;
50717290231SMax Filippov * - return to user. By the time we get to this fixup handler all information
50817290231SMax Filippov *   about the conditions of the original double exception that happened in
50917290231SMax Filippov *   the window overflow handler is lost, so we just return to userspace to
51017290231SMax Filippov *   retry overflow from start.
51117290231SMax Filippov *
51217290231SMax Filippov * a0: value of depc, original value in depc
51317290231SMax Filippov * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
51417290231SMax Filippov * a3: exctable, original value in excsave1
51517290231SMax Filippov */
51617290231SMax Filippov
51750722f0bSMax Filippov	__XTENSA_HANDLER
518f8f02ca7SMax Filippov	.literal_position
519f8f02ca7SMax Filippov
52017290231SMax FilippovENTRY(window_overflow_restore_a0_fixup)
52117290231SMax Filippov
52217290231SMax Filippov	rsr	a0, ps
52317290231SMax Filippov	extui	a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
52417290231SMax Filippov	rsr	a2, windowbase
52517290231SMax Filippov	sub	a0, a2, a0
52617290231SMax Filippov	extui	a0, a0, 0, 3
52717290231SMax Filippov	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
52817290231SMax Filippov	xsr	a3, excsave1
52917290231SMax Filippov
53017290231SMax Filippov	_beqi	a0, 1, .Lhandle_1
53117290231SMax Filippov	_beqi	a0, 3, .Lhandle_3
53217290231SMax Filippov
53317290231SMax Filippov	.macro	overflow_fixup_handle_exception_pane n
53417290231SMax Filippov
53517290231SMax Filippov	rsr	a0, depc
53617290231SMax Filippov	rotw	-\n
53717290231SMax Filippov
53817290231SMax Filippov	xsr	a3, excsave1
53917290231SMax Filippov	wsr	a2, depc
54017290231SMax Filippov	l32i	a2, a3, EXC_TABLE_KSTK
54117290231SMax Filippov	s32i	a0, a2, PT_AREG0
54217290231SMax Filippov
54317290231SMax Filippov	movi	a0, .Lrestore_\n
54417290231SMax Filippov	s32i	a0, a2, PT_DEPC
54517290231SMax Filippov	rsr	a0, exccause
54617290231SMax Filippov	j	_DoubleExceptionVector_handle_exception
54717290231SMax Filippov
54817290231SMax Filippov	.endm
54917290231SMax Filippov
55017290231SMax Filippov	overflow_fixup_handle_exception_pane 2
55117290231SMax Filippov.Lhandle_1:
55217290231SMax Filippov	overflow_fixup_handle_exception_pane 1
55317290231SMax Filippov.Lhandle_3:
55417290231SMax Filippov	overflow_fixup_handle_exception_pane 3
55517290231SMax Filippov
55617290231SMax Filippov	.macro	overflow_fixup_restore_a0_pane n
55717290231SMax Filippov
55817290231SMax Filippov	rotw	\n
55917290231SMax Filippov	/* Need to preserve a0 value here to be able to handle exception
56017290231SMax Filippov	 * that may occur on a0 reload from stack. It may occur because
56117290231SMax Filippov	 * TLB miss handler may not be atomic and pointer to page table
56217290231SMax Filippov	 * may be lost before we get here. There are no free registers,
56317290231SMax Filippov	 * so we need to use EXC_TABLE_DOUBLE_SAVE area.
56417290231SMax Filippov	 */
56517290231SMax Filippov	xsr	a3, excsave1
56617290231SMax Filippov	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
56717290231SMax Filippov	movi	a2, window_overflow_restore_a0_fixup
56817290231SMax Filippov	s32i	a2, a3, EXC_TABLE_FIXUP
56917290231SMax Filippov	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
57017290231SMax Filippov	xsr	a3, excsave1
57117290231SMax Filippov	bbsi.l	a0, 7, 1f
57217290231SMax Filippov	l32e	a0, a9, -16
57317290231SMax Filippov	j	2f
57417290231SMax Filippov1:
57517290231SMax Filippov	l32e	a0, a13, -16
57617290231SMax Filippov2:
57717290231SMax Filippov	rotw	-\n
57817290231SMax Filippov
57917290231SMax Filippov	.endm
58017290231SMax Filippov
58117290231SMax Filippov.Lrestore_2:
58217290231SMax Filippov	overflow_fixup_restore_a0_pane 2
58317290231SMax Filippov
58417290231SMax Filippov.Lset_default_fixup:
58517290231SMax Filippov	xsr	a3, excsave1
58617290231SMax Filippov	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
58717290231SMax Filippov	movi	a2, 0
58817290231SMax Filippov	s32i	a2, a3, EXC_TABLE_FIXUP
58917290231SMax Filippov	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
59017290231SMax Filippov	xsr	a3, excsave1
59117290231SMax Filippov	rfe
59217290231SMax Filippov
59317290231SMax Filippov.Lrestore_1:
59417290231SMax Filippov	overflow_fixup_restore_a0_pane 1
59517290231SMax Filippov	j	.Lset_default_fixup
59617290231SMax Filippov.Lrestore_3:
59717290231SMax Filippov	overflow_fixup_restore_a0_pane 3
59817290231SMax Filippov	j	.Lset_default_fixup
59917290231SMax Filippov
60017290231SMax FilippovENDPROC(window_overflow_restore_a0_fixup)
60117290231SMax Filippov
602da0a4e5cSMax Filippov#endif
603da0a4e5cSMax Filippov
60417290231SMax Filippov/*
6055a0015d6SChris Zankel * Debug interrupt vector
6065a0015d6SChris Zankel *
6075a0015d6SChris Zankel * There is not much space here, so simply jump to another handler.
6085a0015d6SChris Zankel * EXCSAVE[DEBUGLEVEL] has been set to that handler.
6095a0015d6SChris Zankel */
6105a0015d6SChris Zankel
6115a0015d6SChris Zankel	.section .DebugInterruptVector.text, "ax"
6125a0015d6SChris Zankel
6135a0015d6SChris ZankelENTRY(_DebugInterruptVector)
614d1538c46SChris Zankel
6156ec7026aSMax Filippov	xsr	a3, SREG_EXCSAVE + XCHAL_DEBUGLEVEL
6166ec7026aSMax Filippov	s32i	a0, a3, DT_DEBUG_SAVE
6176ec7026aSMax Filippov	l32i	a0, a3, DT_DEBUG_EXCEPTION
6185a0015d6SChris Zankel	jx	a0
6195a0015d6SChris Zankel
620d1538c46SChris ZankelENDPROC(_DebugInterruptVector)
6215a0015d6SChris Zankel
6225a0015d6SChris Zankel
6232d1c645cSMarc Gauthier
6242d1c645cSMarc Gauthier/*
6252d1c645cSMarc Gauthier * Medium priority level interrupt vectors
6262d1c645cSMarc Gauthier *
6272d1c645cSMarc Gauthier * Each takes less than 16 (0x10) bytes, no literals, by placing
6282d1c645cSMarc Gauthier * the extra 8 bytes that would otherwise be required in the window
6292d1c645cSMarc Gauthier * vectors area where there is space.  With relocatable vectors,
6302d1c645cSMarc Gauthier * all vectors are within ~ 4 kB range of each other, so we can
6312d1c645cSMarc Gauthier * simply jump (J) to another vector without having to use JX.
6322d1c645cSMarc Gauthier *
6332d1c645cSMarc Gauthier * common_exception code gets current IRQ level in PS.INTLEVEL
6342d1c645cSMarc Gauthier * and preserves it for the IRQ handling time.
6352d1c645cSMarc Gauthier */
6362d1c645cSMarc Gauthier
6372d1c645cSMarc Gauthier	.macro	irq_entry_level level
6382d1c645cSMarc Gauthier
6392d1c645cSMarc Gauthier	.if	XCHAL_EXCM_LEVEL >= \level
6402d1c645cSMarc Gauthier	.section .Level\level\()InterruptVector.text, "ax"
6412d1c645cSMarc GauthierENTRY(_Level\level\()InterruptVector)
642895666a9SMax Filippov	wsr	a0, excsave2
6432d1c645cSMarc Gauthier	rsr	a0, epc\level
644895666a9SMax Filippov	wsr	a0, epc1
64538fef73cSMax Filippov	.if	\level <= LOCKLEVEL
646895666a9SMax Filippov	movi	a0, EXCCAUSE_LEVEL1_INTERRUPT
64738fef73cSMax Filippov	.else
64838fef73cSMax Filippov	movi	a0, EXCCAUSE_MAPPED_NMI
64938fef73cSMax Filippov	.endif
650895666a9SMax Filippov	wsr	a0, exccause
651895666a9SMax Filippov	rsr	a0, eps\level
6522d1c645cSMarc Gauthier					# branch to user or kernel vector
6532d1c645cSMarc Gauthier	j	_SimulateUserKernelVectorException
6542d1c645cSMarc Gauthier	.endif
6552d1c645cSMarc Gauthier
6562d1c645cSMarc Gauthier	.endm
6572d1c645cSMarc Gauthier
6582d1c645cSMarc Gauthier	irq_entry_level 2
6592d1c645cSMarc Gauthier	irq_entry_level 3
6602d1c645cSMarc Gauthier	irq_entry_level 4
6612d1c645cSMarc Gauthier	irq_entry_level 5
6622d1c645cSMarc Gauthier	irq_entry_level 6
6632d1c645cSMarc Gauthier
664e369953aSMax Filippov#if XCHAL_EXCM_LEVEL >= 2
665e369953aSMax Filippov	/*
666e369953aSMax Filippov	 *  Continuation of medium priority interrupt dispatch code.
667e369953aSMax Filippov	 *  On entry here, a0 contains PS, and EPC2 contains saved a0:
668e369953aSMax Filippov	 */
669e369953aSMax Filippov	__XTENSA_HANDLER
670e369953aSMax Filippov	.align 4
671e369953aSMax Filippov_SimulateUserKernelVectorException:
672e369953aSMax Filippov	addi	a0, a0, (1 << PS_EXCM_BIT)
673e369953aSMax Filippov#if !XTENSA_FAKE_NMI
674e369953aSMax Filippov	wsr	a0, ps
675e369953aSMax Filippov#endif
676e369953aSMax Filippov	bbsi.l	a0, PS_UM_BIT, 1f	# branch if user mode
677e369953aSMax Filippov	xsr	a0, excsave2		# restore a0
678e369953aSMax Filippov	j	_KernelExceptionVector	# simulate kernel vector exception
679e369953aSMax Filippov1:	xsr	a0, excsave2		# restore a0
680e369953aSMax Filippov	j	_UserExceptionVector	# simulate user vector exception
681e369953aSMax Filippov#endif
682e369953aSMax Filippov
6832d1c645cSMarc Gauthier
6845a0015d6SChris Zankel/* Window overflow and underflow handlers.
6855a0015d6SChris Zankel * The handlers must be 64 bytes apart, first starting with the underflow
6865a0015d6SChris Zankel * handlers underflow-4 to underflow-12, then the overflow handlers
6875a0015d6SChris Zankel * overflow-4 to overflow-12.
6885a0015d6SChris Zankel *
6895a0015d6SChris Zankel * Note: We rerun the underflow handlers if we hit an exception, so
6905a0015d6SChris Zankel *	 we try to access any page that would cause a page fault early.
6915a0015d6SChris Zankel */
6925a0015d6SChris Zankel
693d1538c46SChris Zankel#define ENTRY_ALIGN64(name)	\
694d1538c46SChris Zankel	.globl name;		\
695d1538c46SChris Zankel	.align 64;		\
696d1538c46SChris Zankel	name:
697d1538c46SChris Zankel
6985a0015d6SChris Zankel	.section		.WindowVectors.text, "ax"
6995a0015d6SChris Zankel
7005a0015d6SChris Zankel
701da0a4e5cSMax Filippov#ifdef SUPPORT_WINDOWED
702da0a4e5cSMax Filippov
7035a0015d6SChris Zankel/* 4-Register Window Overflow Vector (Handler) */
7045a0015d6SChris Zankel
705d1538c46SChris ZankelENTRY_ALIGN64(_WindowOverflow4)
706d1538c46SChris Zankel
7075a0015d6SChris Zankel	s32e	a0, a5, -16
7085a0015d6SChris Zankel	s32e	a1, a5, -12
7095a0015d6SChris Zankel	s32e	a2, a5,  -8
7105a0015d6SChris Zankel	s32e	a3, a5,  -4
7115a0015d6SChris Zankel	rfwo
7125a0015d6SChris Zankel
713d1538c46SChris ZankelENDPROC(_WindowOverflow4)
714d1538c46SChris Zankel
7155a0015d6SChris Zankel/* 4-Register Window Underflow Vector (Handler) */
7165a0015d6SChris Zankel
717d1538c46SChris ZankelENTRY_ALIGN64(_WindowUnderflow4)
718d1538c46SChris Zankel
7195a0015d6SChris Zankel	l32e	a0, a5, -16
7205a0015d6SChris Zankel	l32e	a1, a5, -12
7215a0015d6SChris Zankel	l32e	a2, a5,  -8
7225a0015d6SChris Zankel	l32e	a3, a5,  -4
7235a0015d6SChris Zankel	rfwu
7245a0015d6SChris Zankel
725d1538c46SChris ZankelENDPROC(_WindowUnderflow4)
7265a0015d6SChris Zankel
7275a0015d6SChris Zankel/* 8-Register Window Overflow Vector (Handler) */
7285a0015d6SChris Zankel
729d1538c46SChris ZankelENTRY_ALIGN64(_WindowOverflow8)
730d1538c46SChris Zankel
7315a0015d6SChris Zankel	s32e	a0, a9, -16
7325a0015d6SChris Zankel	l32e	a0, a1, -12
7335a0015d6SChris Zankel	s32e	a2, a9,  -8
7345a0015d6SChris Zankel	s32e	a1, a9, -12
7355a0015d6SChris Zankel	s32e	a3, a9,  -4
7365a0015d6SChris Zankel	s32e	a4, a0, -32
7375a0015d6SChris Zankel	s32e	a5, a0, -28
7385a0015d6SChris Zankel	s32e	a6, a0, -24
7395a0015d6SChris Zankel	s32e	a7, a0, -20
7405a0015d6SChris Zankel	rfwo
7415a0015d6SChris Zankel
742d1538c46SChris ZankelENDPROC(_WindowOverflow8)
743d1538c46SChris Zankel
7445a0015d6SChris Zankel/* 8-Register Window Underflow Vector (Handler) */
7455a0015d6SChris Zankel
746d1538c46SChris ZankelENTRY_ALIGN64(_WindowUnderflow8)
747d1538c46SChris Zankel
7485a0015d6SChris Zankel	l32e	a1, a9, -12
7495a0015d6SChris Zankel	l32e	a0, a9, -16
7505a0015d6SChris Zankel	l32e	a7, a1, -12
7515a0015d6SChris Zankel	l32e	a2, a9,  -8
7525a0015d6SChris Zankel	l32e	a4, a7, -32
7535a0015d6SChris Zankel	l32e	a3, a9,  -4
7545a0015d6SChris Zankel	l32e	a5, a7, -28
7555a0015d6SChris Zankel	l32e	a6, a7, -24
7565a0015d6SChris Zankel	l32e	a7, a7, -20
7575a0015d6SChris Zankel	rfwu
7585a0015d6SChris Zankel
759d1538c46SChris ZankelENDPROC(_WindowUnderflow8)
7605a0015d6SChris Zankel
7615a0015d6SChris Zankel/* 12-Register Window Overflow Vector (Handler) */
7625a0015d6SChris Zankel
763d1538c46SChris ZankelENTRY_ALIGN64(_WindowOverflow12)
764d1538c46SChris Zankel
7655a0015d6SChris Zankel	s32e	a0,  a13, -16
7665a0015d6SChris Zankel	l32e	a0,  a1,  -12
7675a0015d6SChris Zankel	s32e	a1,  a13, -12
7685a0015d6SChris Zankel	s32e	a2,  a13,  -8
7695a0015d6SChris Zankel	s32e	a3,  a13,  -4
7705a0015d6SChris Zankel	s32e	a4,  a0,  -48
7715a0015d6SChris Zankel	s32e	a5,  a0,  -44
7725a0015d6SChris Zankel	s32e	a6,  a0,  -40
7735a0015d6SChris Zankel	s32e	a7,  a0,  -36
7745a0015d6SChris Zankel	s32e	a8,  a0,  -32
7755a0015d6SChris Zankel	s32e	a9,  a0,  -28
7765a0015d6SChris Zankel	s32e	a10, a0,  -24
7775a0015d6SChris Zankel	s32e	a11, a0,  -20
7785a0015d6SChris Zankel	rfwo
7795a0015d6SChris Zankel
780d1538c46SChris ZankelENDPROC(_WindowOverflow12)
781d1538c46SChris Zankel
7825a0015d6SChris Zankel/* 12-Register Window Underflow Vector (Handler) */
7835a0015d6SChris Zankel
784d1538c46SChris ZankelENTRY_ALIGN64(_WindowUnderflow12)
785d1538c46SChris Zankel
7865a0015d6SChris Zankel	l32e	a1,  a13, -12
7875a0015d6SChris Zankel	l32e	a0,  a13, -16
7885a0015d6SChris Zankel	l32e	a11, a1,  -12
7895a0015d6SChris Zankel	l32e	a2,  a13,  -8
7905a0015d6SChris Zankel	l32e	a4,  a11, -48
7915a0015d6SChris Zankel	l32e	a8,  a11, -32
7925a0015d6SChris Zankel	l32e	a3,  a13,  -4
7935a0015d6SChris Zankel	l32e	a5,  a11, -44
7945a0015d6SChris Zankel	l32e	a6,  a11, -40
7955a0015d6SChris Zankel	l32e	a7,  a11, -36
7965a0015d6SChris Zankel	l32e	a9,  a11, -28
7975a0015d6SChris Zankel	l32e	a10, a11, -24
7985a0015d6SChris Zankel	l32e	a11, a11, -20
7995a0015d6SChris Zankel	rfwu
8005a0015d6SChris Zankel
801d1538c46SChris ZankelENDPROC(_WindowUnderflow12)
802d1538c46SChris Zankel
803da0a4e5cSMax Filippov#endif
804da0a4e5cSMax Filippov
8055a0015d6SChris Zankel	.text
806