| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 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 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 <asm/ptrace.h> | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 47 | #include <asm/current.h> | 
| Sam Ravnborg | 0013a85 | 2005-09-09 20:57:26 +0200 | [diff] [blame] | 48 | #include <asm/asm-offsets.h> | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 49 | #include <asm/pgtable.h> | 
 | 50 | #include <asm/processor.h> | 
 | 51 | #include <asm/page.h> | 
 | 52 | #include <asm/thread_info.h> | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 53 |  | 
| Chris Zankel | 173d668 | 2006-12-10 02:18:48 -0800 | [diff] [blame] | 54 | #define WINDOW_VECTORS_SIZE   0x180 | 
 | 55 |  | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 56 |  | 
 | 57 | /* | 
 | 58 |  * User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0) | 
 | 59 |  * | 
 | 60 |  * We get here when an exception occurred while we were in userland. | 
 | 61 |  * We switch to the kernel stack and jump to the first level handler | 
 | 62 |  * associated to the exception cause. | 
 | 63 |  * | 
 | 64 |  * Note: the saved kernel stack pointer (EXC_TABLE_KSTK) is already | 
 | 65 |  *       decremented by PT_USER_SIZE. | 
 | 66 |  */ | 
 | 67 |  | 
 | 68 | 	.section .UserExceptionVector.text, "ax" | 
 | 69 |  | 
 | 70 | ENTRY(_UserExceptionVector) | 
 | 71 |  | 
 | 72 | 	xsr	a3, EXCSAVE_1		# save a3 and get dispatch table | 
 | 73 | 	wsr	a2, DEPC		# save a2 | 
 | 74 | 	l32i	a2, a3, EXC_TABLE_KSTK	# load kernel stack to a2 | 
 | 75 | 	s32i	a0, a2, PT_AREG0	# save a0 to ESF | 
 | 76 | 	rsr	a0, EXCCAUSE		# retrieve exception cause | 
 | 77 | 	s32i	a0, a2, PT_DEPC		# mark it as a regular exception | 
 | 78 | 	addx4	a0, a0, a3		# find entry in table | 
 | 79 | 	l32i	a0, a0, EXC_TABLE_FAST_USER	# load handler | 
 | 80 | 	jx	a0 | 
 | 81 |  | 
 | 82 | /* | 
 | 83 |  * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0) | 
 | 84 |  * | 
 | 85 |  * We get this exception when we were already in kernel space. | 
 | 86 |  * We decrement the current stack pointer (kernel) by PT_SIZE and | 
 | 87 |  * jump to the first-level handler associated with the exception cause. | 
 | 88 |  * | 
 | 89 |  * Note: we need to preserve space for the spill region. | 
 | 90 |  */ | 
 | 91 |  | 
 | 92 | 	.section .KernelExceptionVector.text, "ax" | 
 | 93 |  | 
 | 94 | ENTRY(_KernelExceptionVector) | 
 | 95 |  | 
 | 96 | 	xsr	a3, EXCSAVE_1		# save a3, and get dispatch table | 
 | 97 | 	wsr	a2, DEPC		# save a2 | 
 | 98 | 	addi	a2, a1, -16-PT_SIZE	# adjust stack pointer | 
 | 99 | 	s32i	a0, a2, PT_AREG0	# save a0 to ESF | 
 | 100 | 	rsr	a0, EXCCAUSE		# retrieve exception cause | 
 | 101 | 	s32i	a0, a2, PT_DEPC		# mark it as a regular exception | 
 | 102 | 	addx4	a0, a0, a3		# find entry in table | 
 | 103 | 	l32i	a0, a0, EXC_TABLE_FAST_KERNEL	# load handler address | 
 | 104 | 	jx	a0 | 
 | 105 |  | 
 | 106 |  | 
 | 107 | /* | 
 | 108 |  * Double exception vector (Exceptions with PS.EXCM == 1) | 
 | 109 |  * We get this exception when another exception occurs while were are | 
 | 110 |  * already in an exception, such as window overflow/underflow exception, | 
 | 111 |  * or 'expected' exceptions, for example memory exception when we were trying | 
 | 112 |  * to read data from an invalid address in user space. | 
 | 113 |  * | 
 | 114 |  * Note that this vector is never invoked for level-1 interrupts, because such | 
 | 115 |  * interrupts are disabled (masked) when PS.EXCM is set. | 
 | 116 |  * | 
 | 117 |  * We decode the exception and take the appropriate action.  However, the | 
 | 118 |  * double exception vector is much more careful, because a lot more error | 
 | 119 |  * cases go through the double exception vector than through the user and | 
 | 120 |  * kernel exception vectors. | 
 | 121 |  * | 
 | 122 |  * Occasionally, the kernel expects a double exception to occur.  This usually | 
 | 123 |  * happens when accessing user-space memory with the user's permissions | 
 | 124 |  * (l32e/s32e instructions).  The kernel state, though, is not always suitable | 
 | 125 |  * for immediate transfer of control to handle_double, where "normal" exception | 
 | 126 |  * processing occurs. Also in kernel mode, TLB misses can occur if accessing | 
 | 127 |  * vmalloc memory, possibly requiring repair in a double exception handler. | 
 | 128 |  * | 
 | 129 |  * The variable at TABLE_FIXUP offset from the pointer in EXCSAVE_1 doubles as | 
 | 130 |  * a boolean variable and a pointer to a fixup routine. If the variable | 
 | 131 |  * EXC_TABLE_FIXUP is non-zero, this handler jumps to that address. A value of | 
 | 132 |  * zero indicates to use the default kernel/user exception handler. | 
 | 133 |  * There is only one exception, when the value is identical to the exc_table | 
 | 134 |  * label, the kernel is in trouble. This mechanism is used to protect critical | 
 | 135 |  * sections, mainly when the handler writes to the stack to assert the stack | 
 | 136 |  * pointer is valid. Once the fixup/default handler leaves that area, the | 
 | 137 |  * EXC_TABLE_FIXUP variable is reset to the fixup handler or zero. | 
 | 138 |  * | 
 | 139 |  * Procedures wishing to use this mechanism should set EXC_TABLE_FIXUP to the | 
 | 140 |  * nonzero address of a fixup routine before it could cause a double exception | 
 | 141 |  * and reset it before it returns. | 
 | 142 |  * | 
 | 143 |  * Some other things to take care of when a fast exception handler doesn't | 
 | 144 |  * specify a particular fixup handler but wants to use the default handlers: | 
 | 145 |  * | 
 | 146 |  *  - The original stack pointer (in a1) must not be modified. The fast | 
 | 147 |  *    exception handler should only use a2 as the stack pointer. | 
 | 148 |  * | 
 | 149 |  *  - If the fast handler manipulates the stack pointer (in a2), it has to | 
 | 150 |  *    register a valid fixup handler and cannot use the default handlers. | 
 | 151 |  * | 
 | 152 |  *  - The handler can use any other generic register from a3 to a15, but it | 
 | 153 |  *    must save the content of these registers to stack (PT_AREG3...PT_AREGx) | 
 | 154 |  * | 
 | 155 |  *  - These registers must be saved before a double exception can occur. | 
 | 156 |  * | 
 | 157 |  *  - If we ever implement handling signals while in double exceptions, the | 
 | 158 |  *    number of registers a fast handler has saved (excluding a0 and a1) must | 
 | 159 |  *    be written to  PT_AREG1. (1 if only a3 is used, 2 for a3 and a4, etc. ) | 
 | 160 |  * | 
 | 161 |  * The fixup handlers are special handlers: | 
 | 162 |  * | 
 | 163 |  *  - Fixup entry conditions differ from regular exceptions: | 
 | 164 |  * | 
 | 165 |  *	a0:	   DEPC | 
 | 166 |  *	a1: 	   a1 | 
 | 167 |  *	a2:	   trashed, original value in EXC_TABLE_DOUBLE_A2 | 
 | 168 |  *	a3:	   exctable | 
 | 169 |  *	depc:	   a0 | 
 | 170 |  *	excsave_1: a3 | 
 | 171 |  * | 
 | 172 |  *  - When the kernel enters the fixup handler, it still assumes it is in a | 
 | 173 |  *    critical section, so EXC_TABLE_FIXUP variable is set to exc_table. | 
 | 174 |  *    The fixup handler, therefore, has to re-register itself as the fixup | 
 | 175 |  *    handler before it returns from the double exception. | 
 | 176 |  * | 
 | 177 |  *  - Fixup handler can share the same exception frame with the fast handler. | 
 | 178 |  *    The kernel stack pointer is not changed when entering the fixup handler. | 
 | 179 |  * | 
 | 180 |  *  - Fixup handlers can jump to the default kernel and user exception | 
 | 181 |  *    handlers. Before it jumps, though, it has to setup a exception frame | 
 | 182 |  *    on stack. Because the default handler resets the register fixup handler | 
 | 183 |  *    the fixup handler must make sure that the default handler returns to | 
 | 184 |  *    it instead of the exception address, so it can re-register itself as | 
 | 185 |  *    the fixup handler. | 
 | 186 |  * | 
 | 187 |  * In case of a critical condition where the kernel cannot recover, we jump | 
 | 188 |  * to unrecoverable_exception with the following entry conditions. | 
 | 189 |  * All registers a0...a15 are unchanged from the last exception, except: | 
 | 190 |  * | 
 | 191 |  *	a0:	   last address before we jumped to the unrecoverable_exception. | 
 | 192 |  *	excsave_1: a0 | 
 | 193 |  * | 
 | 194 |  * | 
 | 195 |  * See the handle_alloca_user and spill_registers routines for example clients. | 
 | 196 |  * | 
 | 197 |  * FIXME: Note: we currently don't allow signal handling coming from a double | 
 | 198 |  *        exception, so the item markt with (*) is not required. | 
 | 199 |  */ | 
 | 200 |  | 
 | 201 | 	.section .DoubleExceptionVector.text, "ax" | 
 | 202 | 	.begin literal_prefix .DoubleExceptionVector | 
 | 203 |  | 
 | 204 | ENTRY(_DoubleExceptionVector) | 
 | 205 |  | 
 | 206 | 	/* Deliberately destroy excsave (don't assume it's value was valid). */ | 
 | 207 |  | 
 | 208 | 	wsr	a3, EXCSAVE_1		# save a3 | 
 | 209 |  | 
 | 210 | 	/* Check for kernel double exception (usually fatal). */ | 
 | 211 |  | 
 | 212 | 	rsr	a3, PS | 
