sh: nmi_debug support.
[linux-block.git] / arch / sh / kernel / cpu / sh3 / entry.S
CommitLineData
baf4326e 1/*
58862699 2 * arch/sh/kernel/cpu/sh3/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>
db2e1fa3 16#include <asm/unistd.h>
f15cbe6f 17#include <cpu/mmu_context.h>
1efe4ce3 18#include <asm/page.h>
1d015cf0 19#include <asm/cache.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 */
ab6e570b 56#if defined(CONFIG_KGDB)
1da177e4
LT
57NMI_VEC = 0x1c0 ! Must catch early for debounce
58#endif
59
60/* Offsets to the stack */
61OFF_R0 = 0 /* Return value. New ABI also arg4 */
62OFF_R1 = 4 /* New ABI: arg5 */
63OFF_R2 = 8 /* New ABI: arg6 */
64OFF_R3 = 12 /* New ABI: syscall_nr */
65OFF_R4 = 16 /* New ABI: arg0 */
66OFF_R5 = 20 /* New ABI: arg1 */
67OFF_R6 = 24 /* New ABI: arg2 */
68OFF_R7 = 28 /* New ABI: arg3 */
69OFF_SP = (15*4)
70OFF_PC = (16*4)
71OFF_SR = (16*4+8)
72OFF_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
115ENTRY(tlb_miss_load)
112e5847 116 bra call_handle_tlbmiss
1da177e4
LT
117 mov #0, r5
118
119 .align 2
120ENTRY(tlb_miss_store)
112e5847 121 bra call_handle_tlbmiss
1da177e4
LT
122 mov #1, r5
123
124 .align 2
125ENTRY(initial_page_write)
112e5847 126 bra call_handle_tlbmiss
8010fbe7 127 mov #2, r5
1da177e4
LT
128
129 .align 2
130ENTRY(tlb_protection_violation_load)
112e5847 131 bra call_do_page_fault
1da177e4
LT
132 mov #0, r5
133
134 .align 2
135ENTRY(tlb_protection_violation_store)
112e5847 136 bra call_do_page_fault
1da177e4
LT
137 mov #1, r5
138
112e5847 139call_handle_tlbmiss:
0b930489 140 setup_frame_reg
1da177e4 141 mov.l 1f, r0
db2e1fa3
PM
142 mov r5, r8
143 mov.l @r0, r6
db2e1fa3
PM
144 mov.l 2f, r0
145 sts pr, r10
146 jsr @r0
147 mov r15, r4
148 !
149 tst r0, r0
150 bf/s 0f
151 lds r10, pr
152 rts
153 nop
112e5847 1540:
db2e1fa3 155 mov r8, r5
112e5847
PM
156call_do_page_fault:
157 mov.l 1f, r0
158 mov.l @r0, r6
159
160 sti
161
162 mov.l 3f, r0
163 mov.l 4f, r1
164 mov r15, r4
1da177e4 165 jmp @r0
112e5847 166 lds r1, pr
1da177e4
LT
167
168 .align 2
1691: .long MMU_TEA
112e5847 1702: .long handle_tlbmiss
1da177e4 1713: .long do_page_fault
112e5847 1724: .long ret_from_exception
1da177e4
LT
173
174 .align 2
175ENTRY(address_error_load)
176 bra call_dae
177 mov #0,r5 ! writeaccess = 0
178
179 .align 2
180ENTRY(address_error_store)
181 bra call_dae
182 mov #1,r5 ! writeaccess = 1
183
184 .align 2
185call_dae:
186 mov.l 1f, r0
187 mov.l @r0, r6 ! address
188 mov.l 2f, r0
189 jmp @r0
190 mov r15, r4 ! regs
191
192 .align 2
1931: .long MMU_TEA
1942: .long do_address_error
195#endif /* CONFIG_MMU */
196
1da177e4
LT
197#if defined(CONFIG_SH_STANDARD_BIOS)
198 /* Unwind the stack and jmp to the debug entry */
f413d0d9 199ENTRY(sh_bios_handler)
1dd22722
MD
200 mov.l 1f, r8
201 bsr restore_regs
202 nop
203
204 lds k2, pr ! restore pr
205 mov k4, r15
1da177e4
LT
206 !
207 mov.l 2f, k0
208 mov.l @k0, k0
209 jmp @k0
1dd22722 210 ldc k3, ssr
1da177e4
LT
211 .align 2
2121: .long 0x300000f0
2132: .long gdb_vbr_vector
214#endif /* CONFIG_SH_STANDARD_BIOS */
215
1dd22722
MD
216! restore_regs()
217! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
218! - switch bank
219! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
220! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
221! k2 returns original pr
222! k3 returns original sr
223! k4 returns original stack pointer
224! r8 passes SR bitmask, overwritten with restored data on return
225! r9 trashed
226! BL=0 on entry, on exit BL=1 (depending on r8).
227
2ef7f0da 228ENTRY(restore_regs)
1da177e4
LT
229 mov.l @r15+, r0
230 mov.l @r15+, r1
231 mov.l @r15+, r2
232 mov.l @r15+, r3
233 mov.l @r15+, r4
234 mov.l @r15+, r5
235 mov.l @r15+, r6
236 mov.l @r15+, r7
237 !
1dd22722
MD
238 stc sr, r9
239 or r8, r9
240 ldc r9, sr
1da177e4
LT
241 !
242 mov.l @r15+, r8
243 mov.l @r15+, r9
244 mov.l @r15+, r10
245 mov.l @r15+, r11
246 mov.l @r15+, r12
247 mov.l @r15+, r13
248 mov.l @r15+, r14
249 mov.l @r15+, k4 ! original stack pointer
250 ldc.l @r15+, spc
1dd22722 251 mov.l @r15+, k2 ! original PR
1da177e4
LT
252 mov.l @r15+, k3 ! original SR
253 ldc.l @r15+, gbr
254 lds.l @r15+, mach
255 lds.l @r15+, macl
1dd22722
MD
256 rts
257 add #4, r15 ! Skip syscall number
258
259restore_all:
260 mov.l 7f, r8
261 bsr restore_regs
262 nop
263
264 lds k2, pr ! restore pr
1da177e4 265 !
1da177e4
LT
266 ! Calculate new SR value
267 mov k3, k2 ! original SR value
fea966f7 268 mov #0xfffffff0, k1
de398406
YS
269 extu.b k1, k1
270 not k1, k1
1d015cf0 271 and k1, k2 ! Mask original SR value
1da177e4
LT
272 !
273 mov k3, k0 ! Calculate IMASK-bits
274 shlr2 k0
275 and #0x3c, k0
276 cmp/eq #0x3c, k0
277 bt/s 6f
278 shll2 k0
279 mov g_imask, k0
280 !
2816: or k0, k2 ! Set the IMASK-bits
282 ldc k2, ssr
283 !
ab6e570b 284#if defined(CONFIG_KGDB)
1da177e4 285 ! Clear in_nmi
6ae5e8d7 286 mov.l 6f, k0
1da177e4
LT
287 mov #0, k1
288 mov.b k1, @k0
289#endif
1da177e4
LT
290 mov k4, r15
291 rte
292 nop
293
294 .align 2
1da177e4 2955: .long 0x00001000 ! DSP
ab6e570b 296#ifdef CONFIG_KGDB
370ac91a 2976: .long in_nmi
c596b1a3 298#endif
1da177e4 2997: .long 0x30000000
1da177e4 300
de398406 301! common exception handler
716067f2 302#include "../../entry-common.S"
de398406 303
1da177e4
LT
304! Exception Vector Base
305!
306! Should be aligned page boundary.
307!
308 .balign 4096,0,4096
309ENTRY(vbr_base)
310 .long 0
1d015cf0
MD
311!
312! 0x100: General exception vector
1da177e4
LT
313!
314 .balign 256,0,256
315general_exception:
1d015cf0
MD
316#ifndef CONFIG_CPU_SUBTYPE_SHX3
317 bra handle_exception
318 sts pr, k3 ! save original pr value in k3
319#else
320 mov.l 1f, k4
321 mov.l @k4, k4
2b1bd1ac
PM
322
323 ! Is EXPEVT larger than 0x800?
324 mov #0x8, k0
325 shll8 k0
1d015cf0 326 cmp/hs k0, k4
2b1bd1ac
PM
327 bf 0f
328
329 ! then add 0x580 (k2 is 0xd80 or 0xda0)
330 mov #0x58, k0
331 shll2 k0
332 shll2 k0
1d015cf0 333 add k0, k4
2b1bd1ac 3340:
1d015cf0 335 ! Setup stack and save DSP context (k0 contains original r15 on return)
01ab1039 336 bsr prepare_stack
2b1bd1ac 337 nop
9b3a53ab 338
1d015cf0 339 ! Save registers / Switch to bank 0
7a516280 340 mov k4, k2 ! keep vector in k2
2ef7f0da 341 mov.l 1f, k4 ! SR bits to clear in k4
1d015cf0 342 bsr save_regs ! needs original pr value in k3
2ef7f0da 343 nop
1d015cf0
MD
344
345 bra handle_exception_special
1da177e4 346 nop
1da177e4
LT
347
348 .align 2
3491: .long EXPEVT
1d015cf0 350#endif
1da177e4 351
01ab1039 352! prepare_stack()
1d015cf0
MD
353! - roll back gRB
354! - switch to kernel stack
1d015cf0
MD
355! k0 returns original sp (after roll back)
356! k1 trashed
357! k2 trashed
1efe4ce3 358
01ab1039 359prepare_stack:
1efe4ce3
SM
360#ifdef CONFIG_GUSA
361 ! Check for roll back gRB (User and Kernel)
362 mov r15, k0
363 shll k0
364 bf/s 1f
365 shll k0
366 bf/s 1f
367 stc spc, k1
368 stc r0_bank, k0
369 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0)
370 bt/s 2f
371 stc r1_bank, k1
372
373 add #-2, k0
374 add r15, k0
375 ldc k0, spc ! PC = saved r0 + r15 - 2
3762: mov k1, r15 ! SP = r1
3771:
378#endif
1d015cf0 379 ! Switch to kernel stack if needed
1da177e4
LT
380 stc ssr, k0 ! Is it from kernel space?
381 shll k0 ! Check MD bit (bit30) by shifting it into...
382 shll k0 ! ...the T bit
383 bt/s 1f ! It's a kernel to kernel transition.
384 mov r15, k0 ! save original stack to k0
385 /* User space to kernel */
510c72ad 386 mov #(THREAD_SIZE >> 10), k1
a6a31139 387 shll8 k1 ! k1 := THREAD_SIZE
510c72ad 388 shll2 k1
1da177e4
LT
389 add current, k1
390 mov k1, r15 ! change to kernel stack
391 !
1d015cf0 3921:
1d015cf0
MD
393 rts
394 nop
01ab1039 395
1d015cf0
MD
396!
397! 0x400: Instruction and Data TLB miss exception vector
398!
399 .balign 1024,0,1024
400tlb_miss:
401 sts pr, k3 ! save original pr value in k3
baf4326e 402
1d015cf0 403handle_exception:
0197f21c
MD
404 mova exception_data, k0
405
1d015cf0 406 ! Setup stack and save DSP context (k0 contains original r15 on return)
01ab1039 407 bsr prepare_stack
0197f21c 408 PREF(k0)
1d015cf0
MD
409
410 ! Save registers / Switch to bank 0
411 mov.l 5f, k2 ! vector register address
2ef7f0da 412 mov.l 1f, k4 ! SR bits to clear in k4
1d015cf0
MD
413 bsr save_regs ! needs original pr value in k3
414 mov.l @k2, k2 ! read out vector and keep in k2
415
416handle_exception_special:
417 ! Setup return address and jump to exception handler
418 mov.l 7f, r9 ! fetch return address
419 stc r2_bank, r0 ! k2 (vector)
420 mov.l 6f, r10
421 shlr2 r0
422 shlr r0
423 mov.l @(r0, r10), r10
424 jmp @r10
425 lds r9, pr ! put return address in pr
426
427 .align L1_CACHE_SHIFT
428
429! save_regs()
4f099ebb 430! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
1d015cf0
MD
431! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
432! - switch bank
433! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
434! k0 contains original stack pointer*
435! k1 trashed
1d015cf0 436! k3 passes original pr*
2ef7f0da 437! k4 passes SR bitmask
1d015cf0
MD
438! BL=1 on entry, on exit BL=0.
439
2ef7f0da 440ENTRY(save_regs)
1d015cf0 441 mov #-1, r1
1d015cf0 442 mov.l k1, @-r15 ! set TRA (default: -1)
1da177e4
LT
443 sts.l macl, @-r15
444 sts.l mach, @-r15
445 stc.l gbr, @-r15
446 stc.l ssr, @-r15
1d015cf0 447 mov.l k3, @-r15 ! original pr in k3
1da177e4 448 stc.l spc, @-r15
1d015cf0
MD
449
450 mov.l k0, @-r15 ! original stack pointer in k0
1da177e4
LT
451 mov.l r14, @-r15
452 mov.l r13, @-r15
453 mov.l r12, @-r15
454 mov.l r11, @-r15
455 mov.l r10, @-r15
456 mov.l r9, @-r15
457 mov.l r8, @-r15
1d015cf0
MD
458
459 mov.l 0f, k3 ! SR bits to set in k3
1d015cf0 460
2ef7f0da
MD
461 ! fall-through
462
463! save_low_regs()
464! - modify SR for bank switch
465! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
466! k3 passes bits to set in SR
467! k4 passes bits to clear in SR
468
469ENTRY(save_low_regs)
1d015cf0
MD
470 stc sr, r8
471 or k3, r8
472 and k4, r8
473 ldc r8, sr
474
1da177e4
LT
475 mov.l r7, @-r15
476 mov.l r6, @-r15
477 mov.l r5, @-r15
478 mov.l r4, @-r15
479 mov.l r3, @-r15
480 mov.l r2, @-r15
481 mov.l r1, @-r15
baf4326e 482 rts
1d015cf0 483 mov.l r0, @-r15
1da177e4 484
1d015cf0
MD
485!
486! 0x600: Interrupt / NMI vector
487!
488 .balign 512,0,512
489ENTRY(handle_interrupt)
490#if defined(CONFIG_KGDB)
491 mov.l 2f, k2
492 ! Debounce (filter nested NMI)
493 mov.l @k2, k0
494 mov.l 9f, k1
495 cmp/eq k1, k0
496 bf 11f
497 mov.l 10f, k1
498 tas.b @k1
499 bt 11f
500 rte
501 nop
1da177e4 502 .align 2
1d015cf0
MD
5039: .long NMI_VEC
50410: .long in_nmi
50511:
506#endif /* defined(CONFIG_KGDB) */
507 sts pr, k3 ! save original pr value in k3
0197f21c 508 mova exception_data, k0
1da177e4 509
1d015cf0 510 ! Setup stack and save DSP context (k0 contains original r15 on return)
01ab1039 511 bsr prepare_stack
0197f21c 512 PREF(k0)
baf4326e 513
1d015cf0 514 ! Save registers / Switch to bank 0
2ef7f0da 515 mov.l 1f, k4 ! SR bits to clear in k4
1d015cf0
MD
516 bsr save_regs ! needs original pr value in k3
517 mov #-1, k2 ! default vector kept in k2
518
fe98dd31
MF
519 setup_frame_reg
520
f3a83088
MF
521 stc sr, r0 ! get status register
522 shlr2 r0
523 and #0x3c, r0
524 cmp/eq #0x3c, r0
525 bf 9f
526 TRACE_IRQS_OFF
5279:
528
1d015cf0
MD
529 ! Setup return address and jump to do_IRQ
530 mov.l 4f, r9 ! fetch return address
531 lds r9, pr ! put return address in pr
532 mov.l 2f, r4
533 mov.l 3f, r9
534 mov.l @r4, r4 ! pass INTEVT vector as arg0
1e1030dc
PM
535
536 shlr2 r4
537 shlr r4
538 mov r4, r0 ! save vector->jmp table offset for later
539
540 shlr2 r4 ! vector to IRQ# conversion
541 add #-0x10, r4
542
543 cmp/pz r4 ! is it a valid IRQ?
544 bt 10f
545
546 /*
547 * We got here as a result of taking the INTEVT path for something
548 * that isn't a valid hard IRQ, therefore we bypass the do_IRQ()
549 * path and special case the event dispatch instead. This is the
550 * expected path for the NMI (and any other brilliantly implemented
551 * exception), which effectively wants regular exception dispatch
552 * but is unfortunately reported through INTEVT rather than
553 * EXPEVT. Grr.
554 */
555 mov.l 6f, r9
556 mov.l @(r0, r9), r9
1d015cf0 557 jmp @r9
1e1030dc
PM
558 mov r15, r8 ! trap handlers take saved regs in r8
559
56010:
561 jmp @r9 ! Off to do_IRQ() we go.
1d015cf0 562 mov r15, r5 ! pass saved registers as arg1
baf4326e 563
1da177e4
LT
564ENTRY(exception_none)
565 rts
566 nop
1d015cf0
MD
567
568 .align L1_CACHE_SHIFT
569exception_data:
5700: .long 0x000080f0 ! FD=1, IMASK=15
5711: .long 0xcfffffff ! RB=0, BL=0
5722: .long INTEVT
5733: .long do_IRQ
5744: .long ret_from_irq
5755: .long EXPEVT
5766: .long exception_handling_table
5777: .long ret_from_exception