1 /* arch/arm26/kernel/entry.S
3 * Assembled from chunks of code in arch/arm
5 * Copyright (C) 2003 Ian Molton
6 * Based on the work of RMK.
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 @ OS version number used in SWIs
43 #define ARMSWI_OFFSET 0x000f0000
46 @ Stack format (ensured by USER_* and SVC_*)
47 @ PSR and PC are comined on arm26
71 str r0, [sp, #-4]! @ Store SVC r0
72 str lr, [sp, #-4]! @ Store user mode PC
74 stmia sp, {r0 - lr}^ @ Store the other user-mode regs
78 .macro slow_restore_user_regs
79 ldmia sp, {r0 - lr}^ @ restore the user regs not including PC
81 ldr lr, [sp, #15*4] @ get user PC
82 add sp, sp, #15*4+8 @ free stack
86 .macro fast_restore_user_regs
101 str r0, [sp, #S_OLD_R0]
105 .macro save_svc_regs_irq
111 stmfd sp!, {r0 - r12}
113 str r0, [sp, #S_OLD_R0]
117 .macro restore_svc_regs
121 .macro mask_pc, rd, rm
122 bic \rd, \rm, #PCMASK
125 .macro disable_irqs, temp
127 orr \temp, \temp, #PSR_I_BIT
131 .macro enable_irqs, temp
133 and \temp, \temp, #~PSR_I_BIT
137 .macro initialise_traps_extra
140 .macro get_thread_info, rd
142 mov \rd, \rd, lsl #13
146 * These are the registers used in the syscall handler, and allow us to
147 * have in theory up to 7 arguments to a function - r0 to r6.
149 * Note that tbl == why is intentional.
151 * We must set at least "tsk" and "why" when calling ret_with_reschedule.
153 scno .req r7 @ syscall number
154 tbl .req r8 @ syscall table pointer
155 why .req r8 @ Linux syscall (!= 0)
156 tsk .req r9 @ current thread_info
159 * Get the system call number.
163 ldr scno, [lr, #-4] @ get SWI instruction
166 * -----------------------------------------------------------------------
170 * We rely on the fact that R0 is at the bottom of the stack (due to
171 * slow/fast restore user regs).
178 * This is the fast syscall return path. We do as little as
179 * possible here, and this includes saving r0 back into the SVC
183 disable_irqs r1 @ disable interrupts
184 ldr r1, [tsk, #TI_FLAGS]
185 tst r1, #_TIF_WORK_MASK
186 bne fast_work_pending
187 fast_restore_user_regs
190 * Ok, we need to do extra processing, enter the slow path.
193 str r0, [sp, #S_R0+S_OFF]! @ returned r0
195 tst r1, #_TIF_NEED_RESCHED
197 tst r1, #_TIF_NOTIFY_RESUME | _TIF_SIGPENDING
200 mov r2, why @ 'syscall'
202 disable_irqs r1 @ disable interrupts
208 * "slow" syscall return path. "why" tells us if this was a real syscall.
212 disable_irqs r1 @ disable interrupts
213 ldr r1, [tsk, #TI_FLAGS]
214 tst r1, #_TIF_WORK_MASK
217 slow_restore_user_regs
220 * This is how we return from a fork.
225 ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing
227 tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
230 mov r0, #1 @ trace exit [IP = 1]
234 // FIXME - is this strictly necessary?
237 /*=============================================================================
239 *-----------------------------------------------------------------------------
250 str r4, [sp, #-S_OFF]! @ push fifth arg
253 ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing
254 bic scno, scno, #0xff000000 @ mask off SWI op-code
255 eor scno, scno, #OS_NUMBER << 20 @ check OS number
256 adr tbl, sys_call_table @ load syscall table pointer
257 tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls?
260 adral lr, ret_fast_syscall @ set return address
261 orral lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return
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 adral lr, __sys_trace_return @ set return address
282 orral lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return
283 add r1, sp, #S_R0 + S_OFF @ pointer to regs
284 cmp scno, #NR_syscalls @ check upper syscall limit
285 ldmccia r1, {r0 - r3} @ have to reload r0 - r3
286 ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine
290 str r0, [sp, #S_R0 + S_OFF]! @ save returned r0
292 mov r0, #1 @ trace exit [IP = 1]
298 .type sys_call_table, #object
299 ENTRY(sys_call_table)
302 /*============================================================================
303 * Special system call wrappers
305 @ r0 = syscall number
307 .type sys_syscall, #function
309 eor scno, r0, #OS_NUMBER << 20
310 cmp scno, #NR_syscalls @ check range
311 stmleia sp, {r5, r6} @ shuffle args
316 ldrle pc, [tbl, scno, lsl #2]
335 sys_sigsuspend_wrapper:
339 sys_rt_sigsuspend_wrapper:
343 sys_sigreturn_wrapper:
347 sys_rt_sigreturn_wrapper:
351 sys_sigaltstack_wrapper:
352 ldr r2, [sp, #S_OFF + S_SP]
356 * Note: off_4k (r5) is always units of 4K. If we can't do the requested
357 * offset, we return EINVAL. FIXME - this lost some stuff from arm32 to
358 * ifdefs. check it out.
361 tst r5, #((1 << (PAGE_SHIFT - 12)) - 1)
362 moveq r5, r5, lsr #PAGE_SHIFT - 12
370 * - We have several modes that each vector can be called from,
371 * each with its own set of registers. On entry to any vector,
372 * we *must* save the registers used in *that* mode.
374 * - This code must be as fast as possible.
376 * There are a few restrictions on the vectors:
377 * - the SWI vector cannot be called from *any* non-user mode
379 * - the FP emulator is *never* called from *any* non-user mode undefined
388 ldrb r6, [r4, #0x24] @ get high priority first
391 ldreqb r6, [r4, #0x14] @ get low priority
394 teq r6, #0 @ If an IRQ happened...
395 ldrneb r0, [r5, r6] @ get IRQ number
396 movne r1, sp @ get struct pt_regs
397 adrne lr, 1b @ Set return address to 1b
398 orrne lr, lr, #PSR_I_BIT | MODE_SVC26 @ (and force SVC mode)
399 bne asm_do_IRQ @ process IRQ (if asserted)
404 * Interrupt table (incorporates priority)
406 .macro irq_prio_table
407 irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
408 .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3
409 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
410 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
411 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
412 .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3
413 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
414 .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
415 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
416 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
417 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
418 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
419 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
420 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
421 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
422 .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
423 irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
424 .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10
425 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
426 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
427 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
428 .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10
429 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
430 .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10
431 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
432 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
433 .byte 13,13,13,13,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 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
436 .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10
437 .byte 13,13,13,13,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
443 * Uncomment these if you wish to get more debugging into about data aborts.
444 * FIXME - I bet we can find a way to encode these and keep performance.
446 #define FAULT_CODE_LDRSTRPOST 0x80
447 #define FAULT_CODE_LDRSTRPRE 0x40
448 #define FAULT_CODE_LDRSTRREG 0x20
449 #define FAULT_CODE_LDMSTM 0x10
450 #define FAULT_CODE_LDCSTC 0x08
452 #define FAULT_CODE_PREFETCH 0x04
453 #define FAULT_CODE_WRITE 0x02
454 #define FAULT_CODE_FORCECOW 0x01
456 /*=============================================================================
458 *-----------------------------------------------------------------------------
460 _unexp_fiq: ldr sp, .LCfiq
462 strb r12, [r12, #0x38] @ Disable FIQ register
463 teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_SVC26
465 stmfd sp!, {r0 - r3, ip, lr}
468 ldmfd sp!, {r0 - r3, ip, lr}
469 teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_FIQ26
473 Lfiqmsg: .ascii "*** Unexpected FIQ\n\0"
476 .LCfiq: .word __temp_fiq
477 .LCirq: .word __temp_irq
479 /*=============================================================================
480 * Undefined instruction handler
481 *-----------------------------------------------------------------------------
482 * Handles floating point instructions
485 tst lr, #MODE_SVC26 @ did we come from a non-user mode?
486 bne __und_svc @ yes - deal with it.
487 /* Otherwise, fall through for the user-space (common) case. */
489 zero_fp @ zero frame pointer
490 teqp pc, #PSR_I_BIT | MODE_SVC26 @ disable IRQs
493 ldr pc, [r4] @ Call FP module entry point
494 /* FIXME - should we trap for a null pointer here? */
496 /* The SVC mode case */
497 __und_svc: save_svc_regs @ Non-user mode
505 /* We get here if the FP emulator doesnt handle the undef instr.
506 * If the insn WAS handled, the emulator jumps to ret_from_exception by itself/
514 b ret_from_exception @ Normal FP exit
516 #if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE
517 /* The FPE is always present */
518 .equ fpe_not_present, 0
520 /* We get here if an undefined instruction happens and the floating
521 * point emulator is not present. If the offending instruction was
522 * a WFS, we just perform a normal return as if we had emulated the
523 * operation. This is a hack to allow some basic userland binaries
524 * to run so that the emulator module proper can be loaded. --philb
525 * FIXME - probably a broken useless hack...
528 adr r10, wfs_mask_data
529 ldmia r10, {r4, r5, r6, r7, r8}
530 ldr r10, [sp, #S_PC] @ Load PC
533 ldrt r10, [r10] @ get instruction
535 teq r5, r4 @ Is it WFS?
536 beq ret_from_exception
538 teq r5, r6 @ Is it LDF/STF on sp or fp?
541 tst r10, #0x00200000 @ Does it have WB
542 beq ret_from_exception
543 and r4, r10, #255 @ get offset
544 and r6, r10, #0x000f0000
545 tst r10, #0x00800000 @ +/-
546 ldr r5, [sp, r6, lsr #14] @ Load reg
548 add r5, r5, r4, lsl #2
549 str r5, [sp, r6, lsr #14] @ Save reg
552 wfs_mask_data: .word 0x0e200110 @ WFS/RFS
554 .word 0x0d0d0100 @ LDF [sp]/STF [sp]
555 .word 0x0d0b0100 @ LDF [fp]/STF [fp]
561 /*=============================================================================
562 * Prefetch abort handler
563 *-----------------------------------------------------------------------------
566 /* remember: lr = USR pc */
572 teqp pc, #MODE_SVC26 @ Enable IRQs...
573 mask_pc r0, lr @ Address of abort
574 mov r1, sp @ Tasks registers
576 teq r0, #0 @ If non-zero, we believe this abort..
577 bne ret_from_exception
582 ldr lr, [sp,#S_PC] @ FIXME program to test this on. I think its
583 b .Lbug_undef @ broken at the moment though!)
585 __pabt_invalid: save_svc_regs
586 mov r0, sp @ Prefetch aborts are definitely *not*
587 mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant
588 and r2, lr, #3 @ recover from this problem.
592 t: .ascii "*** undef ***\r\n\0"
596 /*=============================================================================
597 * Address exception handler
598 *-----------------------------------------------------------------------------
599 * These aren't too critical.
600 * (they're not supposed to happen).
601 * In order to debug the reason for address exceptions in non-user modes,
602 * we have to obtain all the registers so that we can see what's going on.
608 bne Laddrexcptn_not_user
611 mask_pc r0, lr @ Point to instruction
612 mov r1, sp @ Point to registers
618 Laddrexcptn_not_user:
622 bne Laddrexcptn_illegal_mode
628 ldmia sp, {r0 - lr} @ I cant remember the reason I changed this...
632 Laddrexcptn_illegal_mode:
635 orr r1, r2, #PSR_I_BIT | PSR_F_BIT
636 teqp r1, #0 @ change into mode (wont be user mode)
638 mov r1, r8 @ Any register from r8 - r14 can be banked
645 teqp pc, #PSR_F_BIT | MODE_SVC26 @ back to svc
651 mov r1, #BAD_ADDREXCPTN
654 /*=============================================================================
655 * Interrupt (IRQ) handler
656 *-----------------------------------------------------------------------------
657 * Note: if the IRQ was taken whilst in user mode, then *no* kernel routine
658 * is running, so do not have to save svc lr.
660 * Entered in IRQ mode.
663 vector_IRQ: ldr sp, .LCirq @ Setup some temporary stack
665 str lr, [sp] @ push return address
670 __irq_usr: teqp pc, #PSR_I_BIT | MODE_SVC26 @ Enter SVC mode
674 ldr lr, [lr] @ Restore lr for jump back to USR
684 @ Place the IRQ priority table here so that the handle_irq macros above
685 @ and below here can access it.
689 __irq_non_usr: teqp pc, #PSR_I_BIT | MODE_SVC26 @ Enter SVC mode
696 bne __irq_invalid @ IRQ not from SVC mode
702 __irq_invalid: mov r0, sp
706 /*=============================================================================
707 * Data abort handler code
708 *-----------------------------------------------------------------------------
710 * This handles both exceptions from user and SVC modes, computes the address
711 * range of the problem, and does any correction that is required. It then
712 * calls the kernel data abort routine.
714 * This is where I wish that the ARM would tell you which address aborted.
717 vector_data: sub lr, lr, #8 @ Correct lr
730 bne Ldata_illegal_mode
732 teqeqp pc, #MODE_SVC26
743 ldr r4, [r0] @ Get instruction
745 tst r4, #1 << 20 @ Check to see if it is a write instruction
746 orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction
747 mov r1, r4, lsr #22 @ Now branch to the relevent processing routine
755 b Ldata_ldrstr_post @ ldr rd, [rn], #m
756 b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal
757 b Ldata_ldrstr_post @ ldr rd, [rn], rm
758 b Ldata_ldrstr_regindex @ ldr rd, [rn, rm]
759 b Ldata_ldmstm @ ldm*a rn, <rlist>
760 b Ldata_ldmstm @ ldm*b rn, <rlist>
763 b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m
764 b Ldata_ldcstc_pre @ ldc rd, [rn, #m]
766 Ldata_unknown: @ Part of jumptable
773 mov r0, r4, lsr #14 @ Get Rn
774 and r0, r0, #15 << 2 @ Mask out reg.
776 ldr r0, [r3, r0] @ Get register
777 biceq r0, r0, #PCMASK
779 #ifdef FAULT_CODE_LDRSTRPOST
780 orr r2, r2, #FAULT_CODE_LDRSTRPOST
784 Ldata_ldrstr_numindex:
785 mov r0, r4, lsr #14 @ Get Rn
786 and r0, r0, #15 << 2 @ Mask out reg.
788 ldr r0, [r3, r0] @ Get register
790 biceq r0, r0, #PCMASK
792 addne r0, r0, r1, lsr #20
793 subeq r0, r0, r1, lsr #20
795 #ifdef FAULT_CODE_LDRSTRPRE
796 orr r2, r2, #FAULT_CODE_LDRSTRPRE
800 Ldata_ldrstr_regindex:
801 mov r0, r4, lsr #14 @ Get Rn
802 and r0, r0, #15 << 2 @ Mask out reg.
804 ldr r0, [r3, r0] @ Get register
806 biceq r0, r0, #PCMASK
807 teq r7, #15 @ Check for PC
808 ldr r7, [r3, r7, lsl #2] @ Get Rm
809 and r8, r4, #0x60 @ Get shift types
810 biceq r7, r7, #PCMASK
811 mov r9, r4, lsr #7 @ Get shift amount
815 teq r8, #0x20 @ LSR shift
817 teq r8, #0x40 @ ASR shift
819 teq r8, #0x60 @ ROR shift
823 subeq r0, r0, r7 @ Apply correction
825 #ifdef FAULT_CODE_LDRSTRREG
826 orr r2, r2, #FAULT_CODE_LDRSTRREG
832 orr r7, r7, r7, lsl #8
834 and r1, r4, r7, lsl #1
835 add r0, r0, r1, lsr #1
836 and r1, r4, r7, lsl #2
837 add r0, r0, r1, lsr #2
838 and r1, r4, r7, lsl #3
839 add r0, r0, r1, lsr #3
840 add r0, r0, r0, lsr #8
841 add r0, r0, r0, lsr #4
842 and r7, r0, #15 @ r7 = no. of registers to transfer.
843 mov r5, r4, lsr #14 @ Get Rn
845 ldr r0, [r3, r5] @ Get reg
846 eor r6, r4, r4, lsl #2
847 tst r6, #1 << 23 @ Check inc/dec ^ writeback
849 add r7, r0, r7, lsl #2 @ Do correction (signed)
853 tst r4, #1 << 21 @ Check writeback
855 eor r6, r4, r4, lsl #1
856 tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec
859 teq r5, #15*4 @ CHECK FOR PC
860 biceq r1, r1, #PCMASK
861 biceq r0, r0, #PCMASK
862 #ifdef FAULT_CODE_LDMSTM
863 orr r2, r2, #FAULT_CODE_LDMSTM
868 mov r0, r4, lsr #14 @ Get Rn
869 and r0, r0, #15 << 2 @ Mask out reg.
871 ldr r0, [r3, r0] @ Get register
872 mov r1, r4, lsl #24 @ Get offset
873 biceq r0, r0, #PCMASK
875 addne r0, r0, r1, lsr #24
876 subeq r0, r0, r1, lsr #24
878 #ifdef FAULT_CODE_LDCSTC
879 orr r2, r2, #FAULT_CODE_LDCSTC
885 * This is the return code to user mode for abort handlers
887 ENTRY(ret_from_exception)
894 .word fpe_not_present
897 * Register switch for older 26-bit only ARMs
900 add r0, r0, #TI_CPU_SAVE
901 stmia r0, {r4 - sl, fp, sp, lr}
902 add r1, r1, #TI_CPU_SAVE
903 ldmia r1, {r4 - sl, fp, sp, pc}^
906 *=============================================================================
907 * Low-level interface code
908 *-----------------------------------------------------------------------------
909 * Trap initialisation
910 *-----------------------------------------------------------------------------
912 * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20
913 * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes
914 * some excess cycles).
916 * What we need to put into 0-0x1c are branches to branch to the kernel.
919 .section ".init.text",#alloc,#execinstr
923 .word vector_undefinstr - 12
924 .word vector_swi - 16
925 .word vector_prefetch - 20
926 .word vector_data - 24
927 .word vector_addrexcptn - 28
928 .word vector_IRQ - 32
929 .word _unexp_fiq - 36
932 * initialise the trap system
935 stmfd sp!, {r4 - r7, lr}
936 adr r1, .Ljump_addresses
937 ldmia r1, {r1 - r7, ip, lr}
938 orr r2, lr, r2, lsr #2
939 orr r3, lr, r3, lsr #2
940 orr r4, lr, r4, lsr #2
941 orr r5, lr, r5, lsr #2
942 orr r6, lr, r6, lsr #2
943 orr r7, lr, r7, lsr #2
944 orr ip, lr, ip, lsr #2
946 stmia r0, {r1 - r7, ip}
947 ldmfd sp!, {r4 - r7, pc}^
950 __temp_irq: .space 4 @ saved lr_irq
951 __temp_fiq: .space 128