blob: 1a05804caf3725d1967b5f5718c8e11bca631f34 [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 */
13
14#include <linux/sys.h>
15#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
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
75ENOSYS = 38
76EINVAL = 22
77
Linus Torvalds1da177e2005-04-16 15:20:36 -070078#if defined(CONFIG_KGDB_NMI)
79NMI_VEC = 0x1c0 ! Must catch early for debounce
80#endif
81
82/* Offsets to the stack */
83OFF_R0 = 0 /* Return value. New ABI also arg4 */
84OFF_R1 = 4 /* New ABI: arg5 */
85OFF_R2 = 8 /* New ABI: arg6 */
86OFF_R3 = 12 /* New ABI: syscall_nr */
87OFF_R4 = 16 /* New ABI: arg0 */
88OFF_R5 = 20 /* New ABI: arg1 */
89OFF_R6 = 24 /* New ABI: arg2 */
90OFF_R7 = 28 /* New ABI: arg3 */
91OFF_SP = (15*4)
92OFF_PC = (16*4)
93OFF_SR = (16*4+8)
94OFF_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
156ENTRY(tlb_miss_load)
157 bra call_dpf
158 mov #0, r5
159
160 .align 2
161ENTRY(tlb_miss_store)
162 bra call_dpf
163 mov #1, r5
164
165 .align 2
166ENTRY(initial_page_write)
167 bra call_dpf
168 mov #1, r5
169
170 .align 2
171ENTRY(tlb_protection_violation_load)
172 bra call_dpf
173 mov #0, r5
174
175 .align 2
176ENTRY(tlb_protection_violation_store)
177 bra call_dpf
178 mov #1, r5
179
180call_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
1950: 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
2031: .long MMU_TEA
2042: .long __do_page_fault
2053: .long do_page_fault
206
207 .align 2
208ENTRY(address_error_load)
209 bra call_dae
210 mov #0,r5 ! writeaccess = 0
211
212 .align 2
213ENTRY(address_error_store)
214 bra call_dae
215 mov #1,r5 ! writeaccess = 1
216
217 .align 2
218call_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
2261: .long MMU_TEA
2272: .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
236debug_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
245debug_enter:
246#if defined(CONFIG_SH_KGDB)
247 /* Jump to kgdb, pass stacked regs as arg */
248debug_kernel_sw:
249 mov.l 3f, r0
250 jmp @r0
251 mov r15, r4
252 .align 2
2533: .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 */
258debug_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
2921: .long 0x300000f0
2932: .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
300debug_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
314ENTRY(exception_error)
315 !
316 STI()
317 mov.l 2f, r0
318 jmp @r0
319 nop
320
321!
322 .align 2
3231: .long break_point_trap_software
3242: .long do_exception_error
325
326 .align 2
327ret_from_exception:
328 preempt_stop()
329ret_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
341ENTRY(resume_kernel)
342 mov.l @(TI_PRE_COUNT,r8), r0 ! current_thread_info->preempt_count
343 tst r0, r0
344 bf noresched
345need_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
369noresched:
370 bra restore_all
371 nop
372
373 .align 2
3741: .long PREEMPT_ACTIVE
3752: .long schedule
376#endif
377
378ENTRY(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
387work_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
393work_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
401work_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 !
4191:
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
4331: .long schedule
4342: .long do_signal
435
436 .align 2
437syscall_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
452syscall_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
504ret_from_fork:
505 mov.l 1f, r8
506 jsr @r8
507 mov r0, r4
508 bra syscall_exit
509 nop
510 .align 2
5111: .long schedule_tail
512 !
513ENTRY(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)
533syscall_badsys: ! Bad syscall number
534 mov #-ENOSYS, r0
535 bra resume_userspace
536 mov.l r0, @(OFF_R0,r15) ! Return value
537 !
5380:
539 bra debug_trap
540 nop
541 !
542good_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 !
548syscall_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 !
557syscall_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
564restore_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
626skip_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 !
6426: or k0, k2 ! Set the IMASK-bits
643 ldc k2, ssr
644 !
645#if defined(CONFIG_KGDB_NMI)
646 ! Clear in_nmi
Paul Mundt6ae5e8d2006-09-27 11:37:33 +0900647 mov.l 6f, k0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 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
6571: .long TRA
6582: .long NR_syscalls
6593: .long sys_call_table
6604: .long do_syscall_trace
6615: .long 0x00001000 ! DSP
6627: .long 0x30000000
6639:
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
672ENTRY(vbr_base)
673 .long 0
674!
675 .balign 256,0,256
676general_exception:
677 mov.l 1f, k2
678 mov.l 2f, k3
679 bra handle_exception
680 mov.l @k2, k2
681 .align 2
6821: .long EXPEVT
6832: .long ret_from_exception
684!
685!
686 .balign 1024,0,1024
687tlb_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
694interrupt:
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
7095: .long NMI_VEC
7106: .long in_nmi
7110:
712#endif /* defined(CONFIG_KGDB_NMI) */
713 bra handle_exception
714 mov.l @k2, k2
715
716 .align 2
7171: .long EXPEVT
7182: .long INTEVT
7193: .long ret_from_irq
7204: .long ret_from_exception
721
722!
723!
724 .align 2
725handle_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 !
7401: 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
781skip_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
8311: .long 0x00001000 ! DSP=1
8322: .long 0x000080f0 ! FD=1, IMASK=15
8333: .long 0xcfffffff ! RB=0, BL=0
8344: .long exception_handling_table
835
836 .align 2
837ENTRY(exception_none)
838 rts
839 nop
840