1 /* arch/arm26/kernel/entry.S
3 * Assembled from chunks of code in arch/arm
5 * Copyright (C) 2003 Ian Molton
9 #include <linux/config.h> /* for CONFIG_ARCH_xxxx */
10 #include <linux/linkage.h>
12 #include <asm/assembler.h>
13 #include <asm/asm_offsets.h>
14 #include <asm/errno.h>
15 #include <asm/hardware.h>
16 #include <asm/sysirq.h>
17 #include <asm/thread_info.h>
19 #include <asm/ptrace.h>
22 #ifndef CONFIG_NO_FRAME_POINTER
32 #define BAD_PREFETCH 0
34 #define BAD_ADDREXCPTN 2
36 #define BAD_UNDEFINSTR 4
38 #define PT_TRACESYS 0x00000002
40 @ OS version number used in SWIs
45 #define ARMSWI_OFFSET 0x000f0000
48 @ Stack format (ensured by USER_* and SVC_*)
50 #define S_FRAME_SIZE 72 @ FIXME: Really?
79 .macro slow_restore_user_regs
80 ldmia sp, {r0 - lr}^ @ restore the user regs
82 ldr lr, [sp, #15*4] @ get user PC
83 add sp, sp, #15*4+8 @ free stack
87 .macro fast_restore_user_regs
96 .macro mask_pc, rd, rm
100 .macro disable_irqs, temp
102 orr \temp, \temp, #PSR_I_BIT
106 .macro enable_irqs, temp
108 and \temp, \temp, #~PSR_I_BIT
112 .macro initialise_traps_extra
115 .macro get_thread_info, rd
117 mov \rd, \rd, lsl #13
121 * Like adr, but force SVC mode (if required)
123 .macro adrsvc, cond, reg, label
124 adr\cond \reg, \label
125 orr\cond \reg, \reg, #PSR_I_BIT | MODE_SVC26
130 * These are the registers used in the syscall handler, and allow us to
131 * have in theory up to 7 arguments to a function - r0 to r6.
133 * r7 is reserved for the system call number for thumb mode.
135 * Note that tbl == why is intentional.
137 * We must set at least "tsk" and "why" when calling ret_with_reschedule.
139 scno .req r7 @ syscall number
140 tbl .req r8 @ syscall table pointer
141 why .req r8 @ Linux syscall (!= 0)
142 tsk .req r9 @ current thread_info
145 * Get the system call number.
149 ldr scno, [lr, #-4] @ get SWI instruction
152 * -----------------------------------------------------------------------
156 * We rely on the fact that R0 is at the bottom of the stack (due to
157 * slow/fast restore user regs).
164 * Our do_softirq out of line code. See include/asm-arm26/hardirq.h for
165 * the calling assembly.
168 stmfd sp!, {r0 - r3, ip, lr}
170 ldmfd sp!, {r0 - r3, ip, pc}
175 * This is the fast syscall return path. We do as little as
176 * possible here, and this includes saving r0 back into the SVC
180 disable_irqs r1 @ disable interrupts
181 ldr r1, [tsk, #TI_FLAGS]
182 tst r1, #_TIF_WORK_MASK
183 bne fast_work_pending
184 fast_restore_user_regs
187 * Ok, we need to do extra processing, enter the slow path.
190 str r0, [sp, #S_R0+S_OFF]! @ returned r0
192 tst r1, #_TIF_NEED_RESCHED
194 tst r1, #_TIF_NOTIFY_RESUME | _TIF_SIGPENDING
197 mov r2, why @ 'syscall'
199 disable_irqs r1 @ disable interrupts
205 * "slow" syscall return path. "why" tells us if this was a real syscall.
209 disable_irqs r1 @ disable interrupts
210 ldr r1, [tsk, #TI_FLAGS]
211 tst r1, #_TIF_WORK_MASK
214 slow_restore_user_regs
217 * This is how we return from a fork.
222 ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing
224 tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
227 mov r0, #1 @ trace exit [IP = 1]
231 #include <asm/calls.h>
233 /*=============================================================================
235 *-----------------------------------------------------------------------------
244 #ifdef CONFIG_ALIGNMENT_TRAP
245 ldr ip, __cr_alignment
247 mcr p15, 0, ip, c1, c0 @ update control register
251 str r4, [sp, #-S_OFF]! @ push fifth arg
254 ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing
255 bic scno, scno, #0xff000000 @ mask off SWI op-code
256 eor scno, scno, #OS_NUMBER << 20 @ check OS number
257 adr tbl, sys_call_table @ load syscall table pointer
258 tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
261 adrsvc al, lr, ret_fast_syscall @ return address
262 cmp scno, #NR_syscalls @ check upper syscall limit
263 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
266 2: mov why, #0 @ no longer a real syscall
267 cmp scno, #ARMSWI_OFFSET
268 eor r0, scno, #OS_NUMBER << 20 @ put OS number back
270 b sys_ni_syscall @ not private func
273 * This is the really slow path. We're going to be doing
274 * context switches, and waiting for our parent to respond.
278 mov r0, #0 @ trace entry [IP = 0]
281 adrsvc al, lr, __sys_trace_return @ return address
282 add r1, sp, #S_R0 + S_OFF @ pointer to regs
283 cmp scno, #NR_syscalls @ check upper syscall limit
284 ldmccia r1, {r0 - r3} @ have to reload r0 - r3
285 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
289 str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
291 mov r0, #1 @ trace exit [IP = 1]
296 #ifdef CONFIG_ALIGNMENT_TRAP
297 .type __cr_alignment, #object
302 .type sys_call_table, #object
303 ENTRY(sys_call_table)
304 #include <asm/calls.h>
306 /*============================================================================
307 * Special system call wrappers
309 @ r0 = syscall number
311 .type sys_syscall, #function
313 eor scno, r0, #OS_NUMBER << 20
314 cmp scno, #NR_syscalls @ check range
315 stmleia sp, {r5, r6} @ shuffle args
320 ldrle pc, [tbl, scno, lsl #2]
339 sys_sigsuspend_wrapper:
343 sys_rt_sigsuspend_wrapper:
347 sys_sigreturn_wrapper:
351 sys_rt_sigreturn_wrapper:
355 sys_sigaltstack_wrapper:
356 ldr r2, [sp, #S_OFF + S_SP]
360 * Note: off_4k (r5) is always units of 4K. If we can't do the requested
361 * offset, we return EINVAL. FIXME - this lost some stuff from arm32 to
362 * ifdefs. check it out.
365 tst r5, #((1 << (PAGE_SHIFT - 12)) - 1)
366 moveq r5, r5, lsr #PAGE_SHIFT - 12
374 * - We have several modes that each vector can be called from,
375 * each with its own set of registers. On entry to any vector,
376 * we *must* save the registers used in *that* mode.
378 * - This code must be as fast as possible.
380 * There are a few restrictions on the vectors:
381 * - the SWI vector cannot be called from *any* non-user mode
383 * - the FP emulator is *never* called from *any* non-user mode undefined
390 .equ ioc_base_high, IOC_BASE & 0xff000000
391 .equ ioc_base_low, IOC_BASE & 0x00ff0000
393 mov r12, #ioc_base_high
395 orr r12, r12, #ioc_base_low
397 strb r12, [r12, #0x38] @ Disable FIQ register
400 .macro get_irqnr_and_base, irqnr, base
401 mov r4, #ioc_base_high @ point at IOC
403 orr r4, r4, #ioc_base_low
405 ldrb \irqnr, [r4, #0x24] @ get high priority first
406 adr \base, irq_prio_h
408 ldreqb \irqnr, [r4, #0x14] @ get low priority
409 adreq \base, irq_prio_l
413 * Interrupt table (incorporates priority)
415 .macro irq_prio_table
416 irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
417 .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
418 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
419 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
420 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
421 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
422 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
423 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
424 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
425 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
426 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
427 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
428 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
429 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
430 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
431 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
432 irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
433 .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
434 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
435 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
436 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
437 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
438 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
439 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
440 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
441 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
442 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
443 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
444 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
445 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
446 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
447 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
451 /* FIXME (well, ok, dont - but its easy to grep for :) */
453 * Uncomment these if you wish to get more debugging into about data aborts.
455 #define FAULT_CODE_LDRSTRPOST 0x80
456 #define FAULT_CODE_LDRSTRPRE 0x40
457 #define FAULT_CODE_LDRSTRREG 0x20
458 #define FAULT_CODE_LDMSTM 0x10
459 #define FAULT_CODE_LDCSTC 0x08
461 #define FAULT_CODE_PREFETCH 0x04
462 #define FAULT_CODE_WRITE 0x02
463 #define FAULT_CODE_FORCECOW 0x01
465 #define SVC_SAVE_ALL \
466 str sp, [sp, #-16]! ;\
469 stmfd sp!, {r0 - r12} ;\
471 str r0, [sp, #S_OLD_R0] ;\
474 #define SVC_IRQ_SAVE_ALL \
475 str sp, [sp, #-16]! ;\
480 stmfd sp!, {r0 - r12} ;\
482 str r0, [sp, #S_OLD_R0] ;\
485 #define SVC_RESTORE_ALL \
488 /*=============================================================================
490 *-----------------------------------------------------------------------------
492 _unexp_fiq: ldr sp, .LCfiq
494 strb r12, [r12, #0x38] @ Disable FIQ register
495 teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_SVC26
497 stmfd sp!, {r0 - r3, ip, lr}
500 ldmfd sp!, {r0 - r3, ip, lr}
501 teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_FIQ26
505 Lfiqmsg: .ascii "*** Unexpected FIQ\n\0"
508 .LCfiq: .word __temp_fiq
509 .LCirq: .word __temp_irq
511 /*=============================================================================
512 * Undefined instruction handler
513 *-----------------------------------------------------------------------------
514 * Handles floating point instructions
517 tst lr, #MODE_SVC26 @ did we come from a non-user mode?
518 bne __und_svc @ yes - deal with it.
519 /* Otherwise, fall through for the user-space (common) case. */
521 zero_fp @ zero frame pointer
522 teqp pc, #PSR_I_BIT | MODE_SVC26 @ disable IRQs
525 ldr pc, [r4] @ Call FP module entry point
526 /* FIXME - should we trap for a null pointer here? */
528 /* The SVC mode case */
529 __und_svc: SVC_SAVE_ALL @ Non-user mode
537 /* We get here if the FP emulator doesnt handle the undef instr.
538 * If the insn WAS handled, the emulator jumps to ret_from_exception by itself/
546 b ret_from_exception @ Normal FP exit
548 #if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE
549 /* The FPE is always present */
550 .equ fpe_not_present, 0
552 /* We get here if an undefined instruction happens and the floating
553 * point emulator is not present. If the offending instruction was
554 * a WFS, we just perform a normal return as if we had emulated the
555 * operation. This is a hack to allow some basic userland binaries
556 * to run so that the emulator module proper can be loaded. --philb
557 * FIXME - probably a broken useless hack...
560 adr r10, wfs_mask_data
561 ldmia r10, {r4, r5, r6, r7, r8}
562 ldr r10, [sp, #S_PC] @ Load PC
565 ldrt r10, [r10] @ get instruction
567 teq r5, r4 @ Is it WFS?
568 beq ret_from_exception
570 teq r5, r6 @ Is it LDF/STF on sp or fp?
573 tst r10, #0x00200000 @ Does it have WB
574 beq ret_from_exception
575 and r4, r10, #255 @ get offset
576 and r6, r10, #0x000f0000
577 tst r10, #0x00800000 @ +/-
578 ldr r5, [sp, r6, lsr #14] @ Load reg
580 add r5, r5, r4, lsl #2
581 str r5, [sp, r6, lsr #14] @ Save reg
584 wfs_mask_data: .word 0x0e200110 @ WFS/RFS
586 .word 0x0d0d0100 @ LDF [sp]/STF [sp]
587 .word 0x0d0b0100 @ LDF [fp]/STF [fp]
593 /*=============================================================================
594 * Prefetch abort handler
595 *-----------------------------------------------------------------------------
598 /* remember: lr = USR pc */
604 teqp pc, #MODE_SVC26 @ Enable IRQs...
605 mask_pc r0, lr @ Address of abort
606 mov r1, sp @ Tasks registers
608 teq r0, #0 @ If non-zero, we believe this abort..
609 bne ret_from_exception
614 ldr lr, [sp,#S_PC] @ FIXME program to test this on. I think its
615 b .Lbug_undef @ broken at the moment though!)
617 __pabt_invalid: SVC_SAVE_ALL
618 mov r0, sp @ Prefetch aborts are definitely *not*
619 mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant
620 and r2, lr, #3 @ recover from this problem.
624 t: .ascii "*** undef ***\r\n\0"
628 /*=============================================================================
629 * Address exception handler
630 *-----------------------------------------------------------------------------
631 * These aren't too critical.
632 * (they're not supposed to happen).
633 * In order to debug the reason for address exceptions in non-user modes,
634 * we have to obtain all the registers so that we can see what's going on.
640 bne Laddrexcptn_not_user
643 mask_pc r0, lr @ Point to instruction
644 mov r1, sp @ Point to registers
650 Laddrexcptn_not_user:
654 bne Laddrexcptn_illegal_mode
660 ldmia sp, {r0 - lr} @ I cant remember the reason I changed this...
664 Laddrexcptn_illegal_mode:
667 orr r1, r2, #PSR_I_BIT | PSR_F_BIT
668 teqp r1, #0 @ change into mode (wont be user mode)
670 mov r1, r8 @ Any register from r8 - r14 can be banked
677 teqp pc, #PSR_F_BIT | MODE_SVC26 @ back to svc
683 mov r1, #BAD_ADDREXCPTN
686 /*=============================================================================
687 * Interrupt (IRQ) handler
688 *-----------------------------------------------------------------------------
689 * Note: if in user mode, then *no* kernel routine is running, so do not have
691 * (r13 points to irq temp save area)
694 vector_IRQ: ldr r13, .LCirq @ I will leave this one in just in case...
699 teqp pc, #PSR_I_BIT | MODE_SVC26
705 1: get_irqnr_and_base r6, r5
707 ldrneb r0, [r5, r6] @ get IRQ number
710 @ routine called with r0 = irq number, r1 = struct pt_regs *
713 orr lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC
717 get_thread_info tsk @ FIXME - was r5, but seemed wrong.
722 __irq_svc: teqp pc, #PSR_I_BIT | MODE_SVC26
728 1: get_irqnr_and_base r6, r5
730 ldrneb r0, [r5, r6] @ get IRQ number
733 @ routine called with r0 = irq number, r1 = struct pt_regs *
736 orr lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC
737 bne asm_do_IRQ @ Returns to 1b
740 __irq_invalid: mov r0, sp
744 /*=============================================================================
745 * Data abort handler code
746 *-----------------------------------------------------------------------------
748 * This handles both exceptions from user and SVC modes, computes the address
749 * range of the problem, and does any correction that is required. It then
750 * calls the kernel data abort routine.
752 * This is where I wish that the ARM would tell you which address aborted.
755 vector_data: sub lr, lr, #8 @ Correct lr
768 bne Ldata_illegal_mode
770 teqeqp pc, #MODE_SVC26
781 ldr r4, [r0] @ Get instruction
783 tst r4, #1 << 20 @ Check to see if it is a write instruction
784 orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
785 mov r1, r4, lsr #22 @ Now branch to the relevent processing routine
793 b Ldata_ldrstr_post @ ldr rd, [rn], #m
794 b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal
795 b Ldata_ldrstr_post @ ldr rd, [rn], rm
796 b Ldata_ldrstr_regindex @ ldr rd, [rn, rm]
797 b Ldata_ldmstm @ ldm*a rn, <rlist>
798 b Ldata_ldmstm @ ldm*b rn, <rlist>
801 b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
802 b Ldata_ldcstc_pre @ ldc rd, [rn, #m]
804 Ldata_unknown: @ Part of jumptable
811 mov r0, r4, lsr #14 @ Get Rn
812 and r0, r0, #15 << 2 @ Mask out reg.
814 ldr r0, [r3, r0] @ Get register
815 biceq r0, r0, #PCMASK
817 #ifdef FAULT_CODE_LDRSTRPOST
818 orr r2, r2, #FAULT_CODE_LDRSTRPOST
822 Ldata_ldrstr_numindex:
823 mov r0, r4, lsr #14 @ Get Rn
824 and r0, r0, #15 << 2 @ Mask out reg.
826 ldr r0, [r3, r0] @ Get register
828 biceq r0, r0, #PCMASK
830 addne r0, r0, r1, lsr #20
831 subeq r0, r0, r1, lsr #20
833 #ifdef FAULT_CODE_LDRSTRPRE
834 orr r2, r2, #FAULT_CODE_LDRSTRPRE
838 Ldata_ldrstr_regindex:
839 mov r0, r4, lsr #14 @ Get Rn
840 and r0, r0, #15 << 2 @ Mask out reg.
842 ldr r0, [r3, r0] @ Get register
844 biceq r0, r0, #PCMASK
845 teq r7, #15 @ Check for PC
846 ldr r7, [r3, r7, lsl #2] @ Get Rm
847 and r8, r4, #0x60 @ Get shift types
848 biceq r7, r7, #PCMASK
849 mov r9, r4, lsr #7 @ Get shift amount
853 teq r8, #0x20 @ LSR shift
855 teq r8, #0x40 @ ASR shift
857 teq r8, #0x60 @ ROR shift
861 subeq r0, r0, r7 @ Apply correction
863 #ifdef FAULT_CODE_LDRSTRREG
864 orr r2, r2, #FAULT_CODE_LDRSTRREG
870 orr r7, r7, r7, lsl #8
872 and r1, r4, r7, lsl #1
873 add r0, r0, r1, lsr #1
874 and r1, r4, r7, lsl #2
875 add r0, r0, r1, lsr #2
876 and r1, r4, r7, lsl #3
877 add r0, r0, r1, lsr #3
878 add r0, r0, r0, lsr #8
879 add r0, r0, r0, lsr #4
880 and r7, r0, #15 @ r7 = no. of registers to transfer.
881 mov r5, r4, lsr #14 @ Get Rn
883 ldr r0, [r3, r5] @ Get reg
884 eor r6, r4, r4, lsl #2
885 tst r6, #1 << 23 @ Check inc/dec ^ writeback
887 add r7, r0, r7, lsl #2 @ Do correction (signed)
891 tst r4, #1 << 21 @ Check writeback
893 eor r6, r4, r4, lsl #1
894 tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec
897 teq r5, #15*4 @ CHECK FOR PC
898 biceq r1, r1, #PCMASK
899 biceq r0, r0, #PCMASK
900 #ifdef FAULT_CODE_LDMSTM
901 orr r2, r2, #FAULT_CODE_LDMSTM
906 mov r0, r4, lsr #14 @ Get Rn
907 and r0, r0, #15 << 2 @ Mask out reg.
909 ldr r0, [r3, r0] @ Get register
910 mov r1, r4, lsl #24 @ Get offset
911 biceq r0, r0, #PCMASK
913 addne r0, r0, r1, lsr #24
914 subeq r0, r0, r1, lsr #24
916 #ifdef FAULT_CODE_LDCSTC
917 orr r2, r2, #FAULT_CODE_LDCSTC
923 * This is the return code to user mode for abort handlers
925 ENTRY(ret_from_exception)
932 .word fpe_not_present
935 * Register switch for older 26-bit only ARMs
938 add r0, r0, #TI_CPU_SAVE
939 stmia r0, {r4 - sl, fp, sp, lr}
940 add r1, r1, #TI_CPU_SAVE
941 ldmia r1, {r4 - sl, fp, sp, pc}^
944 *=============================================================================
945 * Low-level interface code
946 *-----------------------------------------------------------------------------
947 * Trap initialisation
948 *-----------------------------------------------------------------------------
950 * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20
951 * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes
952 * some excess cycles).
954 * What we need to put into 0-0x1c are branches to branch to the kernel.
957 .section ".init.text",#alloc,#execinstr
961 .word vector_undefinstr - 12
962 .word vector_swi - 16
963 .word vector_prefetch - 20
964 .word vector_data - 24
965 .word vector_addrexcptn - 28
966 .word vector_IRQ - 32
967 .word _unexp_fiq - 36
970 * initialise the trap system
973 stmfd sp!, {r4 - r7, lr}
974 adr r1, .Ljump_addresses
975 ldmia r1, {r1 - r7, ip, lr}
976 orr r2, lr, r2, lsr #2
977 orr r3, lr, r3, lsr #2
978 orr r4, lr, r4, lsr #2
979 orr r5, lr, r5, lsr #2
980 orr r6, lr, r6, lsr #2
981 orr r7, lr, r7, lsr #2
982 orr ip, lr, ip, lsr #2
984 stmia r0, {r1 - r7, ip}
985 ldmfd sp!, {r4 - r7, pc}^
988 __temp_irq: .space 4 @ saved lr_irq
989 __temp_fiq: .space 128