blob: 97c571fbcdf13a5e2922867c143bf55dcb432292 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/sys.h>
Paul Mundt711fa802006-10-03 13:14:04 +090014#include <linux/errno.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/linkage.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <asm/asm-offsets.h>
17#include <asm/thread_info.h>
Paul Mundt091904a2006-02-01 03:06:01 -080018#include <asm/cpu/mmu_context.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <asm/unistd.h>
20
Linus Torvalds1da177e2005-04-16 15:20:36 -070021! 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#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
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
134ENTRY(tlb_miss_load)
135 bra call_dpf
136 mov #0, r5
137
138 .align 2
139ENTRY(tlb_miss_store)
140 bra call_dpf
141 mov #1, r5
142
143 .align 2
144ENTRY(initial_page_write)
145 bra call_dpf
146 mov #1, r5
147
148 .align 2
149ENTRY(tlb_protection_violation_load)
150 bra call_dpf
151 mov #0, r5
152
153 .align 2
154ENTRY(tlb_protection_violation_store)
155 bra call_dpf
156 mov #1, r5
157
158call_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
1730: 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
1811: .long MMU_TEA
1822: .long __do_page_fault
1833: .long do_page_fault
184
185 .align 2
186ENTRY(address_error_load)
187 bra call_dae
188 mov #0,r5 ! writeaccess = 0
189
190 .align 2
191ENTRY(address_error_store)
192 bra call_dae
193 mov #1,r5 ! writeaccess = 1
194
195 .align 2
196call_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
2041: .long MMU_TEA
2052: .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
214debug_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
223debug_enter:
224#if defined(CONFIG_SH_KGDB)
225 /* Jump to kgdb, pass stacked regs as arg */
226debug_kernel_sw:
227 mov.l 3f, r0
228 jmp @r0
229 mov r15, r4
230 .align 2
2313: .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 */
236debug_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
2701: .long 0x300000f0
2712: .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
278debug_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
292ENTRY(exception_error)
293 !
294 STI()
295 mov.l 2f, r0
296 jmp @r0
297 nop
298
299!
300 .align 2
3011: .long break_point_trap_software
3022: .long do_exception_error
303
304 .align 2
305ret_from_exception:
306 preempt_stop()
Andriy Skulysh3aa770e2006-09-27 16:20:22 +0900307ENTRY(ret_from_irq)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 !
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
319ENTRY(resume_kernel)
320 mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count
321 tst r0, r0
322 bf noresched
323need_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
347noresched:
348 bra restore_all
349 nop
350
351 .align 2
3521: .long PREEMPT_ACTIVE
3532: .long schedule
354#endif
355
356ENTRY(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
365work_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
Paul Mundt9f23e7e2006-09-27 17:27:00 +0900370 tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371work_notifysig:
372 bt/s restore_all
373 mov r15, r4
Paul Mundt9f23e7e2006-09-27 17:27:00 +0900374 mov r12, r5 ! set arg1(save_r0)
375 mov r0, r6
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 mov.l 2f, r1
377 mova restore_all, r0
378 jmp @r1
379 lds r0, pr
380work_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 !
3981:
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
4121: .long schedule
Paul Mundt9f23e7e2006-09-27 17:27:00 +09004132: .long do_notify_resume
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 .align 2
416syscall_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
431syscall_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
483ret_from_fork:
484 mov.l 1f, r8
485 jsr @r8
486 mov r0, r4
487 bra syscall_exit
488 nop
489 .align 2
4901: .long schedule_tail
491 !
492ENTRY(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)
512syscall_badsys: ! Bad syscall number
513 mov #-ENOSYS, r0
514 bra resume_userspace
515 mov.l r0, @(OFF_R0,r15) ! Return value
516 !
5170:
518 bra debug_trap
519 nop
520 !
521good_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 !
527syscall_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
Paul Mundt0b892932006-09-27 17:22:49 +0900534 mov.l @(OFF_R0,r15), r12 ! save r0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 mov.l r0, @(OFF_R0,r15) ! save the return value
536 !
537syscall_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
544restore_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
606skip_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 !
6226: or k0, k2 ! Set the IMASK-bits
623 ldc k2, ssr
624 !
625#if defined(CONFIG_KGDB_NMI)
626 ! Clear in_nmi
Paul Mundt6ae5e8d2006-09-27 11:37:33 +0900627 mov.l 6f, k0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 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
6371: .long TRA
6382: .long NR_syscalls
6393: .long sys_call_table
6404: .long do_syscall_trace
6415: .long 0x00001000 ! DSP
6427: .long 0x30000000
6439:
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
652ENTRY(vbr_base)
653 .long 0
654!
655 .balign 256,0,256
656general_exception:
657 mov.l 1f, k2
658 mov.l 2f, k3
659 bra handle_exception
660 mov.l @k2, k2
661 .align 2
6621: .long EXPEVT
6632: .long ret_from_exception
664!
665!
666 .balign 1024,0,1024
667tlb_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
674interrupt:
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
6895: .long NMI_VEC
6906: .long in_nmi
6910:
692#endif /* defined(CONFIG_KGDB_NMI) */
693 bra handle_exception
694 mov.l @k2, k2
695
696 .align 2
6971: .long EXPEVT
6982: .long INTEVT
6993: .long ret_from_irq
7004: .long ret_from_exception
701
702!
703!
704 .align 2
Andriy Skulysh3aa770e2006-09-27 16:20:22 +0900705ENTRY(handle_exception)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 ! 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 */
Paul Mundta6a311392006-09-27 18:22:14 +0900715 mov #(THREAD_SIZE >> 8), k1
716 shll8 k1 ! k1 := THREAD_SIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 add current, k1
718 mov k1, r15 ! change to kernel stack
719 !
7201: 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
761skip_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
8111: .long 0x00001000 ! DSP=1
8122: .long 0x000080f0 ! FD=1, IMASK=15
8133: .long 0xcfffffff ! RB=0, BL=0
8144: .long exception_handling_table
815
816 .align 2
817ENTRY(exception_none)
818 rts
819 nop
820