]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - arch/sh/kernel/entry.S
sh: Move syscall table in to syscall.S.
[linux-2.6.git] / arch / sh / kernel / entry.S
1 /* $Id: entry.S,v 1.37 2004/06/11 13:02:46 doyu Exp $
2  *
3  *  linux/arch/sh/entry.S
4  *
5  *  Copyright (C) 1999, 2000, 2002  Niibe Yutaka
6  *  Copyright (C) 2003  Paul Mundt
7  *
8  * This file is subject to the terms and conditions of the GNU General Public
9  * License.  See the file "COPYING" in the main directory of this archive
10  * for more details.
11  *
12  */
13
14 #include <linux/sys.h>
15 #include <linux/linkage.h>
16 #include <asm/asm-offsets.h>
17 #include <asm/thread_info.h>
18 #include <asm/cpu/mmu_context.h>
19 #include <asm/unistd.h>
20
21 #if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
22 #define sys_nfsservctl          sys_ni_syscall
23 #endif
24
25 #if !defined(CONFIG_MMU)
26 #define sys_madvise             sys_ni_syscall
27 #define sys_readahead           sys_ni_syscall
28 #define sys_mprotect            sys_ni_syscall
29 #define sys_msync               sys_ni_syscall
30 #define sys_mlock               sys_ni_syscall
31 #define sys_munlock             sys_ni_syscall
32 #define sys_mlockall            sys_ni_syscall
33 #define sys_munlockall          sys_ni_syscall
34 #define sys_mremap              sys_ni_syscall
35 #define sys_mincore             sys_ni_syscall
36 #define sys_remap_file_pages    sys_ni_syscall
37 #endif
38
39 ! NOTE:
40 ! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
41 ! to be jumped is too far, but it causes illegal slot exception.
42
43 /*      
44  * entry.S contains the system-call and fault low-level handling routines.
45  * This also contains the timer-interrupt handler, as well as all interrupts
46  * and faults that can result in a task-switch.
47  *
48  * NOTE: This code handles signal-recognition, which happens every time
49  * after a timer-interrupt and after each system call.
50  *
51  * NOTE: This code uses a convention that instructions in the delay slot
52  * of a transfer-control instruction are indented by an extra space, thus:
53  *
54  *    jmp       @k0         ! control-transfer instruction
55  *     ldc      k1, ssr     ! delay slot
56  *
57  * Stack layout in 'ret_from_syscall':
58  *      ptrace needs to have all regs on the stack.
59  *      if the order here is changed, it needs to be
60  *      updated in ptrace.c and ptrace.h
61  *
62  *      r0
63  *      ...
64  *      r15 = stack pointer
65  *      spc
66  *      pr
67  *      ssr
68  *      gbr
69  *      mach
70  *      macl
71  *      syscall #
72  *
73  */
74
75 ENOSYS = 38
76 EINVAL = 22
77
78 #if defined(CONFIG_KGDB_NMI)
79 NMI_VEC = 0x1c0                 ! Must catch early for debounce
80 #endif
81
82 /* Offsets to the stack */
83 OFF_R0  =  0            /* Return value. New ABI also arg4 */
84 OFF_R1  =  4            /* New ABI: arg5 */
85 OFF_R2  =  8            /* New ABI: arg6 */
86 OFF_R3  =  12           /* New ABI: syscall_nr */
87 OFF_R4  =  16           /* New ABI: arg0 */
88 OFF_R5  =  20           /* New ABI: arg1 */
89 OFF_R6  =  24           /* New ABI: arg2 */
90 OFF_R7  =  28           /* New ABI: arg3 */
91 OFF_SP  =  (15*4)
92 OFF_PC  =  (16*4)
93 OFF_SR  =  (16*4+8)
94 OFF_TRA =  (16*4+6*4)
95
96
97 #define k0      r0
98 #define k1      r1
99 #define k2      r2
100 #define k3      r3
101 #define k4      r4
102
103 #define k_ex_code       r2_bank /* r2_bank1 */
104 #define g_imask         r6      /* r6_bank1 */
105 #define k_g_imask       r6_bank /* r6_bank1 */
106 #define current         r7      /* r7_bank1 */
107
108 /*
109  * Kernel mode register usage:
110  *      k0      scratch
111  *      k1      scratch
112  *      k2      scratch (Exception code)
113  *      k3      scratch (Return address)
114  *      k4      scratch
115  *      k5      reserved
116  *      k6      Global Interrupt Mask (0--15 << 4)
117  *      k7      CURRENT_THREAD_INFO (pointer to current thread info)
118  */
119
120 !
121 ! TLB Miss / Initial Page write exception handling
122 !                       _and_
123 ! TLB hits, but the access violate the protection.
124 ! It can be valid access, such as stack grow and/or C-O-W.
125 !
126 !
127 ! Find the pmd/pte entry and loadtlb
128 ! If it's not found, cause address error (SEGV)
129 !
130 ! Although this could be written in assembly language (and it'd be faster),
131 ! this first version depends *much* on C implementation.
132 !
133
134 #define CLI()                           \
135         stc     sr, r0;                 \
136         or      #0xf0, r0;              \
137         ldc     r0, sr
138
139 #define STI()                           \
140         mov.l   __INV_IMASK, r11;       \
141         stc     sr, r10;                \
142         and     r11, r10;               \
143         stc     k_g_imask, r11;         \
144         or      r11, r10;               \
145         ldc     r10, sr
146
147 #if defined(CONFIG_PREEMPT)
148 #  define preempt_stop()        CLI()
149 #else
150 #  define preempt_stop()
151 #  define resume_kernel         restore_all
152 #endif
153
154 #if defined(CONFIG_MMU)
155         .align  2
156 ENTRY(tlb_miss_load)
157         bra     call_dpf
158          mov    #0, r5
159
160         .align  2
161 ENTRY(tlb_miss_store)
162         bra     call_dpf
163          mov    #1, r5
164
165         .align  2
166 ENTRY(initial_page_write)
167         bra     call_dpf
168          mov    #1, r5
169
170         .align  2
171 ENTRY(tlb_protection_violation_load)
172         bra     call_dpf
173          mov    #0, r5
174
175         .align  2
176 ENTRY(tlb_protection_violation_store)
177         bra     call_dpf
178          mov    #1, r5
179
180 call_dpf:
181         mov.l   1f, r0
182         mov     r5, r8
183         mov.l   @r0, r6
184         mov     r6, r9
185         mov.l   2f, r0
186         sts     pr, r10
187         jsr     @r0
188          mov    r15, r4
189         !
190         tst     r0, r0
191         bf/s    0f
192          lds    r10, pr
193         rts
194          nop
195 0:      STI()
196         mov.l   3f, r0
197         mov     r9, r6
198         mov     r8, r5
199         jmp     @r0
200          mov    r15, r4
201
202         .align 2
203 1:      .long   MMU_TEA
204 2:      .long   __do_page_fault
205 3:      .long   do_page_fault
206
207         .align  2
208 ENTRY(address_error_load)
209         bra     call_dae
210          mov    #0,r5           ! writeaccess = 0
211
212         .align  2
213 ENTRY(address_error_store)
214         bra     call_dae
215          mov    #1,r5           ! writeaccess = 1
216
217         .align  2
218 call_dae:
219         mov.l   1f, r0
220         mov.l   @r0, r6         ! address
221         mov.l   2f, r0
222         jmp     @r0
223          mov    r15, r4         ! regs
224
225         .align 2
226 1:      .long   MMU_TEA
227 2:      .long   do_address_error
228 #endif /* CONFIG_MMU */
229
230 #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
231 ! Handle kernel debug if either kgdb (SW) or gdb-stub (FW) is present.
232 ! If both are configured, handle the debug traps (breakpoints) in SW,
233 ! but still allow BIOS traps to FW.
234
235         .align  2
236 debug_kernel:
237 #if defined(CONFIG_SH_STANDARD_BIOS) && defined(CONFIG_SH_KGDB)
238         /* Force BIOS call to FW (debug_trap put TRA in r8) */
239         mov     r8,r0
240         shlr2   r0
241         cmp/eq  #0x3f,r0
242         bt      debug_kernel_fw
243 #endif /* CONFIG_SH_STANDARD_BIOS && CONFIG_SH_KGDB */
244
245 debug_enter:            
246 #if defined(CONFIG_SH_KGDB)
247         /* Jump to kgdb, pass stacked regs as arg */
248 debug_kernel_sw:
249         mov.l   3f, r0
250         jmp     @r0
251          mov    r15, r4
252         .align  2
253 3:      .long   kgdb_handle_exception
254 #endif /* CONFIG_SH_KGDB */
255
256 #if defined(CONFIG_SH_STANDARD_BIOS)
257         /* Unwind the stack and jmp to the debug entry */
258 debug_kernel_fw:
259         mov.l   @r15+, r0
260         mov.l   @r15+, r1
261         mov.l   @r15+, r2
262         mov.l   @r15+, r3
263         mov.l   @r15+, r4
264         mov.l   @r15+, r5
265         mov.l   @r15+, r6
266         mov.l   @r15+, r7
267         stc     sr, r8
268         mov.l   1f, r9                  ! BL =1, RB=1, IMASK=0x0F
269         or      r9, r8
270         ldc     r8, sr                  ! here, change the register bank
271         mov.l   @r15+, r8
272         mov.l   @r15+, r9
273         mov.l   @r15+, r10
274         mov.l   @r15+, r11
275         mov.l   @r15+, r12
276         mov.l   @r15+, r13
277         mov.l   @r15+, r14
278         mov.l   @r15+, k0
279         ldc.l   @r15+, spc
280         lds.l   @r15+, pr
281         mov.l   @r15+, k1
282         ldc.l   @r15+, gbr
283         lds.l   @r15+, mach
284         lds.l   @r15+, macl
285         mov     k0, r15
286         !
287         mov.l   2f, k0
288         mov.l   @k0, k0
289         jmp     @k0
290          ldc    k1, ssr
291         .align  2
292 1:      .long   0x300000f0
293 2:      .long   gdb_vbr_vector
294 #endif /* CONFIG_SH_STANDARD_BIOS */
295
296 #endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
297
298
299         .align  2
300 debug_trap:     
301 #if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
302         mov     #OFF_SR, r0
303         mov.l   @(r0,r15), r0           ! get status register
304         shll    r0
305         shll    r0                      ! kernel space?
306         bt/s    debug_kernel
307 #endif
308          mov.l  @r15, r0                ! Restore R0 value
309         mov.l   1f, r8
310         jmp     @r8
311          nop
312
313         .align  2
314 ENTRY(exception_error)
315         !
316         STI()
317         mov.l   2f, r0
318         jmp     @r0
319          nop
320
321 !
322         .align  2
323 1:      .long   break_point_trap_software
324 2:      .long   do_exception_error
325
326         .align  2
327 ret_from_exception:
328         preempt_stop()
329 ret_from_irq:
330         !
331         mov     #OFF_SR, r0
332         mov.l   @(r0,r15), r0   ! get status register
333         shll    r0
334         shll    r0              ! kernel space?
335         bt/s    resume_kernel   ! Yes, it's from kernel, go back soon
336          GET_THREAD_INFO(r8)
337
338 #ifdef CONFIG_PREEMPT
339         bra     resume_userspace
340          nop
341 ENTRY(resume_kernel)
342         mov.l   @(TI_PRE_COUNT,r8), r0  ! current_thread_info->preempt_count
343         tst     r0, r0
344         bf      noresched
345 need_resched:
346         mov.l   @(TI_FLAGS,r8), r0      ! current_thread_info->flags
347         tst     #_TIF_NEED_RESCHED, r0  ! need_resched set?
348         bt      noresched
349
350         mov     #OFF_SR, r0
351         mov.l   @(r0,r15), r0           ! get status register
352         and     #0xf0, r0               ! interrupts off (exception path)?
353         cmp/eq  #0xf0, r0
354         bt      noresched
355
356         mov.l   1f, r0
357         mov.l   r0, @(TI_PRE_COUNT,r8)
358
359         STI()
360         mov.l   2f, r0
361         jsr     @r0
362          nop
363         mov     #0, r0
364         mov.l   r0, @(TI_PRE_COUNT,r8)
365         CLI()
366
367         bra     need_resched
368          nop
369 noresched:
370         bra     restore_all
371          nop
372
373         .align 2
374 1:      .long   PREEMPT_ACTIVE
375 2:      .long   schedule
376 #endif
377
378 ENTRY(resume_userspace)
379         ! r8: current_thread_info
380         CLI()
381         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
382         tst     #_TIF_WORK_MASK, r0
383         bt/s    restore_all
384          tst    #_TIF_NEED_RESCHED, r0
385
386         .align  2
387 work_pending:
388         ! r0: current_thread_info->flags
389         ! r8: current_thread_info
390         ! t:  result of "tst    #_TIF_NEED_RESCHED, r0"
391         bf/s    work_resched
392          tst    #_TIF_SIGPENDING, r0
393 work_notifysig:
394         bt/s    restore_all
395          mov    r15, r4
396         mov     #0, r5
397         mov.l   2f, r1
398         mova    restore_all, r0
399         jmp     @r1
400          lds    r0, pr
401 work_resched:
402 #ifndef CONFIG_PREEMPT
403         ! gUSA handling
404         mov.l   @(OFF_SP,r15), r0       ! get user space stack pointer
405         mov     r0, r1
406         shll    r0
407         bf/s    1f
408          shll   r0
409         bf/s    1f
410          mov    #OFF_PC, r0
411         !                                 SP >= 0xc0000000 : gUSA mark
412         mov.l   @(r0,r15), r2           ! get user space PC (program counter)
413         mov.l   @(OFF_R0,r15), r3       ! end point
414         cmp/hs  r3, r2                  ! r2 >= r3? 
415         bt      1f
416         add     r3, r1                  ! rewind point #2
417         mov.l   r1, @(r0,r15)           ! reset PC to rewind point #2
418         !
419 1:
420 #endif
421         mov.l   1f, r1
422         jsr     @r1                             ! schedule
423          nop
424         CLI()
425         !
426         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
427         tst     #_TIF_WORK_MASK, r0
428         bt      restore_all
429         bra     work_pending
430          tst    #_TIF_NEED_RESCHED, r0
431
432         .align  2
433 1:      .long   schedule
434 2:      .long   do_signal
435
436         .align  2
437 syscall_exit_work:
438         ! r0: current_thread_info->flags
439         ! r8: current_thread_info
440         tst     #_TIF_SYSCALL_TRACE, r0
441         bt/s    work_pending
442          tst    #_TIF_NEED_RESCHED, r0
443         STI()
444         ! XXX setup arguments...
445         mov.l   4f, r0                  ! do_syscall_trace
446         jsr     @r0
447          nop
448         bra     resume_userspace
449          nop
450
451         .align  2
452 syscall_trace_entry:
453         !                       Yes it is traced.
454         ! XXX setup arguments...
455         mov.l   4f, r11         ! Call do_syscall_trace which notifies
456         jsr     @r11            ! superior (will chomp R[0-7])
457          nop
458         !                       Reload R0-R4 from kernel stack, where the
459         !                       parent may have modified them using
460         !                       ptrace(POKEUSR).  (Note that R0-R2 are
461         !                       used by the system call handler directly
462         !                       from the kernel stack anyway, so don't need
463         !                       to be reloaded here.)  This allows the parent
464         !                       to rewrite system calls and args on the fly.
465         mov.l   @(OFF_R4,r15), r4   ! arg0
466         mov.l   @(OFF_R5,r15), r5
467         mov.l   @(OFF_R6,r15), r6
468         mov.l   @(OFF_R7,r15), r7   ! arg3
469         mov.l   @(OFF_R3,r15), r3   ! syscall_nr
470         !                   Arrange for do_syscall_trace to be called
471         !                   again as the system call returns.
472         mov.l   2f, r10                 ! Number of syscalls
473         cmp/hs  r10, r3
474         bf      syscall_call
475         mov     #-ENOSYS, r0
476         bra     syscall_exit
477          mov.l  r0, @(OFF_R0,r15)       ! Return value
478
479 /*
480  * Syscall interface:
481  *
482  *      Syscall #: R3
483  *      Arguments #0 to #3: R4--R7
484  *      Arguments #4 to #6: R0, R1, R2
485  *      TRA: (number of arguments + 0x10) x 4
486  *
487  * This code also handles delegating other traps to the BIOS/gdb stub
488  * according to:
489  *
490  * Trap number
491  * (TRA>>2)         Purpose
492  * --------         -------
493  * 0x0-0xf          old syscall ABI
494  * 0x10-0x1f        new syscall ABI
495  * 0x20-0xff        delegated through debug_trap to BIOS/gdb stub.
496  *
497  * Note: When we're first called, the TRA value must be shifted
498  * right 2 bits in order to get the value that was used as the "trapa"
499  * argument.
500  */
501
502         .align  2
503         .globl  ret_from_fork
504 ret_from_fork:
505         mov.l   1f, r8
506         jsr     @r8
507          mov    r0, r4
508         bra     syscall_exit
509          nop
510         .align  2
511 1:      .long   schedule_tail
512         !
513 ENTRY(system_call)
514         mov.l   1f, r9
515         mov.l   @r9, r8         ! Read from TRA (Trap Address) Register
516         !
517         ! Is the trap argument >= 0x20? (TRA will be >= 0x80)
518         mov     #0x7f, r9
519         cmp/hi  r9, r8
520         bt/s    0f
521          mov    #OFF_TRA, r9
522         add     r15, r9
523         !
524         mov.l   r8, @r9                 ! set TRA value to tra
525         STI()
526         !                   Call the system call handler through the table.
527         !                   First check for bad syscall number
528         mov     r3, r9
529         mov.l   2f, r8                  ! Number of syscalls
530         cmp/hs  r8, r9
531         bf/s    good_system_call
532          GET_THREAD_INFO(r8)
533 syscall_badsys:                 ! Bad syscall number
534         mov     #-ENOSYS, r0
535         bra     resume_userspace
536          mov.l  r0, @(OFF_R0,r15)       ! Return value
537         !
538 0:
539         bra     debug_trap
540          nop
541         !
542 good_system_call:               ! Good syscall number
543         mov.l   @(TI_FLAGS,r8), r8
544         mov     #_TIF_SYSCALL_TRACE, r10
545         tst     r10, r8
546         bf      syscall_trace_entry
547         !
548 syscall_call:
549         shll2   r9              ! x4
550         mov.l   3f, r8          ! Load the address of sys_call_table
551         add     r8, r9
552         mov.l   @r9, r8
553         jsr     @r8             ! jump to specific syscall handler
554          nop
555         mov.l   r0, @(OFF_R0,r15)               ! save the return value
556         !
557 syscall_exit:
558         CLI()
559         !
560         GET_THREAD_INFO(r8)
561         mov.l   @(TI_FLAGS,r8), r0              ! current_thread_info->flags
562         tst     #_TIF_ALLWORK_MASK, r0
563         bf      syscall_exit_work
564 restore_all:
565         mov.l   @r15+, r0
566         mov.l   @r15+, r1
567         mov.l   @r15+, r2
568         mov.l   @r15+, r3
569         mov.l   @r15+, r4
570         mov.l   @r15+, r5
571         mov.l   @r15+, r6
572         mov.l   @r15+, r7
573         !
574         stc     sr, r8
575         mov.l   7f, r9
576         or      r9, r8                  ! BL =1, RB=1
577         ldc     r8, sr                  ! here, change the register bank
578         !
579         mov.l   @r15+, r8
580         mov.l   @r15+, r9
581         mov.l   @r15+, r10
582         mov.l   @r15+, r11
583         mov.l   @r15+, r12
584         mov.l   @r15+, r13
585         mov.l   @r15+, r14
586         mov.l   @r15+, k4               ! original stack pointer
587         ldc.l   @r15+, spc
588         lds.l   @r15+, pr
589         mov.l   @r15+, k3               ! original SR
590         ldc.l   @r15+, gbr
591         lds.l   @r15+, mach
592         lds.l   @r15+, macl
593         add     #4, r15                 ! Skip syscall number
594         !
595 #ifdef CONFIG_SH_DSP
596         mov.l   @r15+, k0               ! DSP mode marker
597         mov.l   5f, k1
598         cmp/eq  k0, k1                  ! Do we have a DSP stack frame?
599         bf      skip_restore
600
601         stc     sr, k0                  ! Enable CPU DSP mode
602         or      k1, k0                  ! (within kernel it may be disabled)
603         ldc     k0, sr
604         mov     r2, k0                  ! Backup r2
605
606         ! Restore DSP registers from stack
607         mov     r15, r2
608         movs.l  @r2+, a1
609         movs.l  @r2+, a0g
610         movs.l  @r2+, a1g
611         movs.l  @r2+, m0
612         movs.l  @r2+, m1
613         mov     r2, r15
614
615         lds.l   @r15+, a0
616         lds.l   @r15+, x0
617         lds.l   @r15+, x1
618         lds.l   @r15+, y0
619         lds.l   @r15+, y1
620         lds.l   @r15+, dsr
621         ldc.l   @r15+, rs
622         ldc.l   @r15+, re
623         ldc.l   @r15+, mod
624
625         mov     k0, r2                  ! Restore r2
626 skip_restore:
627 #endif
628         !
629         ! Calculate new SR value
630         mov     k3, k2                  ! original SR value
631         mov.l   9f, k1
632         and     k1, k2                  ! Mask orignal SR value
633         !
634         mov     k3, k0                  ! Calculate IMASK-bits
635         shlr2   k0
636         and     #0x3c, k0
637         cmp/eq  #0x3c, k0
638         bt/s    6f
639          shll2  k0
640         mov     g_imask, k0
641         !
642 6:      or      k0, k2                  ! Set the IMASK-bits
643         ldc     k2, ssr
644         !
645 #if defined(CONFIG_KGDB_NMI)
646         ! Clear in_nmi
647         mov.l   4f, k0
648         mov     #0, k1
649         mov.b   k1, @k0
650 #endif
651         mov.l   @r15+, k2               ! restore EXPEVT
652         mov     k4, r15
653         rte
654          nop
655
656         .align  2
657 1:      .long   TRA
658 2:      .long   NR_syscalls
659 3:      .long   sys_call_table
660 4:      .long   do_syscall_trace
661 5:      .long   0x00001000      ! DSP
662 7:      .long   0x30000000
663 9:
664 __INV_IMASK:
665         .long   0xffffff0f      ! ~(IMASK)
666
667 ! Exception Vector Base
668 !
669 !       Should be aligned page boundary.
670 !
671         .balign         4096,0,4096
672 ENTRY(vbr_base)
673         .long   0
674 !
675         .balign         256,0,256
676 general_exception:
677         mov.l   1f, k2
678         mov.l   2f, k3
679         bra     handle_exception
680          mov.l  @k2, k2
681         .align  2
682 1:      .long   EXPEVT
683 2:      .long   ret_from_exception
684 !
685 !
686         .balign         1024,0,1024
687 tlb_miss:
688         mov.l   1f, k2
689         mov.l   4f, k3
690         bra     handle_exception
691          mov.l  @k2, k2
692 !
693         .balign         512,0,512
694 interrupt:
695         mov.l   2f, k2
696         mov.l   3f, k3
697 #if defined(CONFIG_KGDB_NMI)
698         ! Debounce (filter nested NMI)
699         mov.l   @k2, k0
700         mov.l   5f, k1
701         cmp/eq  k1, k0
702         bf      0f
703         mov.l   6f, k1
704         tas.b   @k1
705         bt      0f
706         rte
707          nop
708         .align  2
709 5:      .long   NMI_VEC
710 6:      .long   in_nmi
711 0:
712 #endif /* defined(CONFIG_KGDB_NMI) */
713         bra     handle_exception
714          mov.l  @k2, k2
715
716         .align  2
717 1:      .long   EXPEVT
718 2:      .long   INTEVT
719 3:      .long   ret_from_irq
720 4:      .long   ret_from_exception
721
722 !
723 !
724         .align  2
725 handle_exception:
726         ! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
727         ! save all registers onto stack.
728         !
729         stc     ssr, k0         ! Is it from kernel space?
730         shll    k0              ! Check MD bit (bit30) by shifting it into...
731         shll    k0              !       ...the T bit
732         bt/s    1f              ! It's a kernel to kernel transition.
733          mov    r15, k0         ! save original stack to k0
734         /* User space to kernel */
735         mov     #0x20, k1
736         shll8   k1              ! k1 := 8192 (== THREAD_SIZE)
737         add     current, k1
738         mov     k1, r15         ! change to kernel stack
739         !
740 1:      mov     #-1, k4
741         mov.l   2f, k1
742         !
743 #ifdef CONFIG_SH_DSP
744         mov.l   r2, @-r15               ! Save r2, we need another reg
745         stc     sr, k4
746         mov.l   1f, r2
747         tst     r2, k4                  ! Check if in DSP mode
748         mov.l   @r15+, r2               ! Restore r2 now
749         bt/s    skip_save
750          mov    #0, k4                  ! Set marker for no stack frame
751
752         mov     r2, k4                  ! Backup r2 (in k4) for later
753
754         ! Save DSP registers on stack
755         stc.l   mod, @-r15
756         stc.l   re, @-r15
757         stc.l   rs, @-r15
758         sts.l   dsr, @-r15
759         sts.l   y1, @-r15
760         sts.l   y0, @-r15
761         sts.l   x1, @-r15
762         sts.l   x0, @-r15
763         sts.l   a0, @-r15
764
765         ! GAS is broken, does not generate correct "movs.l Ds,@-As" instr.
766
767         ! FIXME: Make sure that this is still the case with newer toolchains,
768         ! as we're not at all interested in supporting ancient toolchains at
769         ! this point. -- PFM.
770
771         mov     r15, r2
772         .word   0xf653                  ! movs.l        a1, @-r2
773         .word   0xf6f3                  ! movs.l        a0g, @-r2
774         .word   0xf6d3                  ! movs.l        a1g, @-r2
775         .word   0xf6c3                  ! movs.l        m0, @-r2
776         .word   0xf6e3                  ! movs.l        m1, @-r2
777         mov     r2, r15
778
779         mov     k4, r2                  ! Restore r2
780         mov.l   1f, k4                  ! Force DSP stack frame
781 skip_save:
782         mov.l   k4, @-r15               ! Push DSP mode marker onto stack
783 #endif
784         ! Save the user registers on the stack.
785         mov.l   k2, @-r15       ! EXPEVT
786         mov.l   k4, @-r15       ! set TRA (default: -1)
787         !
788         sts.l   macl, @-r15
789         sts.l   mach, @-r15
790         stc.l   gbr, @-r15
791         stc.l   ssr, @-r15
792         sts.l   pr, @-r15
793         stc.l   spc, @-r15
794         !
795         lds     k3, pr          ! Set the return address to pr
796         !
797         mov.l   k0, @-r15       ! save orignal stack
798         mov.l   r14, @-r15
799         mov.l   r13, @-r15
800         mov.l   r12, @-r15
801         mov.l   r11, @-r15
802         mov.l   r10, @-r15
803         mov.l   r9, @-r15
804         mov.l   r8, @-r15
805         !
806         stc     sr, r8          ! Back to normal register bank, and
807         or      k1, r8          ! Block all interrupts
808         mov.l   3f, k1
809         and     k1, r8          ! ...
810         ldc     r8, sr          ! ...changed here.
811         !
812         mov.l   r7, @-r15
813         mov.l   r6, @-r15
814         mov.l   r5, @-r15
815         mov.l   r4, @-r15
816         mov.l   r3, @-r15
817         mov.l   r2, @-r15
818         mov.l   r1, @-r15
819         mov.l   r0, @-r15
820         ! Then, dispatch to the handler, according to the exception code.
821         stc     k_ex_code, r8
822         shlr2   r8
823         shlr    r8
824         mov.l   4f, r9
825         add     r8, r9
826         mov.l   @r9, r9
827         jmp     @r9
828          nop
829
830         .align  2
831 1:      .long   0x00001000      ! DSP=1
832 2:      .long   0x000080f0      ! FD=1, IMASK=15
833 3:      .long   0xcfffffff      ! RB=0, BL=0
834 4:      .long   exception_handling_table
835
836         .align  2
837 ENTRY(exception_none)
838         rts
839          nop
840