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