]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/sh/kernel/cpu/sh3/entry.S
sh: shared register saving code for sh3/sh4/sh4a
[linux-2.6-omap-h63xx.git] / arch / sh / kernel / cpu / sh3 / entry.S
1 /*
2  * arch/sh/kernel/cpu/sh3/entry.S
3  *
4  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
5  *  Copyright (C) 2003 - 2006  Paul Mundt
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.
10  */
11 #include <linux/sys.h>
12 #include <linux/errno.h>
13 #include <linux/linkage.h>
14 #include <asm/asm-offsets.h>
15 #include <asm/thread_info.h>
16 #include <asm/unistd.h>
17 #include <cpu/mmu_context.h>
18 #include <asm/page.h>
19 #include <asm/cache.h>
20
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  */
56 #if defined(CONFIG_KGDB)
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
81 #define g_imask         r6      /* r6_bank1 */
82 #define k_g_imask       r6_bank /* r6_bank1 */
83 #define current         r7      /* r7_bank1 */
84
85 #include <asm/entry-macros.S>
86         
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
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
141         mov     r5, r8
142         mov.l   @r0, r6
143         mov     r6, r9
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
154 0:      mov.l   3f, r0
155         mov     r9, r6
156         mov     r8, r5
157         jmp     @r0
158          mov    r15, r4
159
160         .align 2
161 1:      .long   MMU_TEA
162 2:      .long   __do_page_fault
163 3:      .long   do_page_fault
164
165         .align  2
166 ENTRY(address_error_load)
167         bra     call_dae
168          mov    #0,r5           ! writeaccess = 0
169
170         .align  2
171 ENTRY(address_error_store)
172         bra     call_dae
173          mov    #1,r5           ! writeaccess = 1
174
175         .align  2
176 call_dae:
177         mov.l   1f, r0
178         mov.l   @r0, r6         ! address
179         mov.l   2f, r0
180         jmp     @r0
181          mov    r15, r4         ! regs
182
183         .align 2
184 1:      .long   MMU_TEA
185 2:      .long   do_address_error
186 #endif /* CONFIG_MMU */
187
188 #if defined(CONFIG_SH_STANDARD_BIOS)
189         /* Unwind the stack and jmp to the debug entry */
190 ENTRY(sh_bios_handler)
191         mov.l   @r15+, r0
192         mov.l   @r15+, r1
193         mov.l   @r15+, r2
194         mov.l   @r15+, r3
195         mov.l   @r15+, r4
196         mov.l   @r15+, r5
197         mov.l   @r15+, r6
198         mov.l   @r15+, r7
199         stc     sr, r8
200         mov.l   1f, r9                  ! BL =1, RB=1, IMASK=0x0F
201         or      r9, r8
202         ldc     r8, sr                  ! here, change the register bank
203         mov.l   @r15+, r8
204         mov.l   @r15+, r9
205         mov.l   @r15+, r10
206         mov.l   @r15+, r11
207         mov.l   @r15+, r12
208         mov.l   @r15+, r13
209         mov.l   @r15+, r14
210         mov.l   @r15+, k0
211         ldc.l   @r15+, spc
212         lds.l   @r15+, pr
213         mov.l   @r15+, k1
214         ldc.l   @r15+, gbr
215         lds.l   @r15+, mach
216         lds.l   @r15+, macl
217         mov     k0, r15
218         !
219         mov.l   2f, k0
220         mov.l   @k0, k0
221         jmp     @k0
222          ldc    k1, ssr
223         .align  2
224 1:      .long   0x300000f0
225 2:      .long   gdb_vbr_vector
226 #endif /* CONFIG_SH_STANDARD_BIOS */
227
228 restore_all:
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         !
238         stc     sr, r8
239         mov.l   7f, r9
240         or      r9, r8                  ! BL =1, RB=1
241         ldc     r8, sr                  ! here, change the register bank
242         !
243         mov.l   @r15+, r8
244         mov.l   @r15+, r9
245         mov.l   @r15+, r10
246         mov.l   @r15+, r11
247         mov.l   @r15+, r12
248         mov.l   @r15+, r13
249         mov.l   @r15+, r14
250         mov.l   @r15+, k4               ! original stack pointer
251         ldc.l   @r15+, spc
252         lds.l   @r15+, pr
253         mov.l   @r15+, k3               ! original SR
254         ldc.l   @r15+, gbr
255         lds.l   @r15+, mach
256         lds.l   @r15+, macl
257         add     #4, r15                 ! Skip syscall number
258         !
259 #ifdef CONFIG_SH_DSP
260         mov.l   @r15+, k0               ! DSP mode marker
261         mov.l   5f, k1
262         cmp/eq  k0, k1                  ! Do we have a DSP stack frame?
263         bf      skip_restore
264
265         stc     sr, k0                  ! Enable CPU DSP mode
266         or      k1, k0                  ! (within kernel it may be disabled)
267         ldc     k0, sr
268         mov     r2, k0                  ! Backup r2
269
270         ! Restore DSP registers from stack
271         mov     r15, r2
272         movs.l  @r2+, a1
273         movs.l  @r2+, a0g
274         movs.l  @r2+, a1g
275         movs.l  @r2+, m0
276         movs.l  @r2+, m1
277         mov     r2, r15
278
279         lds.l   @r15+, a0
280         lds.l   @r15+, x0
281         lds.l   @r15+, x1
282         lds.l   @r15+, y0
283         lds.l   @r15+, y1
284         lds.l   @r15+, dsr
285         ldc.l   @r15+, rs
286         ldc.l   @r15+, re
287         ldc.l   @r15+, mod
288
289         mov     k0, r2                  ! Restore r2
290 skip_restore:
291 #endif
292         !
293         ! Calculate new SR value
294         mov     k3, k2                  ! original SR value
295         mov     #0xf0, k1
296         extu.b  k1, k1
297         not     k1, k1
298         and     k1, k2                  ! Mask original SR value
299         !
300         mov     k3, k0                  ! Calculate IMASK-bits
301         shlr2   k0
302         and     #0x3c, k0
303         cmp/eq  #0x3c, k0
304         bt/s    6f
305          shll2  k0
306         mov     g_imask, k0
307         !
308 6:      or      k0, k2                  ! Set the IMASK-bits
309         ldc     k2, ssr
310         !
311 #if defined(CONFIG_KGDB)
312         ! Clear in_nmi
313         mov.l   6f, k0
314         mov     #0, k1
315         mov.b   k1, @k0
316 #endif
317         mov.l   @r15+, k2               ! restore EXPEVT
318         mov     k4, r15
319         rte
320          nop
321
322         .align  2
323 5:      .long   0x00001000      ! DSP
324 #ifdef CONFIG_KGDB
325 6:      .long   in_nmi
326 #endif
327 7:      .long   0x30000000
328
329 ! common exception handler
330 #include "../../entry-common.S"
331         
332 ! Exception Vector Base
333 !
334 !       Should be aligned page boundary.
335 !
336         .balign         4096,0,4096
337 ENTRY(vbr_base)
338         .long   0
339 !
340 ! 0x100: General exception vector
341 !
342         .balign         256,0,256
343 general_exception:
344 #ifndef CONFIG_CPU_SUBTYPE_SHX3
345         bra     handle_exception
346          sts    pr, k3          ! save original pr value in k3
347 #else
348         mov.l   1f, k4
349         mov.l   @k4, k4
350
351         ! Is EXPEVT larger than 0x800?
352         mov     #0x8, k0
353         shll8   k0
354         cmp/hs  k0, k4
355         bf      0f
356
357         ! then add 0x580 (k2 is 0xd80 or 0xda0)
358         mov     #0x58, k0
359         shll2   k0
360         shll2   k0
361         add     k0, k4
362 0:
363         ! Setup stack and save DSP context (k0 contains original r15 on return)
364         bsr     prepare_stack_save_dsp
365          nop
366
367         ! Save registers / Switch to bank 0
368         bsr     save_regs       ! needs original pr value in k3
369          mov.l  k4, k2          ! keep vector in k2
370
371         bra     handle_exception_special
372          nop
373
374         .align  2
375 1:      .long   EXPEVT
376 #endif
377
378 ! prepare_stack_save_dsp()
379 ! - roll back gRB
380 ! - switch to kernel stack
381 ! - save DSP
382 ! k0 returns original sp (after roll back)
383 ! k1 trashed
384 ! k2 trashed
385
386 prepare_stack_save_dsp:
387 #ifdef CONFIG_GUSA
388         ! Check for roll back gRB (User and Kernel)
389         mov     r15, k0
390         shll    k0
391         bf/s    1f
392          shll   k0
393         bf/s    1f
394          stc    spc, k1
395         stc     r0_bank, k0
396         cmp/hs  k0, k1          ! test k1 (saved PC) >= k0 (saved r0)
397         bt/s    2f
398          stc    r1_bank, k1
399
400         add     #-2, k0
401         add     r15, k0
402         ldc     k0, spc         ! PC = saved r0 + r15 - 2
403 2:      mov     k1, r15         ! SP = r1
404 1:
405 #endif
406         ! Switch to kernel stack if needed
407         stc     ssr, k0         ! Is it from kernel space?
408         shll    k0              ! Check MD bit (bit30) by shifting it into...
409         shll    k0              !       ...the T bit
410         bt/s    1f              ! It's a kernel to kernel transition.
411          mov    r15, k0         ! save original stack to k0
412         /* User space to kernel */
413         mov     #(THREAD_SIZE >> 10), k1
414         shll8   k1              ! k1 := THREAD_SIZE
415         shll2   k1
416         add     current, k1
417         mov     k1, r15         ! change to kernel stack
418         !
419 1:
420 #ifdef CONFIG_SH_DSP
421         ! Save DSP context if needed
422         stc     sr, k1
423         mov     #0x10, k2
424         shll8   k2                      ! DSP=1 (0x00001000)
425         tst     k2, k1                  ! Check if in DSP mode (passed in k2)
426         bt/s    skip_save
427          mov    #0, k1                  ! Set marker for no stack frame
428
429         mov     k2, k1                  ! Save has-frame marker
430
431         ! Save DSP registers on stack
432         stc.l   mod, @-r15
433         stc.l   re, @-r15
434         stc.l   rs, @-r15
435         sts.l   dsr, @-r15
436         sts.l   y1, @-r15
437         sts.l   y0, @-r15
438         sts.l   x1, @-r15
439         sts.l   x0, @-r15
440         sts.l   a0, @-r15
441
442         ! GAS is broken, does not generate correct "movs.l Ds,@-As" instr.
443
444         ! FIXME: Make sure that this is still the case with newer toolchains,
445         ! as we're not at all interested in supporting ancient toolchains at
446         ! this point. -- PFM.
447
448         mov     r15, k2
449         .word   0xf653                  ! movs.l        a1, @-r2
450         .word   0xf6f3                  ! movs.l        a0g, @-r2
451         .word   0xf6d3                  ! movs.l        a1g, @-r2
452         .word   0xf6c3                  ! movs.l        m0, @-r2
453         .word   0xf6e3                  ! movs.l        m1, @-r2
454         mov     k2, r15
455
456 skip_save:
457         mov.l   k1, @-r15               ! Push DSP mode marker onto stack
458 #endif
459         rts
460          nop
461 !
462 ! 0x400: Instruction and Data TLB miss exception vector
463 !
464         .balign         1024,0,1024
465 tlb_miss:
466         sts     pr, k3          ! save original pr value in k3
467
468 handle_exception:
469         ! Setup stack and save DSP context (k0 contains original r15 on return)
470         bsr     prepare_stack_save_dsp
471          nop
472
473         ! Save registers / Switch to bank 0
474         mov.l   5f, k2          ! vector register address
475         bsr     save_regs       ! needs original pr value in k3
476          mov.l  @k2, k2         ! read out vector and keep in k2
477
478 handle_exception_special:
479         ! Setup return address and jump to exception handler
480         mov.l   7f, r9          ! fetch return address
481         stc     r2_bank, r0     ! k2 (vector)
482         mov.l   6f, r10
483         shlr2   r0
484         shlr    r0
485         mov.l   @(r0, r10), r10
486         jmp     @r10
487          lds    r9, pr          ! put return address in pr
488
489         .align  L1_CACHE_SHIFT
490
491 ! save_regs()
492 ! - save vector, default tra, macl, mach, gbr, ssr, pr* and spc on the stack
493 ! - save r15*, r14, r13, r12, r11, r10, r9, r8 on the stack
494 ! - switch bank
495 ! - save r7, r6, r5, r4, r3, r2, r1, r0 on the stack
496 ! k0 contains original stack pointer*
497 ! k1 trashed
498 ! k2 passes vector (EXPEVT)
499 ! k3 passes original pr*
500 ! k4 trashed
501 ! BL=1 on entry, on exit BL=0.
502
503 save_regs:
504         mov     #-1, r1
505         mov.l   k2, @-r15       ! vector in k2
506         mov.l   k1, @-r15       ! set TRA (default: -1)
507         sts.l   macl, @-r15
508         sts.l   mach, @-r15
509         stc.l   gbr, @-r15
510         stc.l   ssr, @-r15
511         mov.l   k3, @-r15       ! original pr in k3
512         stc.l   spc, @-r15
513
514         mov.l   k0, @-r15       ! original stack pointer in k0
515         mov.l   r14, @-r15
516         mov.l   r13, @-r15
517         mov.l   r12, @-r15
518         mov.l   r11, @-r15
519         mov.l   r10, @-r15
520         mov.l   r9, @-r15
521         mov.l   r8, @-r15
522
523         mov.l   0f, k3          ! SR bits to set in k3
524         mov.l   1f, k4          ! SR bits to clear in k4
525
526         stc     sr, r8
527         or      k3, r8
528         and     k4, r8
529         ldc     r8, sr
530
531         mov.l   r7, @-r15
532         mov.l   r6, @-r15
533         mov.l   r5, @-r15
534         mov.l   r4, @-r15
535         mov.l   r3, @-r15
536         mov.l   r2, @-r15
537         mov.l   r1, @-r15
538         rts
539          mov.l  r0, @-r15
540
541 !
542 ! 0x600: Interrupt / NMI vector
543 !
544         .balign         512,0,512
545 ENTRY(handle_interrupt)
546 #if defined(CONFIG_KGDB)
547         mov.l   2f, k2
548         ! Debounce (filter nested NMI)
549         mov.l   @k2, k0
550         mov.l   9f, k1
551         cmp/eq  k1, k0
552         bf      11f
553         mov.l   10f, k1
554         tas.b   @k1
555         bt      11f
556         rte
557          nop
558         .align  2
559 9:      .long   NMI_VEC
560 10:     .long   in_nmi
561 11:
562 #endif /* defined(CONFIG_KGDB) */
563         sts     pr, k3          ! save original pr value in k3
564
565         ! Setup stack and save DSP context (k0 contains original r15 on return)
566         bsr     prepare_stack_save_dsp
567          nop
568
569         ! Save registers / Switch to bank 0
570         bsr     save_regs       ! needs original pr value in k3
571          mov    #-1, k2         ! default vector kept in k2
572
573         ! Setup return address and jump to do_IRQ
574         mov.l   4f, r9          ! fetch return address
575         lds     r9, pr          ! put return address in pr
576         mov.l   2f, r4
577         mov.l   3f, r9
578         mov.l   @r4, r4         ! pass INTEVT vector as arg0
579         jmp     @r9
580          mov    r15, r5         ! pass saved registers as arg1
581
582 ENTRY(exception_none)
583         rts
584          nop
585
586         .align  L1_CACHE_SHIFT
587 exception_data:
588 0:      .long   0x000080f0      ! FD=1, IMASK=15
589 1:      .long   0xcfffffff      ! RB=0, BL=0
590 2:      .long   INTEVT
591 3:      .long   do_IRQ
592 4:      .long   ret_from_irq
593 5:      .long   EXPEVT
594 6:      .long   exception_handling_table
595 7:      .long   ret_from_exception