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