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, 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 94ENTRY(_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 204ENTRY(_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 213 _bbci.l a3, PS_UM_BIT, .Lksp 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 222 addi a3, a3, WINDOW_VECTORS_SIZE 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 248 extui a0, a0, PS_OWB_SHIFT, 4 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 310#ifdef CONFIG_MMU 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 316 beqi a3, EXCCAUSE_ITLB_MISS, 1f 317 addi a3, a3, -EXCCAUSE_DTLB_MISS 318 bnez a3, .Lunrecoverable 3191: movi a3, fast_second_level_miss_double_kernel 320 jx a3 321#else 322.equ .Lksp, .Lunrecoverable 323#endif 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 351ENTRY(_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 469