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