diff options
Diffstat (limited to 'arch/xtensa/kernel/vectors.S')
-rw-r--r-- | arch/xtensa/kernel/vectors.S | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S new file mode 100644 index 000000000000..81808f0c6742 --- /dev/null +++ b/arch/xtensa/kernel/vectors.S | |||
@@ -0,0 +1,464 @@ | |||
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/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 | |||
70 | ENTRY(_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 | |||
94 | ENTRY(_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 | |||
204 | ENTRY(_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 | ||
318 | 1: 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 | |||
347 | ENTRY(_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 | |||