| Chris Zankel | 173d668 | 2006-12-10 02:18:48 -0800 | [diff] [blame] | 213 | 	_bbci.l	a3, PS_UM_BIT, .Lksp | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 214 |  | 
 | 215 | 	/* Check if we are currently handling a window exception. */ | 
 | 216 | 	/* Note: We don't need to indicate that we enter a critical section. */ | 
 | 217 |  | 
 | 218 | 	xsr	a0, DEPC		# get DEPC, save a0 | 
 | 219 |  | 
 | 220 | 	movi	a3, XCHAL_WINDOW_VECTORS_VADDR | 
 | 221 | 	_bltu	a0, a3, .Lfixup | 
| Chris Zankel | 173d668 | 2006-12-10 02:18:48 -0800 | [diff] [blame] | 222 | 	addi	a3, a3, WINDOW_VECTORS_SIZE | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 223 | 	_bgeu	a0, a3, .Lfixup | 
 | 224 |  | 
 | 225 | 	/* Window overflow/underflow exception. Get stack pointer. */ | 
 | 226 |  | 
 | 227 | 	mov	a3, a2 | 
 | 228 | 	movi	a2, exc_table | 
 | 229 | 	l32i	a2, a2, EXC_TABLE_KSTK | 
 | 230 |  | 
 | 231 | 	/* Check for overflow/underflow exception, jump if overflow. */ | 
 | 232 |  | 
 | 233 | 	_bbci.l	a0, 6, .Lovfl | 
 | 234 |  | 
 | 235 | 	/* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3  */ | 
 | 236 |  | 
 | 237 | 	/* Restart window underflow exception. | 
 | 238 | 	 * We return to the instruction in user space that caused the window | 
 | 239 | 	 * underflow exception. Therefore, we change window base to the value | 
 | 240 | 	 * before we entered the window underflow exception and prepare the | 
 | 241 | 	 * registers to return as if we were coming from a regular exception | 
 | 242 | 	 * by changing depc (in a0). | 
 | 243 | 	 * Note: We can trash the current window frame (a0...a3) and depc! | 
 | 244 | 	 */ | 
 | 245 |  | 
 | 246 | 	wsr	a2, DEPC		# save stack pointer temporarily | 
 | 247 | 	rsr	a0, PS | 
