diff options
Diffstat (limited to 'arch/arm26/kernel/entry.S')
-rw-r--r-- | arch/arm26/kernel/entry.S | 951 |
1 files changed, 0 insertions, 951 deletions
diff --git a/arch/arm26/kernel/entry.S b/arch/arm26/kernel/entry.S deleted file mode 100644 index 7ffcc6e4770..00000000000 --- a/arch/arm26/kernel/entry.S +++ /dev/null @@ -1,951 +0,0 @@ -/* arch/arm26/kernel/entry.S - * - * Assembled from chunks of code in arch/arm - * - * Copyright (C) 2003 Ian Molton - * Based on the work of RMK. - * - */ - -#include <linux/linkage.h> - -#include <asm/assembler.h> -#include <asm/asm-offsets.h> -#include <asm/errno.h> -#include <asm/hardware.h> -#include <asm/sysirq.h> -#include <asm/thread_info.h> -#include <asm/page.h> -#include <asm/ptrace.h> - - .macro zero_fp -#ifndef CONFIG_NO_FRAME_POINTER - mov fp, #0 -#endif - .endm - - .text - -@ Bad Abort numbers -@ ----------------- -@ -#define BAD_PREFETCH 0 -#define BAD_DATA 1 -#define BAD_ADDREXCPTN 2 -#define BAD_IRQ 3 -#define BAD_UNDEFINSTR 4 - -@ OS version number used in SWIs -@ RISC OS is 0 -@ RISC iX is 8 -@ -#define OS_NUMBER 9 -#define ARMSWI_OFFSET 0x000f0000 - -@ -@ Stack format (ensured by USER_* and SVC_*) -@ PSR and PC are comined on arm26 -@ - -#define S_OFF 8 - -#define S_OLD_R0 64 -#define S_PC 60 -#define S_LR 56 -#define S_SP 52 -#define S_IP 48 -#define S_FP 44 -#define S_R10 40 -#define S_R9 36 -#define S_R8 32 -#define S_R7 28 -#define S_R6 24 -#define S_R5 20 -#define S_R4 16 -#define S_R3 12 -#define S_R2 8 -#define S_R1 4 -#define S_R0 0 - - .macro save_user_regs - str r0, [sp, #-4]! @ Store SVC r0 - str lr, [sp, #-4]! @ Store user mode PC - sub sp, sp, #15*4 - stmia sp, {r0 - lr}^ @ Store the other user-mode regs - mov r0, r0 - .endm - - .macro slow_restore_user_regs - ldmia sp, {r0 - lr}^ @ restore the user regs not including PC - mov r0, r0 - ldr lr, [sp, #15*4] @ get user PC - add sp, sp, #15*4+8 @ free stack - movs pc, lr @ return - .endm - - .macro fast_restore_user_regs - add sp, sp, #S_OFF - ldmib sp, {r1 - lr}^ - mov r0, r0 - ldr lr, [sp, #15*4] - add sp, sp, #15*4+8 - movs pc, lr - .endm - - .macro save_svc_regs - str sp, [sp, #-16]! - str lr, [sp, #8] - str lr, [sp, #4] - stmfd sp!, {r0 - r12} - mov r0, #-1 - str r0, [sp, #S_OLD_R0] - zero_fp - .endm - - .macro save_svc_regs_irq - str sp, [sp, #-16]! - str lr, [sp, #4] - ldr lr, .LCirq - ldr lr, [lr] - str lr, [sp, #8] - stmfd sp!, {r0 - r12} - mov r0, #-1 - str r0, [sp, #S_OLD_R0] - zero_fp - .endm - - .macro restore_svc_regs - ldmfd sp, {r0 - pc}^ - .endm - - .macro mask_pc, rd, rm - bic \rd, \rm, #PCMASK - .endm - - .macro disable_irqs, temp - mov \temp, pc - orr \temp, \temp, #PSR_I_BIT - teqp \temp, #0 - .endm - - .macro enable_irqs, temp - mov \temp, pc - and \temp, \temp, #~PSR_I_BIT - teqp \temp, #0 - .endm - - .macro initialise_traps_extra - .endm - - .macro get_thread_info, rd - mov \rd, sp, lsr #13 - mov \rd, \rd, lsl #13 - .endm - -/* - * These are the registers used in the syscall handler, and allow us to - * have in theory up to 7 arguments to a function - r0 to r6. - * - * Note that tbl == why is intentional. - * - * We must set at least "tsk" and "why" when calling ret_with_reschedule. - */ -scno .req r7 @ syscall number -tbl .req r8 @ syscall table pointer -why .req r8 @ Linux syscall (!= 0) -tsk .req r9 @ current thread_info - -/* - * Get the system call number. - */ - .macro get_scno - mask_pc lr, lr - ldr scno, [lr, #-4] @ get SWI instruction - .endm -/* - * ----------------------------------------------------------------------- - */ - -/* - * We rely on the fact that R0 is at the bottom of the stack (due to - * slow/fast restore user regs). - */ -#if S_R0 != 0 -#error "Please fix" -#endif - -/* - * This is the fast syscall return path. We do as little as - * possible here, and this includes saving r0 back into the SVC - * stack. - */ -ret_fast_syscall: - disable_irqs r1 @ disable interrupts - ldr r1, [tsk, #TI_FLAGS] - tst r1, #_TIF_WORK_MASK - bne fast_work_pending - fast_restore_user_regs - -/* - * Ok, we need to do extra processing, enter the slow path. - */ -fast_work_pending: - str r0, [sp, #S_R0+S_OFF]! @ returned r0 -work_pending: - tst r1, #_TIF_NEED_RESCHED - bne work_resched - tst r1, #_TIF_SIGPENDING - beq no_work_pending - mov r0, sp @ 'regs' - mov r2, why @ 'syscall' - bl do_notify_resume - disable_irqs r1 @ disable interrupts - b no_work_pending - -work_resched: - bl schedule -/* - * "slow" syscall return path. "why" tells us if this was a real syscall. - */ -ENTRY(ret_to_user) -ret_slow_syscall: - disable_irqs r1 @ disable interrupts - ldr r1, [tsk, #TI_FLAGS] - tst r1, #_TIF_WORK_MASK - bne work_pending -no_work_pending: - slow_restore_user_regs - -/* - * This is how we return from a fork. - */ -ENTRY(ret_from_fork) - bl schedule_tail - get_thread_info tsk - ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing - mov why, #1 - tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? - beq ret_slow_syscall - mov r1, sp - mov r0, #1 @ trace exit [IP = 1] - bl syscall_trace - b ret_slow_syscall - -// FIXME - is this strictly necessary? -#include "calls.S" - -/*============================================================================= - * SWI handler - *----------------------------------------------------------------------------- - */ - - .align 5 -ENTRY(vector_swi) - save_user_regs - zero_fp - get_scno - - enable_irqs ip - - str r4, [sp, #-S_OFF]! @ push fifth arg - - get_thread_info tsk - ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing - bic scno, scno, #0xff000000 @ mask off SWI op-code - eor scno, scno, #OS_NUMBER << 20 @ check OS number - adr tbl, sys_call_table @ load syscall table pointer - tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? - bne __sys_trace - - adral lr, ret_fast_syscall @ set return address - orral lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return - cmp scno, #NR_syscalls @ check upper syscall limit - ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine - - add r1, sp, #S_OFF -2: mov why, #0 @ no longer a real syscall - cmp scno, #ARMSWI_OFFSET - eor r0, scno, #OS_NUMBER << 20 @ put OS number back - bcs arm_syscall - b sys_ni_syscall @ not private func - - /* - * This is the really slow path. We're going to be doing - * context switches, and waiting for our parent to respond. - */ -__sys_trace: - add r1, sp, #S_OFF - mov r0, #0 @ trace entry [IP = 0] - bl syscall_trace - - adral lr, __sys_trace_return @ set return address - orral lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC mode on return - add r1, sp, #S_R0 + S_OFF @ pointer to regs - cmp scno, #NR_syscalls @ check upper syscall limit - ldmccia r1, {r0 - r3} @ have to reload r0 - r3 - ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine - b 2b - -__sys_trace_return: - str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 - mov r1, sp - mov r0, #1 @ trace exit [IP = 1] - bl syscall_trace - b ret_slow_syscall - - .align 5 - - .type sys_call_table, #object -ENTRY(sys_call_table) -#include "calls.S" - -/*============================================================================ - * Special system call wrappers - */ -@ r0 = syscall number -@ r5 = syscall table - .type sys_syscall, #function -sys_syscall: - eor scno, r0, #OS_NUMBER << 20 - cmp scno, #NR_syscalls @ check range - stmleia sp, {r5, r6} @ shuffle args - movle r0, r1 - movle r1, r2 - movle r2, r3 - movle r3, r4 - ldrle pc, [tbl, scno, lsl #2] - b sys_ni_syscall - -sys_fork_wrapper: - add r0, sp, #S_OFF - b sys_fork - -sys_vfork_wrapper: - add r0, sp, #S_OFF - b sys_vfork - -sys_execve_wrapper: - add r3, sp, #S_OFF - b sys_execve - -sys_clone_wapper: - add r2, sp, #S_OFF - b sys_clone - -sys_sigsuspend_wrapper: - add r3, sp, #S_OFF - b sys_sigsuspend - -sys_rt_sigsuspend_wrapper: - add r2, sp, #S_OFF - b sys_rt_sigsuspend - -sys_sigreturn_wrapper: - add r0, sp, #S_OFF - b sys_sigreturn - -sys_rt_sigreturn_wrapper: - add r0, sp, #S_OFF - b sys_rt_sigreturn - -sys_sigaltstack_wrapper: - ldr r2, [sp, #S_OFF + S_SP] - b do_sigaltstack - -/* - * Note: off_4k (r5) is always units of 4K. If we can't do the requested - * offset, we return EINVAL. FIXME - this lost some stuff from arm32 to - * ifdefs. check it out. - */ -sys_mmap2: - tst r5, #((1 << (PAGE_SHIFT - 12)) - 1) - moveq r5, r5, lsr #PAGE_SHIFT - 12 - streq r5, [sp, #4] - beq do_mmap2 - mov r0, #-EINVAL - RETINSTR(mov,pc, lr) - -/* - * Design issues: - * - We have several modes that each vector can be called from, - * each with its own set of registers. On entry to any vector, - * we *must* save the registers used in *that* mode. - * - * - This code must be as fast as possible. - * - * There are a few restrictions on the vectors: - * - the SWI vector cannot be called from *any* non-user mode - * - * - the FP emulator is *never* called from *any* non-user mode undefined - * instruction. - * - */ - - .text - - .macro handle_irq -1: mov r4, #IOC_BASE - ldrb r6, [r4, #0x24] @ get high priority first - adr r5, irq_prio_h - teq r6, #0 - ldreqb r6, [r4, #0x14] @ get low priority - adreq r5, irq_prio_l - - teq r6, #0 @ If an IRQ happened... - ldrneb r0, [r5, r6] @ get IRQ number - movne r1, sp @ get struct pt_regs - adrne lr, 1b @ Set return address to 1b - orrne lr, lr, #PSR_I_BIT | MODE_SVC26 @ (and force SVC mode) - bne asm_do_IRQ @ process IRQ (if asserted) - .endm - - -/* - * Interrupt table (incorporates priority) - */ - .macro irq_prio_table -irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 - .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 -irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 - .endm - -#if 1 -/* - * Uncomment these if you wish to get more debugging into about data aborts. - * FIXME - I bet we can find a way to encode these and keep performance. - */ -#define FAULT_CODE_LDRSTRPOST 0x80 -#define FAULT_CODE_LDRSTRPRE 0x40 -#define FAULT_CODE_LDRSTRREG 0x20 -#define FAULT_CODE_LDMSTM 0x10 -#define FAULT_CODE_LDCSTC 0x08 -#endif -#define FAULT_CODE_PREFETCH 0x04 -#define FAULT_CODE_WRITE 0x02 -#define FAULT_CODE_FORCECOW 0x01 - -/*============================================================================= - * Undefined FIQs - *----------------------------------------------------------------------------- - */ -_unexp_fiq: ldr sp, .LCfiq - mov r12, #IOC_BASE - strb r12, [r12, #0x38] @ Disable FIQ register - teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_SVC26 - mov r0, r0 - stmfd sp!, {r0 - r3, ip, lr} - adr r0, Lfiqmsg - bl printk - ldmfd sp!, {r0 - r3, ip, lr} - teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_FIQ26 - mov r0, r0 - movs pc, lr - -Lfiqmsg: .ascii "*** Unexpected FIQ\n\0" - .align - -.LCfiq: .word __temp_fiq -.LCirq: .word __temp_irq - -/*============================================================================= - * Undefined instruction handler - *----------------------------------------------------------------------------- - * Handles floating point instructions - */ -vector_undefinstr: - tst lr, #MODE_SVC26 @ did we come from a non-user mode? - bne __und_svc @ yes - deal with it. -/* Otherwise, fall through for the user-space (common) case. */ - save_user_regs - zero_fp @ zero frame pointer - teqp pc, #PSR_I_BIT | MODE_SVC26 @ disable IRQs -.Lbug_undef: - ldr r4, .LC2 - ldr pc, [r4] @ Call FP module entry point -/* FIXME - should we trap for a null pointer here? */ - -/* The SVC mode case */ -__und_svc: save_svc_regs @ Non-user mode - mask_pc r0, lr - and r2, lr, #3 - sub r0, r0, #4 - mov r1, sp - bl do_undefinstr - restore_svc_regs - -/* We get here if the FP emulator doesnt handle the undef instr. - * If the insn WAS handled, the emulator jumps to ret_from_exception by itself/ - */ - .globl fpundefinstr -fpundefinstr: - mov r0, lr - mov r1, sp - teqp pc, #MODE_SVC26 - bl do_undefinstr - b ret_from_exception @ Normal FP exit - -#if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE - /* The FPE is always present */ - .equ fpe_not_present, 0 -#else -/* We get here if an undefined instruction happens and the floating - * point emulator is not present. If the offending instruction was - * a WFS, we just perform a normal return as if we had emulated the - * operation. This is a hack to allow some basic userland binaries - * to run so that the emulator module proper can be loaded. --philb - * FIXME - probably a broken useless hack... - */ -fpe_not_present: - adr r10, wfs_mask_data - ldmia r10, {r4, r5, r6, r7, r8} - ldr r10, [sp, #S_PC] @ Load PC - sub r10, r10, #4 - mask_pc r10, r10 - ldrt r10, [r10] @ get instruction - and r5, r10, r5 - teq r5, r4 @ Is it WFS? - beq ret_from_exception - and r5, r10, r8 - teq r5, r6 @ Is it LDF/STF on sp or fp? - teqne r5, r7 - bne fpundefinstr - tst r10, #0x00200000 @ Does it have WB - beq ret_from_exception - and r4, r10, #255 @ get offset - and r6, r10, #0x000f0000 - tst r10, #0x00800000 @ +/- - ldr r5, [sp, r6, lsr #14] @ Load reg - rsbeq r4, r4, #0 - add r5, r5, r4, lsl #2 - str r5, [sp, r6, lsr #14] @ Save reg - b ret_from_exception - -wfs_mask_data: .word 0x0e200110 @ WFS/RFS - .word 0x0fef0fff - .word 0x0d0d0100 @ LDF [sp]/STF [sp] - .word 0x0d0b0100 @ LDF [fp]/STF [fp] - .word 0x0f0f0f00 -#endif - -.LC2: .word fp_enter - -/*============================================================================= - * Prefetch abort handler - *----------------------------------------------------------------------------- - */ -#define DEBUG_UNDEF -/* remember: lr = USR pc */ -vector_prefetch: - sub lr, lr, #4 - tst lr, #MODE_SVC26 - bne __pabt_invalid - save_user_regs - teqp pc, #MODE_SVC26 @ Enable IRQs... - mask_pc r0, lr @ Address of abort - mov r1, sp @ Tasks registers - bl do_PrefetchAbort - teq r0, #0 @ If non-zero, we believe this abort.. - bne ret_from_exception -#ifdef DEBUG_UNDEF - adr r0, t - bl printk -#endif - ldr lr, [sp,#S_PC] @ FIXME program to test this on. I think its - b .Lbug_undef @ broken at the moment though!) - -__pabt_invalid: save_svc_regs - mov r0, sp @ Prefetch aborts are definitely *not* - mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant - and r2, lr, #3 @ recover from this problem. - b bad_mode - -#ifdef DEBUG_UNDEF -t: .ascii "*** undef ***\r\n\0" - .align -#endif - -/*============================================================================= - * Address exception handler - *----------------------------------------------------------------------------- - * These aren't too critical. - * (they're not supposed to happen). - * In order to debug the reason for address exceptions in non-user modes, - * we have to obtain all the registers so that we can see what's going on. - */ - -vector_addrexcptn: - sub lr, lr, #8 - tst lr, #3 - bne Laddrexcptn_not_user - save_user_regs - teq pc, #MODE_SVC26 - mask_pc r0, lr @ Point to instruction - mov r1, sp @ Point to registers - mov r2, #0x400 - mov lr, pc - bl do_excpt - b ret_from_exception - -Laddrexcptn_not_user: - save_svc_regs - and r2, lr, #3 - teq r2, #3 - bne Laddrexcptn_illegal_mode - teqp pc, #MODE_SVC26 - mask_pc r0, lr - mov r1, sp - orr r2, r2, #0x400 - bl do_excpt - ldmia sp, {r0 - lr} @ I cant remember the reason I changed this... - add sp, sp, #15*4 - movs pc, lr - -Laddrexcptn_illegal_mode: - mov r0, sp - str lr, [sp, #-4]! - orr r1, r2, #PSR_I_BIT | PSR_F_BIT - teqp r1, #0 @ change into mode (wont be user mode) - mov r0, r0 - mov r1, r8 @ Any register from r8 - r14 can be banked - mov r2, r9 - mov r3, r10 - mov r4, r11 - mov r5, r12 - mov r6, r13 - mov r7, r14 - teqp pc, #PSR_F_BIT | MODE_SVC26 @ back to svc - mov r0, r0 - stmfd sp!, {r1-r7} - ldmia r0, {r0-r7} - stmfd sp!, {r0-r7} - mov r0, sp - mov r1, #BAD_ADDREXCPTN - b bad_mode - -/*============================================================================= - * Interrupt (IRQ) handler - *----------------------------------------------------------------------------- - * Note: if the IRQ was taken whilst in user mode, then *no* kernel routine - * is running, so do not have to save svc lr. - * - * Entered in IRQ mode. - */ - -vector_IRQ: ldr sp, .LCirq @ Setup some temporary stack - sub lr, lr, #4 - str lr, [sp] @ push return address - - tst lr, #3 - bne __irq_non_usr - -__irq_usr: teqp pc, #PSR_I_BIT | MODE_SVC26 @ Enter SVC mode - mov r0, r0 - - ldr lr, .LCirq - ldr lr, [lr] @ Restore lr for jump back to USR - - save_user_regs - - handle_irq - - mov why, #0 - get_thread_info tsk - b ret_to_user - -@ Place the IRQ priority table here so that the handle_irq macros above -@ and below here can access it. - - irq_prio_table - -__irq_non_usr: teqp pc, #PSR_I_BIT | MODE_SVC26 @ Enter SVC mode - mov r0, r0 - - save_svc_regs_irq - - and r2, lr, #3 - teq r2, #3 - bne __irq_invalid @ IRQ not from SVC mode - - handle_irq - - restore_svc_regs - -__irq_invalid: mov r0, sp - mov r1, #BAD_IRQ - b bad_mode - -/*============================================================================= - * Data abort handler code - *----------------------------------------------------------------------------- - * - * This handles both exceptions from user and SVC modes, computes the address - * range of the problem, and does any correction that is required. It then - * calls the kernel data abort routine. - * - * This is where I wish that the ARM would tell you which address aborted. - */ - -vector_data: sub lr, lr, #8 @ Correct lr - tst lr, #3 - bne Ldata_not_user - save_user_regs - teqp pc, #MODE_SVC26 - mask_pc r0, lr - bl Ldata_do - b ret_from_exception - -Ldata_not_user: - save_svc_regs - and r2, lr, #3 - teq r2, #3 - bne Ldata_illegal_mode - tst lr, #PSR_I_BIT - teqeqp pc, #MODE_SVC26 - mask_pc r0, lr - bl Ldata_do - restore_svc_regs - -Ldata_illegal_mode: - mov r0, sp - mov r1, #BAD_DATA - b bad_mode - -Ldata_do: mov r3, sp - ldr r4, [r0] @ Get instruction - mov r2, #0 - tst r4, #1 << 20 @ Check to see if it is a write instruction - orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction - mov r1, r4, lsr #22 @ Now branch to the relevent processing routine - and r1, r1, #15 << 2 - add pc, pc, r1 - movs pc, lr - b Ldata_unknown - b Ldata_unknown - b Ldata_unknown - b Ldata_unknown - b Ldata_ldrstr_post @ ldr rd, [rn], #m - b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal - b Ldata_ldrstr_post @ ldr rd, [rn], rm - b Ldata_ldrstr_regindex @ ldr rd, [rn, rm] - b Ldata_ldmstm @ ldm*a rn, <rlist> - b Ldata_ldmstm @ ldm*b rn, <rlist> - b Ldata_unknown - b Ldata_unknown - b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m - b Ldata_ldcstc_pre @ ldc rd, [rn, #m] - b Ldata_unknown -Ldata_unknown: @ Part of jumptable - mov r0, r1 - mov r1, r4 - mov r2, r3 - b baddataabort - -Ldata_ldrstr_post: - mov r0, r4, lsr #14 @ Get Rn - and r0, r0, #15 << 2 @ Mask out reg. - teq r0, #15 << 2 - ldr r0, [r3, r0] @ Get register - biceq r0, r0, #PCMASK - mov r1, r0 -#ifdef FAULT_CODE_LDRSTRPOST - orr r2, r2, #FAULT_CODE_LDRSTRPOST -#endif - b do_DataAbort - -Ldata_ldrstr_numindex: - mov r0, r4, lsr #14 @ Get Rn - and r0, r0, #15 << 2 @ Mask out reg. - teq r0, #15 << 2 - ldr r0, [r3, r0] @ Get register - mov r1, r4, lsl #20 - biceq r0, r0, #PCMASK - tst r4, #1 << 23 - addne r0, r0, r1, lsr #20 - subeq r0, r0, r1, lsr #20 - mov r1, r0 -#ifdef FAULT_CODE_LDRSTRPRE - orr r2, r2, #FAULT_CODE_LDRSTRPRE -#endif - b do_DataAbort - -Ldata_ldrstr_regindex: - mov r0, r4, lsr #14 @ Get Rn - and r0, r0, #15 << 2 @ Mask out reg. - teq r0, #15 << 2 - ldr r0, [r3, r0] @ Get register - and r7, r4, #15 - biceq r0, r0, #PCMASK - teq r7, #15 @ Check for PC - ldr r7, [r3, r7, lsl #2] @ Get Rm - and r8, r4, #0x60 @ Get shift types - biceq r7, r7, #PCMASK - mov r9, r4, lsr #7 @ Get shift amount - and r9, r9, #31 - teq r8, #0 - moveq r7, r7, lsl r9 - teq r8, #0x20 @ LSR shift - moveq r7, r7, lsr r9 - teq r8, #0x40 @ ASR shift - moveq r7, r7, asr r9 - teq r8, #0x60 @ ROR shift - moveq r7, r7, ror r9 - tst r4, #1 << 23 - addne r0, r0, r7 - subeq r0, r0, r7 @ Apply correction - mov r1, r0 -#ifdef FAULT_CODE_LDRSTRREG - orr r2, r2, #FAULT_CODE_LDRSTRREG -#endif - b do_DataAbort - -Ldata_ldmstm: - mov r7, #0x11 - orr r7, r7, r7, lsl #8 - and r0, r4, r7 - and r1, r4, r7, lsl #1 - add r0, r0, r1, lsr #1 - and r1, r4, r7, lsl #2 - add r0, r0, r1, lsr #2 - and r1, r4, r7, lsl #3 - add r0, r0, r1, lsr #3 - add r0, r0, r0, lsr #8 - add r0, r0, r0, lsr #4 - and r7, r0, #15 @ r7 = no. of registers to transfer. - mov r5, r4, lsr #14 @ Get Rn - and r5, r5, #15 << 2 - ldr r0, [r3, r5] @ Get reg - eor r6, r4, r4, lsl #2 - tst r6, #1 << 23 @ Check inc/dec ^ writeback - rsbeq r7, r7, #0 - add r7, r0, r7, lsl #2 @ Do correction (signed) - subne r1, r7, #1 - subeq r1, r0, #1 - moveq r0, r7 - tst r4, #1 << 21 @ Check writeback - strne r7, [r3, r5] - eor r6, r4, r4, lsl #1 - tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec - addeq r0, r0, #4 - addeq r1, r1, #4 - teq r5, #15*4 @ CHECK FOR PC - biceq r1, r1, #PCMASK - biceq r0, r0, #PCMASK -#ifdef FAULT_CODE_LDMSTM - orr r2, r2, #FAULT_CODE_LDMSTM -#endif - b do_DataAbort - -Ldata_ldcstc_pre: - mov r0, r4, lsr #14 @ Get Rn - and r0, r0, #15 << 2 @ Mask out reg. - teq r0, #15 << 2 - ldr r0, [r3, r0] @ Get register - mov r1, r4, lsl #24 @ Get offset - biceq r0, r0, #PCMASK - tst r4, #1 << 23 - addne r0, r0, r1, lsr #24 - subeq r0, r0, r1, lsr #24 - mov r1, r0 -#ifdef FAULT_CODE_LDCSTC - orr r2, r2, #FAULT_CODE_LDCSTC -#endif - b do_DataAbort - - -/* - * This is the return code to user mode for abort handlers - */ -ENTRY(ret_from_exception) - get_thread_info tsk - mov why, #0 - b ret_to_user - - .data -ENTRY(fp_enter) - .word fpe_not_present - .text -/* - * Register switch for older 26-bit only ARMs - */ -ENTRY(__switch_to) - add r0, r0, #TI_CPU_SAVE - stmia r0, {r4 - sl, fp, sp, lr} - add r1, r1, #TI_CPU_SAVE - ldmia r1, {r4 - sl, fp, sp, pc}^ - -/* - *============================================================================= - * Low-level interface code - *----------------------------------------------------------------------------- - * Trap initialisation - *----------------------------------------------------------------------------- - * - * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20 - * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes - * some excess cycles). - * - * What we need to put into 0-0x1c are branches to branch to the kernel. - */ - - .section ".init.text",#alloc,#execinstr - -.Ljump_addresses: - swi SYS_ERROR0 - .word vector_undefinstr - 12 - .word vector_swi - 16 - .word vector_prefetch - 20 - .word vector_data - 24 - .word vector_addrexcptn - 28 - .word vector_IRQ - 32 - .word _unexp_fiq - 36 - b . + 8 -/* - * initialise the trap system - */ -ENTRY(__trap_init) - stmfd sp!, {r4 - r7, lr} - adr r1, .Ljump_addresses - ldmia r1, {r1 - r7, ip, lr} - orr r2, lr, r2, lsr #2 - orr r3, lr, r3, lsr #2 - orr r4, lr, r4, lsr #2 - orr r5, lr, r5, lsr #2 - orr r6, lr, r6, lsr #2 - orr r7, lr, r7, lsr #2 - orr ip, lr, ip, lsr #2 - mov r0, #0 - stmia r0, {r1 - r7, ip} - ldmfd sp!, {r4 - r7, pc}^ - - .bss -__temp_irq: .space 4 @ saved lr_irq -__temp_fiq: .space 128 |