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