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 .section .DoubleExceptionVector.text, "ax" 109 .begin literal_prefix .DoubleExceptionVector 110 111ENTRY(_DoubleExceptionVector) 112 113 /* Deliberately destroy excsave (don't assume it's value was valid). */ 114 115 wsr a3, EXCSAVE_1 # save a3 116 117 /* Check for kernel double exception (usually fatal). */ 118 119 rsr a3, PS 120 _bbci.l a3, PS_UM_BIT, .Lksp 121 122 /* Check if we are currently handling a window exception. */ 123 /* Note: We don't need to indicate that we enter a critical section. */ 124 125 xsr a0, DEPC # get DEPC, save a0 126 127 movi a3, XCHAL_WINDOW_VECTORS_VADDR 128 _bltu a0, a3, .Lfixup 129 addi a3, a3, WINDOW_VECTORS_SIZE 130 _bgeu a0, a3, .Lfixup 131 132 /* Window overflow/underflow exception. Get stack pointer. */ 133 134 mov a3, a2 135 movi a2, exc_table 136 l32i a2, a2, EXC_TABLE_KSTK 137 138 /* Check for overflow/underflow exception, jump if overflow. */ 139 140 _bbci.l a0, 6, .Lovfl 141 142 /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */ 143 144 /* Restart window underflow exception. 145 * We return to the instruction in user space that caused the window 146 * underflow exception. Therefore, we change window base to the value 147 * before we entered the window underflow exception and prepare the 148 * registers to return as if we were coming from a regular exception 149 * by changing depc (in a0). 150 * Note: We can trash the current window frame (a0...a3) and depc! 151 */ 152 153 wsr a2, DEPC # save stack pointer temporarily 154 rsr a0, PS 155 extui a0, a0, PS_OWB_SHIFT, 4 156 wsr a0, WINDOWBASE 157 rsync 158 159 /* We are now in the previous window frame. Save registers again. */ 160 161 xsr a2, DEPC # save a2 and get stack pointer 162 s32i a0, a2, PT_AREG0 163 164 wsr a3, EXCSAVE_1 # save a3 165 movi a3, exc_table 166 167 rsr a0, EXCCAUSE 168 s32i a0, a2, PT_DEPC # mark it as a regular exception 169 addx4 a0, a0, a3 170 l32i a0, a0, EXC_TABLE_FAST_USER 171 jx a0 172 173.Lfixup:/* Check for a fixup handler or if we were in a critical section. */ 174 175 /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */ 176 177 movi a3, exc_table 178 s32i a2, a3, EXC_TABLE_DOUBLE_SAVE # temporary variable 179 180 /* Enter critical section. */ 181 182 l32i a2, a3, EXC_TABLE_FIXUP 183 s32i a3, a3, EXC_TABLE_FIXUP 184 beq a2, a3, .Lunrecoverable_fixup # critical! 185 beqz a2, .Ldflt # no handler was registered 186 187 /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */ 188 189 jx a2 190 191.Ldflt: /* Get stack pointer. */ 192 193 l32i a3, a3, EXC_TABLE_DOUBLE_SAVE 194 addi a2, a3, -PT_USER_SIZE 195 196.Lovfl: /* Jump to default handlers. */ 197 198 /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */ 199 200 xsr a3, DEPC 201 s32i a0, a2, PT_DEPC 202 s32i a3, a2, PT_AREG0 203 204 /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */ 205 206 movi a3, exc_table 207 rsr a0, EXCCAUSE 208 addx4 a0, a0, a3 209 l32i a0, a0, EXC_TABLE_FAST_USER 210 jx a0 211 212 /* 213 * We only allow the ITLB miss exception if we are in kernel space. 214 * All other exceptions are unexpected and thus unrecoverable! 215 */ 216 217#ifdef CONFIG_MMU 218 .extern fast_second_level_miss_double_kernel 219 220.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */ 221 222 rsr a3, EXCCAUSE 223 beqi a3, EXCCAUSE_ITLB_MISS, 1f 224 addi a3, a3, -EXCCAUSE_DTLB_MISS 225 bnez a3, .Lunrecoverable 2261: movi a3, fast_second_level_miss_double_kernel 227 jx a3 228#else 229.equ .Lksp, .Lunrecoverable 230#endif 231 232 /* Critical! We can't handle this situation. PANIC! */ 233 234 .extern unrecoverable_exception 235 236.Lunrecoverable_fixup: 237 l32i a2, a3, EXC_TABLE_DOUBLE_SAVE 238 xsr a0, DEPC 239 240.Lunrecoverable: 241 rsr a3, EXCSAVE_1 242 wsr a0, EXCSAVE_1 243 movi a0, unrecoverable_exception 244 callx0 a0 245 246 .end literal_prefix 247 248 249/* 250 * Debug interrupt vector 251 * 252 * There is not much space here, so simply jump to another handler. 253 * EXCSAVE[DEBUGLEVEL] has been set to that handler. 254 */ 255 256 .section .DebugInterruptVector.text, "ax" 257 258ENTRY(_DebugInterruptVector) 259 xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL 260 jx a0 261 262 263 264/* Window overflow and underflow handlers. 265 * The handlers must be 64 bytes apart, first starting with the underflow 266 * handlers underflow-4 to underflow-12, then the overflow handlers 267 * overflow-4 to overflow-12. 268 * 269 * Note: We rerun the underflow handlers if we hit an exception, so 270 * we try to access any page that would cause a page fault early. 271 */ 272 273 .section .WindowVectors.text, "ax" 274 275 276/* 4-Register Window Overflow Vector (Handler) */ 277 278 .align 64 279.global _WindowOverflow4 280_WindowOverflow4: 281 s32e a0, a5, -16 282 s32e a1, a5, -12 283 s32e a2, a5, -8 284 s32e a3, a5, -4 285 rfwo 286 287 288/* 4-Register Window Underflow Vector (Handler) */ 289 290 .align 64 291.global _WindowUnderflow4 292_WindowUnderflow4: 293 l32e a0, a5, -16 294 l32e a1, a5, -12 295 l32e a2, a5, -8 296 l32e a3, a5, -4 297 rfwu 298 299 300/* 8-Register Window Overflow Vector (Handler) */ 301 302 .align 64 303.global _WindowOverflow8 304_WindowOverflow8: 305 s32e a0, a9, -16 306 l32e a0, a1, -12 307 s32e a2, a9, -8 308 s32e a1, a9, -12 309 s32e a3, a9, -4 310 s32e a4, a0, -32 311 s32e a5, a0, -28 312 s32e a6, a0, -24 313 s32e a7, a0, -20 314 rfwo 315 316/* 8-Register Window Underflow Vector (Handler) */ 317 318 .align 64 319.global _WindowUnderflow8 320_WindowUnderflow8: 321 l32e a1, a9, -12 322 l32e a0, a9, -16 323 l32e a7, a1, -12 324 l32e a2, a9, -8 325 l32e a4, a7, -32 326 l32e a3, a9, -4 327 l32e a5, a7, -28 328 l32e a6, a7, -24 329 l32e a7, a7, -20 330 rfwu 331 332 333/* 12-Register Window Overflow Vector (Handler) */ 334 335 .align 64 336.global _WindowOverflow12 337_WindowOverflow12: 338 s32e a0, a13, -16 339 l32e a0, a1, -12 340 s32e a1, a13, -12 341 s32e a2, a13, -8 342 s32e a3, a13, -4 343 s32e a4, a0, -48 344 s32e a5, a0, -44 345 s32e a6, a0, -40 346 s32e a7, a0, -36 347 s32e a8, a0, -32 348 s32e a9, a0, -28 349 s32e a10, a0, -24 350 s32e a11, a0, -20 351 rfwo 352 353/* 12-Register Window Underflow Vector (Handler) */ 354 355 .align 64 356.global _WindowUnderflow12 357_WindowUnderflow12: 358 l32e a1, a13, -12 359 l32e a0, a13, -16 360 l32e a11, a1, -12 361 l32e a2, a13, -8 362 l32e a4, a11, -48 363 l32e a8, a11, -32 364 l32e a3, a13, -4 365 l32e a5, a11, -44 366 l32e a6, a11, -40 367 l32e a7, a11, -36 368 l32e a9, a11, -28 369 l32e a10, a11, -24 370 l32e a11, a11, -20 371 rfwu 372 373 .text 374