Commit | Line | Data |
---|---|---|
baf4326e | 1 | /* |
de398406 | 2 | * arch/sh/kernel/entry.S |
1da177e4 LT |
3 | * |
4 | * Copyright (C) 1999, 2000, 2002 Niibe Yutaka | |
baf4326e | 5 | * Copyright (C) 2003 - 2006 Paul Mundt |
1da177e4 LT |
6 | * |
7 | * This file is subject to the terms and conditions of the GNU General Public | |
8 | * License. See the file "COPYING" in the main directory of this archive | |
9 | * for more details. | |
1da177e4 | 10 | */ |
1da177e4 | 11 | #include <linux/sys.h> |
711fa809 | 12 | #include <linux/errno.h> |
1da177e4 | 13 | #include <linux/linkage.h> |
1da177e4 LT |
14 | #include <asm/asm-offsets.h> |
15 | #include <asm/thread_info.h> | |
16 | #include <asm/unistd.h> | |
9b3a53ab SM |
17 | #include <asm/cpu/mmu_context.h> |
18 | #include <asm/pgtable.h> | |
19 | #include <asm/page.h> | |
1da177e4 | 20 | |
1da177e4 LT |
21 | ! NOTE: |
22 | ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address | |
23 | ! to be jumped is too far, but it causes illegal slot exception. | |
24 | ||
25 | /* | |
26 | * entry.S contains the system-call and fault low-level handling routines. | |
27 | * This also contains the timer-interrupt handler, as well as all interrupts | |
28 | * and faults that can result in a task-switch. | |
29 | * | |
30 | * NOTE: This code handles signal-recognition, which happens every time | |
31 | * after a timer-interrupt and after each system call. | |
32 | * | |
33 | * NOTE: This code uses a convention that instructions in the delay slot | |
34 | * of a transfer-control instruction are indented by an extra space, thus: | |
35 | * | |
36 | * jmp @k0 ! control-transfer instruction | |
37 | * ldc k1, ssr ! delay slot | |
38 | * | |
39 | * Stack layout in 'ret_from_syscall': | |
40 | * ptrace needs to have all regs on the stack. | |
41 | * if the order here is changed, it needs to be | |
42 | * updated in ptrace.c and ptrace.h | |
43 | * | |
44 | * r0 | |
45 | * ... | |
46 | * r15 = stack pointer | |
47 | * spc | |
48 | * pr | |
49 | * ssr | |
50 | * gbr | |
51 | * mach | |
52 | * macl | |
53 | * syscall # | |
54 | * | |
55 | */ | |
1da177e4 LT |
56 | #if defined(CONFIG_KGDB_NMI) |
57 | NMI_VEC = 0x1c0 ! Must catch early for debounce | |
58 | #endif | |
59 | ||
60 | /* Offsets to the stack */ | |
61 | OFF_R0 = 0 /* Return value. New ABI also arg4 */ | |
62 | OFF_R1 = 4 /* New ABI: arg5 */ | |
63 | OFF_R2 = 8 /* New ABI: arg6 */ | |
64 | OFF_R3 = 12 /* New ABI: syscall_nr */ | |
65 | OFF_R4 = 16 /* New ABI: arg0 */ | |
66 | OFF_R5 = 20 /* New ABI: arg1 */ | |
67 | OFF_R6 = 24 /* New ABI: arg2 */ | |
68 | OFF_R7 = 28 /* New ABI: arg3 */ | |
69 | OFF_SP = (15*4) | |
70 | OFF_PC = (16*4) | |
71 | OFF_SR = (16*4+8) | |
72 | OFF_TRA = (16*4+6*4) | |
73 | ||
74 | ||
75 | #define k0 r0 | |
76 | #define k1 r1 | |
77 | #define k2 r2 | |
78 | #define k3 r3 | |
79 | #define k4 r4 | |
80 | ||
1da177e4 LT |
81 | #define g_imask r6 /* r6_bank1 */ |
82 | #define k_g_imask r6_bank /* r6_bank1 */ | |
83 | #define current r7 /* r7_bank1 */ | |
84 | ||
de398406 YS |
85 | #include <asm/entry-macros.S> |
86 | ||
1da177e4 LT |
87 | /* |
88 | * Kernel mode register usage: | |
89 | * k0 scratch | |
90 | * k1 scratch | |
91 | * k2 scratch (Exception code) | |
92 | * k3 scratch (Return address) | |
93 | * k4 scratch | |
94 | * k5 reserved | |
95 | * k6 Global Interrupt Mask (0--15 << 4) | |
96 | * k7 CURRENT_THREAD_INFO (pointer to current thread info) | |
97 | */ | |
98 | ||
99 | ! | |
100 | ! TLB Miss / Initial Page write exception handling | |
101 | ! _and_ | |
102 | ! TLB hits, but the access violate the protection. | |
103 | ! It can be valid access, such as stack grow and/or C-O-W. | |
104 | ! | |
105 | ! | |
106 | ! Find the pmd/pte entry and loadtlb | |
107 | ! If it's not found, cause address error (SEGV) | |
108 | ! | |
109 | ! Although this could be written in assembly language (and it'd be faster), | |
110 | ! this first version depends *much* on C implementation. | |
111 | ! | |
112 | ||
1da177e4 LT |
113 | #if defined(CONFIG_MMU) |
114 | .align 2 | |
115 | ENTRY(tlb_miss_load) | |
116 | bra call_dpf | |
117 | mov #0, r5 | |
118 | ||
119 | .align 2 | |
120 | ENTRY(tlb_miss_store) | |
121 | bra call_dpf | |
122 | mov #1, r5 | |
123 | ||
124 | .align 2 | |
125 | ENTRY(initial_page_write) | |
126 | bra call_dpf | |
127 | mov #1, r5 | |
128 | ||
129 | .align 2 | |
130 | ENTRY(tlb_protection_violation_load) | |
131 | bra call_dpf | |
132 | mov #0, r5 | |
133 | ||
134 | .align 2 | |
135 | ENTRY(tlb_protection_violation_store) | |
136 | bra call_dpf | |
137 | mov #1, r5 | |
138 | ||
139 | call_dpf: | |
140 | mov.l 1f, r0 | |
9b3a53ab | 141 | mov.l @r0, r6 ! address |
1da177e4 | 142 | mov.l 3f, r0 |
afbfb52e | 143 | |
1da177e4 | 144 | jmp @r0 |
9b3a53ab | 145 | mov r15, r4 ! regs |
1da177e4 LT |
146 | |
147 | .align 2 | |
148 | 1: .long MMU_TEA | |
1da177e4 LT |
149 | 3: .long do_page_fault |
150 | ||
151 | .align 2 | |
152 | ENTRY(address_error_load) | |
153 | bra call_dae | |
154 | mov #0,r5 ! writeaccess = 0 | |
155 | ||
156 | .align 2 | |
157 | ENTRY(address_error_store) | |
158 | bra call_dae | |
159 | mov #1,r5 ! writeaccess = 1 | |
160 | ||
161 | .align 2 | |
162 | call_dae: | |
163 | mov.l 1f, r0 | |
164 | mov.l @r0, r6 ! address | |
165 | mov.l 2f, r0 | |
166 | jmp @r0 | |
167 | mov r15, r4 ! regs | |
168 | ||
169 | .align 2 | |
170 | 1: .long MMU_TEA | |
171 | 2: .long do_address_error | |
172 | #endif /* CONFIG_MMU */ | |
173 | ||
1da177e4 LT |
174 | #if defined(CONFIG_SH_STANDARD_BIOS) |
175 | /* Unwind the stack and jmp to the debug entry */ | |
f413d0d9 | 176 | ENTRY(sh_bios_handler) |
1da177e4 LT |
177 | mov.l @r15+, r0 |
178 | mov.l @r15+, r1 | |
179 | mov.l @r15+, r2 | |
180 | mov.l @r15+, r3 | |
181 | mov.l @r15+, r4 | |
182 | mov.l @r15+, r5 | |
183 | mov.l @r15+, r6 | |
184 | mov.l @r15+, r7 | |
185 | stc sr, r8 | |
186 | mov.l 1f, r9 ! BL =1, RB=1, IMASK=0x0F | |
187 | or r9, r8 | |
188 | ldc r8, sr ! here, change the register bank | |
189 | mov.l @r15+, r8 | |
190 | mov.l @r15+, r9 | |
191 | mov.l @r15+, r10 | |
192 | mov.l @r15+, r11 | |
193 | mov.l @r15+, r12 | |
194 | mov.l @r15+, r13 | |
195 | mov.l @r15+, r14 | |
196 | mov.l @r15+, k0 | |
197 | ldc.l @r15+, spc | |
198 | lds.l @r15+, pr | |
199 | mov.l @r15+, k1 | |
200 | ldc.l @r15+, gbr | |
201 | lds.l @r15+, mach | |
202 | lds.l @r15+, macl | |
203 | mov k0, r15 | |
204 | ! | |
205 | mov.l 2f, k0 | |
206 | mov.l @k0, k0 | |
207 | jmp @k0 | |
208 | ldc k1, ssr | |
209 | .align 2 | |
210 | 1: .long 0x300000f0 | |
211 | 2: .long gdb_vbr_vector | |
212 | #endif /* CONFIG_SH_STANDARD_BIOS */ | |
213 | ||
1da177e4 LT |
214 | restore_all: |
215 | mov.l @r15+, r0 | |
216 | mov.l @r15+, r1 | |
217 | mov.l @r15+, r2 | |
218 | mov.l @r15+, r3 | |
219 | mov.l @r15+, r4 | |
220 | mov.l @r15+, r5 | |
221 | mov.l @r15+, r6 | |
222 | mov.l @r15+, r7 | |
223 | ! | |
224 | stc sr, r8 | |
225 | mov.l 7f, r9 | |
226 | or r9, r8 ! BL =1, RB=1 | |
227 | ldc r8, sr ! here, change the register bank | |
228 | ! | |
229 | mov.l @r15+, r8 | |
230 | mov.l @r15+, r9 | |
231 | mov.l @r15+, r10 | |
232 | mov.l @r15+, r11 | |
233 | mov.l @r15+, r12 | |
234 | mov.l @r15+, r13 | |
235 | mov.l @r15+, r14 | |
236 | mov.l @r15+, k4 ! original stack pointer | |
237 | ldc.l @r15+, spc | |
238 | lds.l @r15+, pr | |
239 | mov.l @r15+, k3 ! original SR | |
240 | ldc.l @r15+, gbr | |
241 | lds.l @r15+, mach | |
242 | lds.l @r15+, macl | |
243 | add #4, r15 ! Skip syscall number | |
244 | ! | |
245 | #ifdef CONFIG_SH_DSP | |
246 | mov.l @r15+, k0 ! DSP mode marker | |
247 | mov.l 5f, k1 | |
248 | cmp/eq k0, k1 ! Do we have a DSP stack frame? | |
249 | bf skip_restore | |
250 | ||
251 | stc sr, k0 ! Enable CPU DSP mode | |
252 | or k1, k0 ! (within kernel it may be disabled) | |
253 | ldc k0, sr | |
254 | mov r2, k0 ! Backup r2 | |
255 | ||
256 | ! Restore DSP registers from stack | |
257 | mov r15, r2 | |
258 | movs.l @r2+, a1 | |
259 | movs.l @r2+, a0g | |
260 | movs.l @r2+, a1g | |
261 | movs.l @r2+, m0 | |
262 | movs.l @r2+, m1 | |
263 | mov r2, r15 | |
264 | ||
265 | lds.l @r15+, a0 | |
266 | lds.l @r15+, x0 | |
267 | lds.l @r15+, x1 | |
268 | lds.l @r15+, y0 | |
269 | lds.l @r15+, y1 | |
270 | lds.l @r15+, dsr | |
271 | ldc.l @r15+, rs | |
272 | ldc.l @r15+, re | |
273 | ldc.l @r15+, mod | |
274 | ||
275 | mov k0, r2 ! Restore r2 | |
276 | skip_restore: | |
277 | #endif | |
278 | ! | |
279 | ! Calculate new SR value | |
280 | mov k3, k2 ! original SR value | |
de398406 YS |
281 | mov #0xf0, k1 |
282 | extu.b k1, k1 | |
283 | not k1, k1 | |
1da177e4 LT |
284 | and k1, k2 ! Mask orignal SR value |
285 | ! | |
286 | mov k3, k0 ! Calculate IMASK-bits | |
287 | shlr2 k0 | |
288 | and #0x3c, k0 | |
289 | cmp/eq #0x3c, k0 | |
290 | bt/s 6f | |
291 | shll2 k0 | |
292 | mov g_imask, k0 | |
293 | ! | |
294 | 6: or k0, k2 ! Set the IMASK-bits | |
295 | ldc k2, ssr | |
296 | ! | |
297 | #if defined(CONFIG_KGDB_NMI) | |
298 | ! Clear in_nmi | |
6ae5e8d7 | 299 | mov.l 6f, k0 |
1da177e4 LT |
300 | mov #0, k1 |
301 | mov.b k1, @k0 | |
302 | #endif | |
303 | mov.l @r15+, k2 ! restore EXPEVT | |
304 | mov k4, r15 | |
305 | rte | |
306 | nop | |
307 | ||
308 | .align 2 | |
1da177e4 LT |
309 | 5: .long 0x00001000 ! DSP |
310 | 7: .long 0x30000000 | |
1da177e4 | 311 | |
de398406 | 312 | ! common exception handler |
716067f2 | 313 | #include "../../entry-common.S" |
de398406 | 314 | |
1da177e4 LT |
315 | ! Exception Vector Base |
316 | ! | |
317 | ! Should be aligned page boundary. | |
318 | ! | |
319 | .balign 4096,0,4096 | |
320 | ENTRY(vbr_base) | |
321 | .long 0 | |
322 | ! | |
323 | .balign 256,0,256 | |
324 | general_exception: | |
325 | mov.l 1f, k2 | |
326 | mov.l 2f, k3 | |
327 | bra handle_exception | |
328 | mov.l @k2, k2 | |
329 | .align 2 | |
330 | 1: .long EXPEVT | |
331 | 2: .long ret_from_exception | |
332 | ! | |
333 | ! | |
9b3a53ab | 334 | |
9b3a53ab SM |
335 | /* gas doesn't flag impossible values for mov #immediate as an error */ |
336 | #if (_PAGE_PRESENT >> 2) > 0x7f | |
337 | #error cannot load PAGE_PRESENT as an immediate | |
338 | #endif | |
339 | #if _PAGE_DIRTY > 0x7f | |
340 | #error cannot load PAGE_DIRTY as an immediate | |
341 | #endif | |
342 | #if (_PAGE_PRESENT << 2) != _PAGE_ACCESSED | |
343 | #error cannot derive PAGE_ACCESSED from PAGE_PRESENT | |
344 | #endif | |
345 | ||
346 | #if defined(CONFIG_CPU_SH4) | |
347 | #define ldmmupteh(r) mov.l 8f, r | |
348 | #else | |
349 | #define ldmmupteh(r) mov #MMU_PTEH, r | |
350 | #endif | |
351 | ||
1da177e4 LT |
352 | .balign 1024,0,1024 |
353 | tlb_miss: | |
9b3a53ab SM |
354 | #ifdef COUNT_EXCEPTIONS |
355 | ! Increment the counts | |
356 | mov.l 9f, k1 | |
357 | mov.l @k1, k2 | |
358 | add #1, k2 | |
359 | mov.l k2, @k1 | |
360 | #endif | |
361 | ||
362 | ! k0 scratch | |
363 | ! k1 pgd and pte pointers | |
364 | ! k2 faulting address | |
365 | ! k3 pgd and pte index masks | |
366 | ! k4 shift | |
367 | ||
368 | ! Load up the pgd entry (k1) | |
369 | ||
370 | ldmmupteh(k0) ! 9 LS (latency=2) MMU_PTEH | |
371 | ||
372 | mov.w 4f, k3 ! 8 LS (latency=2) (PTRS_PER_PGD-1) << 2 | |
373 | mov #-(PGDIR_SHIFT-2), k4 ! 6 EX | |
374 | ||
375 | mov.l @(MMU_TEA-MMU_PTEH,k0), k2 ! 18 LS (latency=2) | |
376 | ||
377 | mov.l @(MMU_TTB-MMU_PTEH,k0), k1 ! 18 LS (latency=2) | |
378 | ||
379 | mov k2, k0 ! 5 MT (latency=0) | |
380 | shld k4, k0 ! 99 EX | |
381 | ||
382 | and k3, k0 ! 78 EX | |
383 | ||
384 | mov.l @(k0, k1), k1 ! 21 LS (latency=2) | |
385 | mov #-(PAGE_SHIFT-2), k4 ! 6 EX | |
386 | ||
387 | ! Load up the pte entry (k2) | |
388 | ||
389 | mov k2, k0 ! 5 MT (latency=0) | |
390 | shld k4, k0 ! 99 EX | |
391 | ||
392 | tst k1, k1 ! 86 MT | |
393 | ||
394 | bt 20f ! 110 BR | |
395 | ||
7a847f81 | 396 | mov.w 3f, k3 ! 8 LS (latency=2) (PTRS_PER_PTE-1) << 2 |
9b3a53ab SM |
397 | and k3, k0 ! 78 EX |
398 | mov.w 5f, k4 ! 8 LS (latency=2) _PAGE_PRESENT | |
399 | ||
400 | mov.l @(k0, k1), k2 ! 21 LS (latency=2) | |
401 | add k0, k1 ! 49 EX | |
402 | ||
403 | #ifdef CONFIG_CPU_HAS_PTEA | |
404 | ! Test the entry for present and _PAGE_ACCESSED | |
405 | ||
406 | mov #-28, k3 ! 6 EX | |
407 | mov k2, k0 ! 5 MT (latency=0) | |
408 | ||
409 | tst k4, k2 ! 68 MT | |
410 | shld k3, k0 ! 99 EX | |
411 | ||
412 | bt 20f ! 110 BR | |
413 | ||
414 | ! Set PTEA register | |
415 | ! MMU_PTEA = ((pteval >> 28) & 0xe) | (pteval & 0x1) | |
416 | ! | |
417 | ! k0=pte>>28, k1=pte*, k2=pte, k3=<unused>, k4=_PAGE_PRESENT | |
418 | ||
419 | and #0xe, k0 ! 79 EX | |
420 | ||
421 | mov k0, k3 ! 5 MT (latency=0) | |
422 | mov k2, k0 ! 5 MT (latency=0) | |
423 | ||
424 | and #1, k0 ! 79 EX | |
425 | ||
426 | or k0, k3 ! 82 EX | |
427 | ||
428 | ldmmupteh(k0) ! 9 LS (latency=2) | |
429 | shll2 k4 ! 101 EX _PAGE_ACCESSED | |
430 | ||
431 | tst k4, k2 ! 68 MT | |
432 | ||
433 | mov.l k3, @(MMU_PTEA-MMU_PTEH,k0) ! 27 LS | |
434 | ||
435 | mov.l 7f, k3 ! 9 LS (latency=2) _PAGE_FLAGS_HARDWARE_MASK | |
436 | ||
437 | ! k0=MMU_PTEH, k1=pte*, k2=pte, k3=_PAGE_FLAGS_HARDWARE, k4=_PAGE_ACCESSED | |
438 | #else | |
439 | ||
440 | ! Test the entry for present and _PAGE_ACCESSED | |
441 | ||
442 | mov.l 7f, k3 ! 9 LS (latency=2) _PAGE_FLAGS_HARDWARE_MASK | |
443 | tst k4, k2 ! 68 MT | |
444 | ||
445 | shll2 k4 ! 101 EX _PAGE_ACCESSED | |
446 | ldmmupteh(k0) ! 9 LS (latency=2) | |
447 | ||
448 | bt 20f ! 110 BR | |
449 | tst k4, k2 ! 68 MT | |
450 | ||
451 | ! k0=MMU_PTEH, k1=pte*, k2=pte, k3=_PAGE_FLAGS_HARDWARE, k4=_PAGE_ACCESSED | |
452 | ||
453 | #endif | |
454 | ||
455 | ! Set up the entry | |
456 | ||
457 | and k2, k3 ! 78 EX | |
458 | bt/s 10f ! 108 BR | |
459 | ||
460 | mov.l k3, @(MMU_PTEL-MMU_PTEH,k0) ! 27 LS | |
461 | ||
462 | ldtlb ! 128 CO | |
463 | ||
464 | ! At least one instruction between ldtlb and rte | |
465 | nop ! 119 NOP | |
466 | ||
467 | rte ! 126 CO | |
468 | ||
469 | nop ! 119 NOP | |
470 | ||
471 | ||
472 | 10: or k4, k2 ! 82 EX | |
473 | ||
474 | ldtlb ! 128 CO | |
475 | ||
476 | ! At least one instruction between ldtlb and rte | |
477 | mov.l k2, @k1 ! 27 LS | |
478 | ||
479 | rte ! 126 CO | |
480 | ||
481 | ! Note we cannot execute mov here, because it is executed after | |
482 | ! restoring SSR, so would be executed in user space. | |
483 | nop ! 119 NOP | |
484 | ||
485 | ||
486 | .align 5 | |
487 | ! Once cache line if possible... | |
488 | 1: .long swapper_pg_dir | |
7a847f81 | 489 | 3: .short (PTRS_PER_PTE-1) << 2 |
9b3a53ab | 490 | 4: .short (PTRS_PER_PGD-1) << 2 |
7a847f81 | 491 | 5: .long _PAGE_PRESENT |
9b3a53ab SM |
492 | 7: .long _PAGE_FLAGS_HARDWARE_MASK |
493 | 8: .long MMU_PTEH | |
494 | #ifdef COUNT_EXCEPTIONS | |
495 | 9: .long exception_count_miss | |
496 | #endif | |
497 | ||
498 | ! Either pgd or pte not present | |
499 | 20: mov.l 1f, k2 | |
1da177e4 LT |
500 | mov.l 4f, k3 |
501 | bra handle_exception | |
502 | mov.l @k2, k2 | |
503 | ! | |
504 | .balign 512,0,512 | |
505 | interrupt: | |
506 | mov.l 2f, k2 | |
507 | mov.l 3f, k3 | |
508 | #if defined(CONFIG_KGDB_NMI) | |
509 | ! Debounce (filter nested NMI) | |
510 | mov.l @k2, k0 | |
511 | mov.l 5f, k1 | |
512 | cmp/eq k1, k0 | |
513 | bf 0f | |
514 | mov.l 6f, k1 | |
515 | tas.b @k1 | |
516 | bt 0f | |
517 | rte | |
518 | nop | |
519 | .align 2 | |
520 | 5: .long NMI_VEC | |
521 | 6: .long in_nmi | |
522 | 0: | |
523 | #endif /* defined(CONFIG_KGDB_NMI) */ | |
524 | bra handle_exception | |
baf4326e | 525 | mov #-1, k2 ! interrupt exception marker |
1da177e4 LT |
526 | |
527 | .align 2 | |
528 | 1: .long EXPEVT | |
529 | 2: .long INTEVT | |
530 | 3: .long ret_from_irq | |
531 | 4: .long ret_from_exception | |
532 | ||
533 | ! | |
534 | ! | |
535 | .align 2 | |
3aa770e7 | 536 | ENTRY(handle_exception) |
1da177e4 LT |
537 | ! Using k0, k1 for scratch registers (r0_bank1, r1_bank), |
538 | ! save all registers onto stack. | |
539 | ! | |
540 | stc ssr, k0 ! Is it from kernel space? | |
541 | shll k0 ! Check MD bit (bit30) by shifting it into... | |
542 | shll k0 ! ...the T bit | |
543 | bt/s 1f ! It's a kernel to kernel transition. | |
544 | mov r15, k0 ! save original stack to k0 | |
545 | /* User space to kernel */ | |
510c72ad | 546 | mov #(THREAD_SIZE >> 10), k1 |
a6a31139 | 547 | shll8 k1 ! k1 := THREAD_SIZE |
510c72ad | 548 | shll2 k1 |
1da177e4 LT |
549 | add current, k1 |
550 | mov k1, r15 ! change to kernel stack | |
551 | ! | |
baf4326e | 552 | 1: mov.l 2f, k1 |
1da177e4 LT |
553 | ! |
554 | #ifdef CONFIG_SH_DSP | |
555 | mov.l r2, @-r15 ! Save r2, we need another reg | |
556 | stc sr, k4 | |
557 | mov.l 1f, r2 | |
558 | tst r2, k4 ! Check if in DSP mode | |
559 | mov.l @r15+, r2 ! Restore r2 now | |
560 | bt/s skip_save | |
561 | mov #0, k4 ! Set marker for no stack frame | |
562 | ||
563 | mov r2, k4 ! Backup r2 (in k4) for later | |
564 | ||
565 | ! Save DSP registers on stack | |
566 | stc.l mod, @-r15 | |
567 | stc.l re, @-r15 | |
568 | stc.l rs, @-r15 | |
569 | sts.l dsr, @-r15 | |
570 | sts.l y1, @-r15 | |
571 | sts.l y0, @-r15 | |
572 | sts.l x1, @-r15 | |
573 | sts.l x0, @-r15 | |
574 | sts.l a0, @-r15 | |
575 | ||
576 | ! GAS is broken, does not generate correct "movs.l Ds,@-As" instr. | |
577 | ||
578 | ! FIXME: Make sure that this is still the case with newer toolchains, | |
579 | ! as we're not at all interested in supporting ancient toolchains at | |
580 | ! this point. -- PFM. | |
581 | ||
582 | mov r15, r2 | |
583 | .word 0xf653 ! movs.l a1, @-r2 | |
584 | .word 0xf6f3 ! movs.l a0g, @-r2 | |
585 | .word 0xf6d3 ! movs.l a1g, @-r2 | |
586 | .word 0xf6c3 ! movs.l m0, @-r2 | |
587 | .word 0xf6e3 ! movs.l m1, @-r2 | |
588 | mov r2, r15 | |
589 | ||
590 | mov k4, r2 ! Restore r2 | |
591 | mov.l 1f, k4 ! Force DSP stack frame | |
592 | skip_save: | |
593 | mov.l k4, @-r15 ! Push DSP mode marker onto stack | |
594 | #endif | |
595 | ! Save the user registers on the stack. | |
596 | mov.l k2, @-r15 ! EXPEVT | |
baf4326e | 597 | |
de398406 | 598 | mov #-1, k4 |
1da177e4 LT |
599 | mov.l k4, @-r15 ! set TRA (default: -1) |
600 | ! | |
601 | sts.l macl, @-r15 | |
602 | sts.l mach, @-r15 | |
603 | stc.l gbr, @-r15 | |
604 | stc.l ssr, @-r15 | |
605 | sts.l pr, @-r15 | |
606 | stc.l spc, @-r15 | |
607 | ! | |
608 | lds k3, pr ! Set the return address to pr | |
609 | ! | |
610 | mov.l k0, @-r15 ! save orignal stack | |
611 | mov.l r14, @-r15 | |
612 | mov.l r13, @-r15 | |
613 | mov.l r12, @-r15 | |
614 | mov.l r11, @-r15 | |
615 | mov.l r10, @-r15 | |
616 | mov.l r9, @-r15 | |
617 | mov.l r8, @-r15 | |
618 | ! | |
619 | stc sr, r8 ! Back to normal register bank, and | |
620 | or k1, r8 ! Block all interrupts | |
621 | mov.l 3f, k1 | |
622 | and k1, r8 ! ... | |
623 | ldc r8, sr ! ...changed here. | |
624 | ! | |
625 | mov.l r7, @-r15 | |
626 | mov.l r6, @-r15 | |
627 | mov.l r5, @-r15 | |
628 | mov.l r4, @-r15 | |
629 | mov.l r3, @-r15 | |
630 | mov.l r2, @-r15 | |
631 | mov.l r1, @-r15 | |
632 | mov.l r0, @-r15 | |
baf4326e PM |
633 | |
634 | /* | |
635 | * This gets a bit tricky.. in the INTEVT case we don't want to use | |
636 | * the VBR offset as a destination in the jump call table, since all | |
637 | * of the destinations are the same. In this case, (interrupt) sets | |
638 | * a marker in r2 (now r2_bank since SR.RB changed), which we check | |
639 | * to determine the exception type. For all other exceptions, we | |
640 | * forcibly read EXPEVT from memory and fix up the jump address, in | |
641 | * the interrupt exception case we jump to do_IRQ() and defer the | |
642 | * INTEVT read until there. As a bonus, we can also clean up the SR.RB | |
643 | * checks that do_IRQ() was doing.. | |
644 | */ | |
645 | stc r2_bank, r8 | |
646 | cmp/pz r8 | |
647 | bf interrupt_exception | |
1da177e4 LT |
648 | shlr2 r8 |
649 | shlr r8 | |
9b3a53ab SM |
650 | |
651 | #ifdef COUNT_EXCEPTIONS | |
652 | mov.l 5f, r9 | |
653 | add r8, r9 | |
654 | mov.l @r9, r10 | |
655 | add #1, r10 | |
656 | mov.l r10, @r9 | |
657 | #endif | |
658 | ||
1da177e4 LT |
659 | mov.l 4f, r9 |
660 | add r8, r9 | |
661 | mov.l @r9, r9 | |
662 | jmp @r9 | |
663 | nop | |
baf4326e PM |
664 | rts |
665 | nop | |
1da177e4 LT |
666 | |
667 | .align 2 | |
668 | 1: .long 0x00001000 ! DSP=1 | |
669 | 2: .long 0x000080f0 ! FD=1, IMASK=15 | |
670 | 3: .long 0xcfffffff ! RB=0, BL=0 | |
671 | 4: .long exception_handling_table | |
9b3a53ab SM |
672 | #ifdef COUNT_EXCEPTIONS |
673 | 5: .long exception_count_table | |
674 | #endif | |
1da177e4 | 675 | |
baf4326e PM |
676 | interrupt_exception: |
677 | mov.l 1f, r9 | |
678 | jmp @r9 | |
679 | nop | |
680 | rts | |
681 | nop | |
682 | ||
683 | .align 2 | |
684 | 1: .long do_IRQ | |
685 | ||
1da177e4 LT |
686 | .align 2 |
687 | ENTRY(exception_none) | |
688 | rts | |
689 | nop |