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