| Chris Zankel | 173d668 | 2006-12-10 02:18:48 -0800 | [diff] [blame] | 248 | 	extui	a0, a0, PS_OWB_SHIFT, 4 | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 249 | 	wsr	a0, WINDOWBASE | 
 | 250 | 	rsync | 
 | 251 |  | 
 | 252 | 	/* We are now in the previous window frame. Save registers again. */ | 
 | 253 |  | 
 | 254 | 	xsr	a2, DEPC		# save a2 and get stack pointer | 
 | 255 | 	s32i	a0, a2, PT_AREG0 | 
 | 256 |  | 
 | 257 | 	wsr	a3, EXCSAVE_1		# save a3 | 
 | 258 | 	movi	a3, exc_table | 
 | 259 |  | 
 | 260 | 	rsr	a0, EXCCAUSE | 
 | 261 | 	s32i	a0, a2, PT_DEPC		# mark it as a regular exception | 
 | 262 | 	addx4	a0, a0, a3 | 
 | 263 | 	l32i	a0, a0, EXC_TABLE_FAST_USER | 
 | 264 | 	jx	a0 | 
 | 265 |  | 
 | 266 | .Lfixup:/* Check for a fixup handler or if we were in a critical section. */ | 
 | 267 |  | 
 | 268 | 	/* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */ | 
 | 269 |  | 
 | 270 | 	movi	a3, exc_table | 
 | 271 | 	s32i	a2, a3, EXC_TABLE_DOUBLE_SAVE	# temporary variable | 
 | 272 |  | 
 | 273 | 	/* Enter critical section. */ | 
 | 274 |  | 
 | 275 | 	l32i	a2, a3, EXC_TABLE_FIXUP | 
 | 276 | 	s32i	a3, a3, EXC_TABLE_FIXUP | 
 | 277 | 	beq	a2, a3, .Lunrecoverable_fixup	# critical! | 
 | 278 | 	beqz	a2, .Ldflt			# no handler was registered | 
 | 279 |  | 
 | 280 | 	/* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */ | 
 | 281 |  | 
 | 282 | 	jx	a2 | 
 | 283 |  | 
 | 284 | .Ldflt:	/* Get stack pointer. */ | 
 | 285 |  | 
 | 286 | 	l32i	a3, a3, EXC_TABLE_DOUBLE_SAVE | 
 | 287 | 	addi	a2, a3, -PT_USER_SIZE | 
 | 288 |  | 
 | 289 | .Lovfl:	/* Jump to default handlers. */ | 
 | 290 |  | 
 | 291 | 	/* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */ | 
 | 292 |  | 
 | 293 | 	xsr	a3, DEPC | 
 | 294 | 	s32i	a0, a2, PT_DEPC | 
 | 295 | 	s32i	a3, a2, PT_AREG0 | 
 | 296 |  | 
 | 297 | 	/* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */ | 
 | 298 |  | 
 | 299 | 	movi	a3, exc_table | 
 | 300 | 	rsr	a0, EXCCAUSE | 
 | 301 | 	addx4	a0, a0, a3 | 
 | 302 | 	l32i	a0, a0, EXC_TABLE_FAST_USER | 
 | 303 | 	jx	a0 | 
 | 304 |  | 
 | 305 | 	/* | 
 | 306 | 	 * We only allow the ITLB miss exception if we are in kernel space. | 
 | 307 | 	 * All other exceptions are unexpected and thus unrecoverable! | 
 | 308 | 	 */ | 
 | 309 |  | 
