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/ptrace.h> 48#include <asm/current.h> 49#include <asm/asm-offsets.h> 50#include <asm/pgtable.h> 51#include <asm/processor.h> 52#include <asm/page.h> 53#include <asm/thread_info.h> 54#include <asm/processor.h> 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_SHIFT, .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, XSHAL_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, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS 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 .extern fast_second_level_miss_double_kernel 311 312.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */ 313 314 rsr a3, EXCCAUSE 315 beqi a3, XCHAL_EXCCAUSE_ITLB_MISS, 1f 316 addi a3, a3, -XCHAL_EXCCAUSE_DTLB_MISS 317 bnez a3, .Lunrecoverable 3181: movi a3, fast_second_level_miss_double_kernel 319 jx a3 320 321 /* Critical! We can't handle this situation. PANIC! */ 322 323 .extern unrecoverable_exception 324 325.Lunrecoverable_fixup: 326 l32i a2, a3, EXC_TABLE_DOUBLE_SAVE 327 xsr a0, DEPC 328 329.Lunrecoverable: 330 rsr a3, EXCSAVE_1 331 wsr a0, EXCSAVE_1 332 movi a0, unrecoverable_exception 333 callx0 a0 334 335 .end literal_prefix 336 337 338/* 339 * Debug interrupt vector 340 * 341 * There is not much space here, so simply jump to another handler. 342 * EXCSAVE[DEBUGLEVEL] has been set to that handler. 343 */ 344 345 .section .DebugInterruptVector.text, "ax" 346 347ENTRY(_DebugInterruptVector) 348 xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL 349 jx a0 350 351 352 353/* Window overflow and underflow handlers. 354 * The handlers must be 64 bytes apart, first starting with the underflow 355 * handlers underflow-4 to underflow-12, then the overflow handlers 356 * overflow-4 to overflow-12. 357 * 358 * Note: We rerun the underflow handlers if we hit an exception, so 359 * we try to access any page that would cause a page fault early. 360 */ 361 362 .section .WindowVectors.text, "ax" 363 364 365/* 4-Register Window Overflow Vector (Handler) */ 366 367 .align 64 368.global _WindowOverflow4 369_WindowOverflow4: 370 s32e a0, a5, -16 371 s32e a1, a5, -12 372 s32e a2, a5, -8 373 s32e a3, a5, -4 374 rfwo 375 376 377/* 4-Register Window Underflow Vector (Handler) */ 378 379 .align 64 380.global _WindowUnderflow4 381_WindowUnderflow4: 382 l32e a0, a5, -16 383 l32e a1, a5, -12 384 l32e a2, a5, -8 385 l32e a3, a5, -4 386 rfwu 387 388 389/* 8-Register Window Overflow Vector (Handler) */ 390 391 .align 64 392.global _WindowOverflow8 393_WindowOverflow8: 394 s32e a0, a9, -16 395 l32e a0, a1, -12 396 s32e a2, a9, -8 397 s32e a1, a9, -12 398 s32e a3, a9, -4 399 s32e a4, a0, -32 400 s32e a5, a0, -28 401 s32e a6, a0, -24 402 s32e a7, a0, -20 403 rfwo 404 405/* 8-Register Window Underflow Vector (Handler) */ 406 407 .align 64 408.global _WindowUnderflow8 409_WindowUnderflow8: 410 l32e a1, a9, -12 411 l32e a0, a9, -16 412 l32e a7, a1, -12 413 l32e a2, a9, -8 414 l32e a4, a7, -32 415 l32e a3, a9, -4 416 l32e a5, a7, -28 417 l32e a6, a7, -24 418 l32e a7, a7, -20 419 rfwu 420 421 422/* 12-Register Window Overflow Vector (Handler) */ 423 424 .align 64 425.global _WindowOverflow12 426_WindowOverflow12: 427 s32e a0, a13, -16 428 l32e a0, a1, -12 429 s32e a1, a13, -12 430 s32e a2, a13, -8 431 s32e a3, a13, -4 432 s32e a4, a0, -48 433 s32e a5, a0, -44 434 s32e a6, a0, -40 435 s32e a7, a0, -36 436 s32e a8, a0, -32 437 s32e a9, a0, -28 438 s32e a10, a0, -24 439 s32e a11, a0, -20 440 rfwo 441 442/* 12-Register Window Underflow Vector (Handler) */ 443 444 .align 64 445.global _WindowUnderflow12 446_WindowUnderflow12: 447 l32e a1, a13, -12 448 l32e a0, a13, -16 449 l32e a11, a1, -12 450 l32e a2, a13, -8 451 l32e a4, a11, -48 452 l32e a8, a11, -32 453 l32e a3, a13, -4 454 l32e a5, a11, -44 455 l32e a6, a11, -40 456 l32e a7, a11, -36 457 l32e a9, a11, -28 458 l32e a10, a11, -24 459 l32e a11, a11, -20 460 rfwu 461 462 .text 463 464 465