sh: unwinder: Introduce UNWINDER_BUG() and UNWINDER_BUG_ON()
[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)
116 bra call_dpf
117 mov #0, r5
118
119 .align 2
120ENTRY(tlb_miss_store)
121 bra call_dpf
122 mov #1, r5
123
124 .align 2
125ENTRY(initial_page_write)
126 bra call_dpf
127 mov #1, r5
128
129 .align 2
130ENTRY(tlb_protection_violation_load)
131 bra call_dpf
132 mov #0, r5
133
134 .align 2
135ENTRY(tlb_protection_violation_store)
136 bra call_dpf
137 mov #1, r5
138
139call_dpf:
0b930489 140 setup_frame_reg
1da177e4 141 mov.l 1f, r0
db2e1fa3
PM
142 mov r5, r8
143 mov.l @r0, r6
144 mov r6, r9
145 mov.l 2f, r0
146 sts pr, r10
147 jsr @r0
148 mov r15, r4
149 !
150 tst r0, r0
151 bf/s 0f
152 lds r10, pr
153 rts
154 nop
c347d12c 1550: mov.l 3f, r0
db2e1fa3
PM
156 mov r9, r6
157 mov r8, r5
1da177e4 158 jmp @r0
db2e1fa3 159 mov r15, r4
1da177e4
LT
160
161 .align 2
1621: .long MMU_TEA
db2e1fa3 1632: .long __do_page_fault
1da177e4
LT
1643: .long do_page_fault
165
166 .align 2
167ENTRY(address_error_load)
168 bra call_dae
169 mov #0,r5 ! writeaccess = 0
170
171 .align 2
172ENTRY(address_error_store)
173 bra call_dae
174 mov #1,r5 ! writeaccess = 1
175
176 .align 2
177call_dae:
178 mov.l 1f, r0
179 mov.l @r0, r6 ! address
180 mov.l 2f, r0
181 jmp @r0
182 mov r15, r4 ! regs
183
184 .align 2
1851: .long MMU_TEA
1862: .long do_address_error
187#endif /* CONFIG_MMU */
188
1da177e4
LT
189#if defined(CONFIG_SH_STANDARD_BIOS)
190 /* Unwind the stack and jmp to the debug entry */
f413d0d9 191ENTRY(sh_bios_handler)
1dd22722
MD
192 mov.l 1f, r8
193 bsr restore_regs
194 nop
195
196 lds k2, pr ! restore pr
197 mov k4, r15
1da177e4
LT
198 !
199 mov.l 2f, k0
200 mov.l @k0, k0
201 jmp @k0
1dd22722 202 ldc k3, ssr
1da177e4
LT
203 .align 2
2041: .long 0x300000f0
2052: .long gdb_vbr_vector
206#endif /* CONFIG_SH_STANDARD_BIOS */
207
1dd22722
MD
208! restore_regs()
209! - restore r0, r1, r2, r3, r4, r5, r6, r7 from the stack
210! - switch bank
211! - restore r8, r9, r10, r11, r12, r13, r14, r15 from the stack
212! - restore spc, pr*, ssr, gbr, mach, macl, skip default tra
213! k2 returns original pr
214! k3 returns original sr
215! k4 returns original stack pointer
216! r8 passes SR bitmask, overwritten with restored data on return
217! r9 trashed
218! BL=0 on entry, on exit BL=1 (depending on r8).
219
2ef7f0da 220ENTRY(restore_regs)
1da177e4
LT
221 mov.l @r15+, r0
222 mov.l @r15+, r1
223 mov.l @r15+, r2
224 mov.l @r15+, r3
225 mov.l @r15+, r4
226 mov.l @r15+, r5
227 mov.l @r15+, r6
228 mov.l @r15+, r7
229 !
1dd22722
MD
230 stc sr, r9
231 or r8, r9
232 ldc r9, sr
1da177e4
LT
233 !
234 mov.l @r15+, r8
235 mov.l @r15+, r9
236 mov.l @r15+, r10
237 mov.l @r15+, r11
238 mov.l @r15+, r12
239 mov.l @r15+, r13
240 mov.l @r15+, r14
241 mov.l @r15+, k4 ! original stack pointer
242 ldc.l @r15+, spc
1dd22722 243 mov.l @r15+, k2 ! original PR
1da177e4
LT
244 mov.l @r15+, k3 ! original SR
245 ldc.l @r15+, gbr
246 lds.l @r15+, mach
247 lds.l @r15+, macl
1dd22722
MD
248 rts
249 add #4, r15 ! Skip syscall number
250
251restore_all:
252 mov.l 7f, r8
253 bsr restore_regs
254 nop
255
256 lds k2, pr ! restore pr
1da177e4 257 !
1da177e4
LT
258 ! Calculate new SR value
259 mov k3, k2 ! original SR value
de398406
YS
260 mov #0xf0, k1
261 extu.b k1, k1
262 not k1, k1
1d015cf0 263 and k1, k2 ! Mask original SR value
1da177e4
LT
264 !
265 mov k3, k0 ! Calculate IMASK-bits
266 shlr2 k0
267 and #0x3c, k0
268 cmp/eq #0x3c, k0
269 bt/s 6f
270 shll2 k0
271 mov g_imask, k0
272 !
2736: or k0, k2 ! Set the IMASK-bits
274 ldc k2, ssr
275 !
ab6e570b 276#if defined(CONFIG_KGDB)
1da177e4 277 ! Clear in_nmi
6ae5e8d7 278 mov.l 6f, k0
1da177e4
LT
279 mov #0, k1
280 mov.b k1, @k0
281#endif
1da177e4
LT
282 mov k4, r15
283 rte
284 nop
285
286 .align 2
1da177e4 2875: .long 0x00001000 ! DSP
ab6e570b 288#ifdef CONFIG_KGDB
370ac91a 2896: .long in_nmi
c596b1a3 290#endif
1da177e4 2917: .long 0x30000000
1da177e4 292
de398406 293! common exception handler
716067f2 294#include "../../entry-common.S"
de398406 295
1da177e4
LT
296! Exception Vector Base
297!
298! Should be aligned page boundary.
299!
300 .balign 4096,0,4096
301ENTRY(vbr_base)
302 .long 0
1d015cf0
MD
303!
304! 0x100: General exception vector
1da177e4
LT
305!
306 .balign 256,0,256
307general_exception:
1d015cf0
MD
308#ifndef CONFIG_CPU_SUBTYPE_SHX3
309 bra handle_exception
310 sts pr, k3 ! save original pr value in k3
311#else
312 mov.l 1f, k4
313 mov.l @k4, k4
2b1bd1ac
PM
314
315 ! Is EXPEVT larger than 0x800?
316 mov #0x8, k0
317 shll8 k0
1d015cf0 318 cmp/hs k0, k4
2b1bd1ac
PM
319 bf 0f
320
321 ! then add 0x580 (k2 is 0xd80 or 0xda0)
322 mov #0x58, k0
323 shll2 k0
324 shll2 k0
1d015cf0 325 add k0, k4
2b1bd1ac 3260:
1d015cf0 327 ! Setup stack and save DSP context (k0 contains original r15 on return)
01ab1039 328 bsr prepare_stack
2b1bd1ac 329 nop
9b3a53ab 330
1d015cf0 331 ! Save registers / Switch to bank 0
7a516280 332 mov k4, k2 ! keep vector in k2
2ef7f0da 333 mov.l 1f, k4 ! SR bits to clear in k4
1d015cf0 334 bsr save_regs ! needs original pr value in k3
2ef7f0da 335 nop
1d015cf0
MD
336
337 bra handle_exception_special
1da177e4 338 nop
1da177e4
LT
339
340 .align 2
3411: .long EXPEVT
1d015cf0 342#endif
1da177e4 343
01ab1039 344! prepare_stack()
1d015cf0
MD
345! - roll back gRB
346! - switch to kernel stack
1d015cf0
MD
347! k0 returns original sp (after roll back)
348! k1 trashed
349! k2 trashed
1efe4ce3 350
01ab1039 351prepare_stack:
1efe4ce3
SM
352#ifdef CONFIG_GUSA
353 ! Check for roll back gRB (User and Kernel)
354 mov r15, k0
355 shll k0
356 bf/s 1f
357 shll k0
358 bf/s 1f
359 stc spc, k1
360 stc r0_bank, k0
361 cmp/hs k0, k1 ! test k1 (saved PC) >= k0 (saved r0)
362 bt/s 2f
363 stc r1_bank, k1
364
365 add #-2, k0
366 add r15, k0
367 ldc k0, spc ! PC = saved r0 + r15 - 2
3682: mov k1, r15 ! SP = r1
3691:
370#endif
1d015cf0 371 ! Switch to kernel stack if needed
1da177e4
LT
372 stc ssr, k0 ! Is it from kernel space?
373 shll k0 ! Check MD bit (bit30) by shifting it into...
374 shll k0 ! ...the T bit
375 bt/s 1f ! It's a kernel to kernel transition.
376 mov r15, k0 ! save original stack to k0
377 /* User space to kernel */
510c72ad 378 mov #(THREAD_SIZE >> 10), k1
a6a31139 379 shll8 k1 ! k1 := THREAD_SIZE
510c72ad 380 shll2 k1
1da177e4
LT
381 add current, k1
382 mov k1, r15 ! change to kernel stack
383 !
1d015cf0 3841:
1d015cf0
MD
385 rts
386 nop
01ab1039 387
1d015cf0
MD
388!
389! 0x400: Instruction and Data TLB miss exception vector
390!
391 .balign 1024,0,1024
392tlb_miss:
393 sts pr, k3 ! save original pr value in k3
baf4326e 394
1d015cf0 395handle_exception:
0197f21c
MD
396 mova exception_data, k0
397
1d015cf0 398 ! Setup stack and save DSP context (k0 contains original r15 on return)
01ab1039 399 bsr prepare_stack
0197f21c 400 PREF(k0)
1d015cf0
MD
401
402 ! Save registers / Switch to bank 0
403 mov.l 5f, k2 ! vector register address
2ef7f0da 404 mov.l 1f, k4 ! SR bits to clear in k4
1d015cf0
MD
405 bsr save_regs ! needs original pr value in k3
406 mov.l @k2, k2 ! read out vector and keep in k2
407
408handle_exception_special:
409 ! Setup return address and jump to exception handler
410 mov.l 7f, r9 ! fetch return address
411 stc r2_bank, r0 ! k2 (vector)
412 mov.l 6f, r10
413 shlr2 r0
414 shlr r0
415 mov.l @(r0, r10), r10
416 jmp @r10
417 lds r9, pr ! put return address in pr
418
419 .align L1_CACHE_SHIFT
420
421! save_regs()
4f099ebb 422! - save default tra, macl, mach, gbr, ssr, pr* and spc on the stack
1d015cf0
MD
423! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
424! - switch bank
425! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
426! k0 contains original stack pointer*
427! k1 trashed
1d015cf0 428! k3 passes original pr*
2ef7f0da 429! k4 passes SR bitmask
1d015cf0
MD
430! BL=1 on entry, on exit BL=0.
431
2ef7f0da 432ENTRY(save_regs)
1d015cf0 433 mov #-1, r1
1d015cf0 434 mov.l k1, @-r15 ! set TRA (default: -1)
1da177e4
LT
435 sts.l macl, @-r15
436 sts.l mach, @-r15
437 stc.l gbr, @-r15
438 stc.l ssr, @-r15
1d015cf0 439 mov.l k3, @-r15 ! original pr in k3
1da177e4 440 stc.l spc, @-r15
1d015cf0
MD
441
442 mov.l k0, @-r15 ! original stack pointer in k0
1da177e4
LT
443 mov.l r14, @-r15
444 mov.l r13, @-r15
445 mov.l r12, @-r15
446 mov.l r11, @-r15
447 mov.l r10, @-r15
448 mov.l r9, @-r15
449 mov.l r8, @-r15
1d015cf0
MD
450
451 mov.l 0f, k3 ! SR bits to set in k3
1d015cf0 452
2ef7f0da
MD
453 ! fall-through
454
455! save_low_regs()
456! - modify SR for bank switch
457! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
458! k3 passes bits to set in SR
459! k4 passes bits to clear in SR
460
461ENTRY(save_low_regs)
1d015cf0
MD
462 stc sr, r8
463 or k3, r8
464 and k4, r8
465 ldc r8, sr
466
1da177e4
LT
467 mov.l r7, @-r15
468 mov.l r6, @-r15
469 mov.l r5, @-r15
470 mov.l r4, @-r15
471 mov.l r3, @-r15
472 mov.l r2, @-r15
473 mov.l r1, @-r15
baf4326e 474 rts
1d015cf0 475 mov.l r0, @-r15
1da177e4 476
1d015cf0
MD
477!
478! 0x600: Interrupt / NMI vector
479!
480 .balign 512,0,512
481ENTRY(handle_interrupt)
482#if defined(CONFIG_KGDB)
483 mov.l 2f, k2
484 ! Debounce (filter nested NMI)
485 mov.l @k2, k0
486 mov.l 9f, k1
487 cmp/eq k1, k0
488 bf 11f
489 mov.l 10f, k1
490 tas.b @k1
491 bt 11f
492 rte
493 nop
1da177e4 494 .align 2
1d015cf0
MD
4959: .long NMI_VEC
49610: .long in_nmi
49711:
498#endif /* defined(CONFIG_KGDB) */
499 sts pr, k3 ! save original pr value in k3
0197f21c 500 mova exception_data, k0
1da177e4 501
1d015cf0 502 ! Setup stack and save DSP context (k0 contains original r15 on return)
01ab1039 503 bsr prepare_stack
0197f21c 504 PREF(k0)
baf4326e 505
1d015cf0 506 ! Save registers / Switch to bank 0
2ef7f0da 507 mov.l 1f, k4 ! SR bits to clear in k4
1d015cf0
MD
508 bsr save_regs ! needs original pr value in k3
509 mov #-1, k2 ! default vector kept in k2
510
511 ! Setup return address and jump to do_IRQ
512 mov.l 4f, r9 ! fetch return address
513 lds r9, pr ! put return address in pr
514 mov.l 2f, r4
515 mov.l 3f, r9
516 mov.l @r4, r4 ! pass INTEVT vector as arg0
517 jmp @r9
518 mov r15, r5 ! pass saved registers as arg1
baf4326e 519
1da177e4
LT
520ENTRY(exception_none)
521 rts
522 nop
1d015cf0
MD
523
524 .align L1_CACHE_SHIFT
525exception_data:
5260: .long 0x000080f0 ! FD=1, IMASK=15
5271: .long 0xcfffffff ! RB=0, BL=0
5282: .long INTEVT
5293: .long do_IRQ
5304: .long ret_from_irq
5315: .long EXPEVT
5326: .long exception_handling_table
5337: .long ret_from_exception