| Johannes Weiner | e5083a6 | 2009-03-04 16:21:31 +0100 | [diff] [blame] | 310 | #ifdef CONFIG_MMU | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 311 | 	.extern fast_second_level_miss_double_kernel | 
 | 312 |  | 
 | 313 | .Lksp:	/* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */ | 
 | 314 |  | 
 | 315 | 	rsr	a3, EXCCAUSE | 
| Chris Zankel | 173d668 | 2006-12-10 02:18:48 -0800 | [diff] [blame] | 316 | 	beqi	a3, EXCCAUSE_ITLB_MISS, 1f | 
 | 317 | 	addi	a3, a3, -EXCCAUSE_DTLB_MISS | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 318 | 	bnez	a3, .Lunrecoverable | 
 | 319 | 1:	movi	a3, fast_second_level_miss_double_kernel | 
 | 320 | 	jx	a3 | 
| Johannes Weiner | e5083a6 | 2009-03-04 16:21:31 +0100 | [diff] [blame] | 321 | #else | 
 | 322 | .equ	.Lksp,	.Lunrecoverable | 
 | 323 | #endif | 
| Chris Zankel | 5a0015d | 2005-06-23 22:01:16 -0700 | [diff] [blame] | 324 |  | 
 | 325 | 	/* Critical! We can't handle this situation. PANIC! */ | 
 | 326 |  | 
 | 327 | 	.extern unrecoverable_exception | 
 | 328 |  | 
 | 329 | .Lunrecoverable_fixup: | 
 | 330 | 	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE | 
 | 331 | 	xsr	a0, DEPC | 
 | 332 |  | 
 | 333 | .Lunrecoverable: | 
 | 334 | 	rsr	a3, EXCSAVE_1 | 
 | 335 | 	wsr	a0, EXCSAVE_1 | 
 | 336 | 	movi	a0, unrecoverable_exception | 
 | 337 | 	callx0	a0 | 
 | 338 |  | 
 | 339 | 	.end literal_prefix | 
 | 340 |  | 
 | 341 |  | 
 | 342 | /* | 
 | 343 |  * Debug interrupt vector | 
 | 344 |  * | 
 | 345 |  * There is not much space here, so simply jump to another handler. | 
 | 346 |  * EXCSAVE[DEBUGLEVEL] has been set to that handler. | 
 | 347 |  */ | 
 | 348 |  | 
 | 349 | 	.section .DebugInterruptVector.text, "ax" | 
 | 350 |  | 
 | 351 | ENTRY(_DebugInterruptVector) | 
 | 352 | 	xsr	a0, EXCSAVE + XCHAL_DEBUGLEVEL | 
 | 353 | 	jx	a0 | 
 | 354 |  | 
 | 355 |  | 
 | 356 |  | 
 | 357 | /* Window overflow and underflow handlers. | 
 | 358 |  * The handlers must be 64 bytes apart, first starting with the underflow | 
 | 359 |  * handlers underflow-4 to underflow-12, then the overflow handlers | 
 | 360 |  * overflow-4 to overflow-12. | 
 | 361 |  * | 
 | 362 |  * Note: We rerun the underflow handlers if we hit an exception, so | 
 | 363 |  *	 we try to access any page that would cause a page fault early. | 
 | 364 |  */ | 
 | 365 |  | 
 | 366 | 	.section		.WindowVectors.text, "ax" | 
 | 367 |  | 
 | 368 |  | 
 | 369 | /* 4-Register Window Overflow Vector (Handler) */ | 
 | 370 |  | 
 | 371 | 	.align 64 | 
 | 372 | .global _WindowOverflow4 | 
 | 373 | _WindowOverflow4: | 
 | 374 | 	s32e	a0, a5, -16 | 
 | 375 | 	s32e	a1, a5, -12 | 
 | 376 | 	s32e	a2, a5,  -8 | 
 | 377 | 	s32e	a3, a5,  -4 | 
 | 378 | 	rfwo | 
 | 379 |  | 
 | 380 |  | 
 | 381 | /* 4-Register Window Underflow Vector (Handler) */ | 
 | 382 |  | 
 | 383 | 	.align 64 | 
 | 384 | .global _WindowUnderflow4 | 
 | 385 | _WindowUnderflow4: | 
 | 386 | 	l32e	a0, a5, -16 | 
 | 387 | 	l32e	a1, a5, -12 | 
 | 388 | 	l32e	a2, a5,  -8 | 
 | 389 | 	l32e	a3, a5,  -4 | 
 | 390 | 	rfwu | 
 | 391 |  | 
 | 392 |  | 
 | 393 | /* 8-Register Window Overflow Vector (Handler) */ | 
 | 394 |  | 
 | 395 | 	.align 64 | 
 | 396 | .global _WindowOverflow8 | 
 | 397 | _WindowOverflow8: | 
 | 398 | 	s32e	a0, a9, -16 | 
 | 399 | 	l32e	a0, a1, -12 | 
 | 400 | 	s32e	a2, a9,  -8 | 
 | 401 | 	s32e	a1, a9, -12 | 
 | 402 | 	s32e	a3, a9,  -4 | 
 | 403 | 	s32e	a4, a0, -32 | 
 | 404 | 	s32e	a5, a0, -28 | 
 | 405 | 	s32e	a6, a0, -24 | 
 | 406 | 	s32e	a7, a0, -20 | 
 | 407 | 	rfwo | 
 | 408 |  | 
 | 409 | /* 8-Register Window Underflow Vector (Handler) */ | 
 | 410 |  | 
 | 411 | 	.align 64 | 
 | 412 | .global _WindowUnderflow8 | 
 | 413 | _WindowUnderflow8: | 
 | 414 | 	l32e	a1, a9, -12 | 
 | 415 | 	l32e	a0, a9, -16 | 
 | 416 | 	l32e	a7, a1, -12 | 
 | 417 | 	l32e	a2, a9,  -8 | 
 | 418 | 	l32e	a4, a7, -32 | 
 | 419 | 	l32e	a3, a9,  -4 | 
 | 420 | 	l32e	a5, a7, -28 | 
 | 421 | 	l32e	a6, a7, -24 | 
 | 422 | 	l32e	a7, a7, -20 | 
 | 423 | 	rfwu | 
 | 424 |  | 
 | 425 |  | 
 | 426 | /* 12-Register Window Overflow Vector (Handler) */ | 
 | 427 |  | 
 | 428 | 	.align 64 | 
 | 429 | .global _WindowOverflow12 | 
 | 430 | _WindowOverflow12: | 
 | 431 | 	s32e	a0,  a13, -16 | 
 | 432 | 	l32e	a0,  a1,  -12 | 
 | 433 | 	s32e	a1,  a13, -12 | 
 | 434 | 	s32e	a2,  a13,  -8 | 
 | 435 | 	s32e	a3,  a13,  -4 | 
 | 436 | 	s32e	a4,  a0,  -48 | 
 | 437 | 	s32e	a5,  a0,  -44 | 
 | 438 | 	s32e	a6,  a0,  -40 | 
 | 439 | 	s32e	a7,  a0,  -36 | 
 | 440 | 	s32e	a8,  a0,  -32 | 
 | 441 | 	s32e	a9,  a0,  -28 | 
 | 442 | 	s32e	a10, a0,  -24 | 
 | 443 | 	s32e	a11, a0,  -20 | 
 | 444 | 	rfwo | 
 | 445 |  | 
 | 446 | /* 12-Register Window Underflow Vector (Handler) */ | 
 | 447 |  | 
 | 448 | 	.align 64 | 
 | 449 | .global _WindowUnderflow12 | 
 | 450 | _WindowUnderflow12: | 
 | 451 | 	l32e	a1,  a13, -12 | 
 | 452 | 	l32e	a0,  a13, -16 | 
 | 453 | 	l32e	a11, a1,  -12 | 
 | 454 | 	l32e	a2,  a13,  -8 | 
 | 455 | 	l32e	a4,  a11, -48 | 
 | 456 | 	l32e	a8,  a11, -32 | 
 | 457 | 	l32e	a3,  a13,  -4 | 
 | 458 | 	l32e	a5,  a11, -44 | 
 | 459 | 	l32e	a6,  a11, -40 | 
 | 460 | 	l32e	a7,  a11, -36 | 
 | 461 | 	l32e	a9,  a11, -28 | 
 | 462 | 	l32e	a10, a11, -24 | 
 | 463 | 	l32e	a11, a11, -20 | 
 | 464 | 	rfwu | 
 | 465 |  | 
 | 466 | 	.text | 
 | 467 |  | 
 | 468 |  |