sh: Compile fix for heartbeat consolidation.
[linux-block.git] / arch / sh / kernel / cpu / sh3 / entry.S
CommitLineData
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)
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:
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
1481: .long MMU_TEA
1da177e4
LT
1493: .long do_page_fault
150
151 .align 2
152ENTRY(address_error_load)
153 bra call_dae
154 mov #0,r5 ! writeaccess = 0
155
156 .align 2
157ENTRY(address_error_store)
158 bra call_dae
159 mov #1,r5 ! writeaccess = 1
160
161 .align 2
162call_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
1701: .long MMU_TEA
1712: .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 176ENTRY(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
2101: .long 0x300000f0
2112: .long gdb_vbr_vector
212#endif /* CONFIG_SH_STANDARD_BIOS */
213
1da177e4
LT
214restore_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
276skip_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 !
2946: 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
3095: .long 0x00001000 ! DSP
3107: .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
320ENTRY(vbr_base)
321 .long 0
322!
323 .balign 256,0,256
324general_exception:
325 mov.l 1f, k2
326 mov.l 2f, k3
327 bra handle_exception
328 mov.l @k2, k2
329 .align 2
3301: .long EXPEVT
3312: .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
353tlb_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
47210: 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...
4881: .long swapper_pg_dir
7a847f81 4893: .short (PTRS_PER_PTE-1) << 2
9b3a53ab 4904: .short (PTRS_PER_PGD-1) << 2
7a847f81 4915: .long _PAGE_PRESENT
9b3a53ab
SM
4927: .long _PAGE_FLAGS_HARDWARE_MASK
4938: .long MMU_PTEH
494#ifdef COUNT_EXCEPTIONS
4959: .long exception_count_miss
496#endif
497
498 ! Either pgd or pte not present
49920: 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
505interrupt:
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
5205: .long NMI_VEC
5216: .long in_nmi
5220:
523#endif /* defined(CONFIG_KGDB_NMI) */
524 bra handle_exception
baf4326e 525 mov #-1, k2 ! interrupt exception marker
1da177e4
LT
526
527 .align 2
5281: .long EXPEVT
5292: .long INTEVT
5303: .long ret_from_irq
5314: .long ret_from_exception
532
533!
534!
535 .align 2
3aa770e7 536ENTRY(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 5521: 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
592skip_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
6681: .long 0x00001000 ! DSP=1
6692: .long 0x000080f0 ! FD=1, IMASK=15
6703: .long 0xcfffffff ! RB=0, BL=0
6714: .long exception_handling_table
9b3a53ab
SM
672#ifdef COUNT_EXCEPTIONS
6735: .long exception_count_table
674#endif
1da177e4 675
baf4326e
PM
676interrupt_exception:
677 mov.l 1f, r9
678 jmp @r9
679 nop
680 rts
681 nop
682
683 .align 2
6841: .long do_IRQ
685
1da177e4
LT
686 .align 2
687ENTRY(exception_none)
688 rts
689 nop