📄 entry-armv.s
字号:
/* * linux/arch/arm/kernel/entry-armv.S * * Copyright (C) 1996,1997,1998 Russell King. * ARM700 fix by Matthew Godbolt (linux-user@willothewisp.demon.co.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Low-level vector interface routines * * Note: there is a StrongARM bug in the STMIA rn, {regs}^ instruction that causes * it to save wrong values... Be aware! */#include <linux/config.h>#include <asm/memory.h>#include <asm/glue.h>#include <asm/vfpmacros.h>#include <asm/hardware.h> /* should be moved into entry-macro.S */#include <asm/arch/irqs.h> /* should be moved into entry-macro.S */#include <asm/arch/entry-macro.S>#include "entry-header.S"/* * Interrupt handling. Preserves r7, r8, r9 */ .macro irq_handler1: get_irqnr_and_base r0, r6, r5, lr movne r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ adrne lr, 1b bne asm_do_IRQ#ifdef CONFIG_SMP /* * XXX * * this macro assumes that irqstat (r6) and base (r5) are * preserved from get_irqnr_and_base above */ test_for_ipi r0, r6, r5, lr movne r0, sp adrne lr, 1b bne do_IPI#ifdef CONFIG_LOCAL_TIMERS test_for_ltirq r0, r6, r5, lr movne r0, sp adrne lr, 1b bne do_local_timer#endif#endif .endm/* * Invalid mode handlers */ .macro inv_entry, reason sub sp, sp, #S_FRAME_SIZE stmib sp, {r1 - lr} mov r1, #\reason .endm__pabt_invalid: inv_entry BAD_PREFETCH b common_invalid__dabt_invalid: inv_entry BAD_DATA b common_invalid__irq_invalid: inv_entry BAD_IRQ b common_invalid__und_invalid: inv_entry BAD_UNDEFINSTR @ @ XXX fall through to common_invalid @@@ common_invalid - generic code for failed exception (re-entrant version of handlers)@common_invalid: zero_fp ldmia r0, {r4 - r6} add r0, sp, #S_PC @ here for interlock avoidance mov r7, #-1 @ "" "" "" "" str r4, [sp] @ save preserved r0 stmia r0, {r5 - r7} @ lr_<exception>, @ cpsr_<exception>, "old_r0" mov r0, sp and r2, r6, #0x1f b bad_mode/* * SVC mode handlers */ .macro svc_entry sub sp, sp, #S_FRAME_SIZE stmib sp, {r1 - r12} ldmia r0, {r1 - r3} add r5, sp, #S_SP @ here for interlock avoidance mov r4, #-1 @ "" "" "" "" add r0, sp, #S_FRAME_SIZE @ "" "" "" "" str r1, [sp] @ save the "real" r0 copied @ from the exception stack mov r1, lr @ @ We are now ready to fill in the remaining blanks on the stack: @ @ r0 - sp_svc @ r1 - lr_svc @ r2 - lr_<exception>, already fixed up for correct return/restart @ r3 - spsr_<exception> @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ stmia r5, {r0 - r4} .endm .align 5__dabt_svc: svc_entry @ @ get ready to re-enable interrupts if appropriate @ mrs r9, cpsr tst r3, #PSR_I_BIT biceq r9, r9, #PSR_I_BIT @ @ Call the processor-specific abort handler: @ @ r2 - aborted context pc @ r3 - aborted context cpsr @ @ The abort handler must return the aborted address in r0, and @ the fault status register in r1. r9 must be preserved. @#ifdef MULTI_ABORT ldr r4, .LCprocfns mov lr, pc ldr pc, [r4]#else bl CPU_ABORT_HANDLER#endif @ @ set desired IRQ state, then call main handler @ msr cpsr_c, r9 mov r2, sp bl do_DataAbort @ @ IRQs off again before pulling preserved data off the stack @ disable_irq @ @ restore SPSR and restart the instruction @ ldr r0, [sp, #S_PSR] msr spsr_cxsf, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr .align 5__irq_svc: svc_entry#ifdef CONFIG_PREEMPT get_thread_info tsk ldr r8, [tsk, #TI_PREEMPT] @ get preempt count add r7, r8, #1 @ increment it str r7, [tsk, #TI_PREEMPT]#endif irq_handler#ifdef CONFIG_PREEMPT ldr r0, [tsk, #TI_FLAGS] @ get flags tst r0, #_TIF_NEED_RESCHED blne svc_preemptpreempt_return: ldr r0, [tsk, #TI_PREEMPT] @ read preempt value str r8, [tsk, #TI_PREEMPT] @ restore preempt count teq r0, r7 strne r0, [r0, -r0] @ bug()#endif ldr r0, [sp, #S_PSR] @ irqs are already disabled msr spsr_cxsf, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr .ltorg#ifdef CONFIG_PREEMPTsvc_preempt: teq r8, #0 @ was preempt count = 0 ldreq r6, .LCirq_stat movne pc, lr @ no ldr r0, [r6, #4] @ local_irq_count ldr r1, [r6, #8] @ local_bh_count adds r0, r0, r1 movne pc, lr mov r7, #0 @ preempt_schedule_irq str r7, [tsk, #TI_PREEMPT] @ expects preempt_count == 01: bl preempt_schedule_irq @ irq en/disable is done inside ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS tst r0, #_TIF_NEED_RESCHED beq preempt_return @ go again b 1b#endif .align 5__und_svc: svc_entry @ @ call emulation code, which returns using r9 if it has emulated @ the instruction, or the more conventional lr if we are to treat @ this as a real undefined instruction @ @ r0 - instruction @ ldr r0, [r2, #-4] adr r9, 1f bl call_fpe mov r0, sp @ struct pt_regs *regs bl do_undefinstr @ @ IRQs off again before pulling preserved data off the stack @1: disable_irq @ @ restore SPSR and restart the instruction @ ldr lr, [sp, #S_PSR] @ Get SVC cpsr msr spsr_cxsf, lr ldmia sp, {r0 - pc}^ @ Restore SVC registers .align 5__pabt_svc: svc_entry @ @ re-enable interrupts if appropriate @ mrs r9, cpsr tst r3, #PSR_I_BIT biceq r9, r9, #PSR_I_BIT msr cpsr_c, r9 @ @ set args, then call main handler @ @ r0 - address of faulting instruction @ r1 - pointer to registers on stack @ mov r0, r2 @ address (pc) mov r1, sp @ regs bl do_PrefetchAbort @ call abort handler @ @ IRQs off again before pulling preserved data off the stack @ disable_irq @ @ restore SPSR and restart the instruction @ ldr r0, [sp, #S_PSR] msr spsr_cxsf, r0 ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr .align 5.LCcralign: .word cr_alignment#ifdef MULTI_ABORT.LCprocfns: .word processor#endif.LCfp: .word fp_enter#ifdef CONFIG_PREEMPT.LCirq_stat: .word irq_stat#endif/* * User mode handlers */ .macro usr_entry sub sp, sp, #S_FRAME_SIZE stmib sp, {r1 - r12} ldmia r0, {r1 - r3} add r0, sp, #S_PC @ here for interlock avoidance mov r4, #-1 @ "" "" "" "" str r1, [sp] @ save the "real" r0 copied @ from the exception stack#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG) @ make sure our user space atomic helper is aborted cmp r2, #TASK_SIZE bichs r3, r3, #PSR_Z_BIT#endif @ @ We are now ready to fill in the remaining blanks on the stack: @ @ r2 - lr_<exception>, already fixed up for correct return/restart @ r3 - spsr_<exception> @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ @ Also, separately save sp_usr and lr_usr @ stmia r0, {r2 - r4} stmdb r0, {sp, lr}^ @ @ Enable the alignment trap while in kernel mode @ alignment_trap r0 @ @ Clear FP to mark the first stack frame @ zero_fp .endm .align 5__dabt_usr: usr_entry @ @ Call the processor-specific abort handler: @ @ r2 - aborted context pc @ r3 - aborted context cpsr @ @ The abort handler must return the aborted address in r0, and @ the fault status register in r1. @#ifdef MULTI_ABORT ldr r4, .LCprocfns mov lr, pc ldr pc, [r4]#else bl CPU_ABORT_HANDLER#endif @ @ IRQs on, then call the main handler @ enable_irq mov r2, sp adr lr, ret_from_exception b do_DataAbort .align 5__irq_usr: usr_entry get_thread_info tsk#ifdef CONFIG_PREEMPT ldr r8, [tsk, #TI_PREEMPT] @ get preempt count add r7, r8, #1 @ increment it str r7, [tsk, #TI_PREEMPT]#endif irq_handler#ifdef CONFIG_PREEMPT ldr r0, [tsk, #TI_PREEMPT] str r8, [tsk, #TI_PREEMPT] teq r0, r7 strne r0, [r0, -r0]#endif mov why, #0 b ret_to_user .ltorg .align 5__und_usr: usr_entry tst r3, #PSR_T_BIT @ Thumb mode? bne fpundefinstr @ ignore FP sub r4, r2, #4 @ @ fall through to the emulation code, which returns using r9 if @ it has emulated the instruction, or the more conventional lr @ if we are to treat this as a real undefined instruction @ @ r0 - instruction @1: ldrt r0, [r4] adr r9, ret_from_exception adr lr, fpundefinstr @ @ fallthrough to call_fpe @/* * The out of line fixup for the ldrt above. */ .section .fixup, "ax"2: mov pc, r9 .previous .section __ex_table,"a" .long 1b, 2b .previous/* * Check whether the instruction is a co-processor instruction. * If yes, we need to call the relevant co-processor handler. * * Note that we don't do a full check here for the co-processor * instructions; all instructions with bit 27 set are well * defined. The only instructions that should fault are the * co-processor instructions. However, we have to watch out * for the ARM6/ARM7 SWI bug. * * Emulators may wish to make use of the following registers: * r0 = instruction opcode. * r2 = PC+4 * r10 = this threads thread_info structure. */call_fpe: tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) and r8, r0, #0x0f000000 @ mask out op-code bits teqne r8, #0x0f000000 @ SWI (ARM6/7 bug)?#endif moveq pc, lr get_thread_info r10 @ get current thread and r8, r0, #0x00000f00 @ mask out CP number mov r7, #1 add r6, r10, #TI_USED_CP strb r7, [r6, r8, lsr #8] @ set appropriate used_cp[]#ifdef CONFIG_IWMMXT @ Test if we need to give access to iWMMXt coprocessors ldr r5, [r10, #TI_FLAGS] rsbs r7, r8, #(1 << 8) @ CP 0 or 1 only movcss r7, r5, lsr #(TIF_USING_IWMMXT + 1) bcs iwmmxt_task_enable#endif enable_irq add pc, pc, r8, lsr #6 mov r0, r0 mov pc, lr @ CP#0 b do_fpe @ CP#1 (FPE) b do_fpe @ CP#2 (FPE) mov pc, lr @ CP#3 mov pc, lr @ CP#4 mov pc, lr @ CP#5 mov pc, lr @ CP#6 mov pc, lr @ CP#7 mov pc, lr @ CP#8 mov pc, lr @ CP#9#ifdef CONFIG_VFP b do_vfp @ CP#10 (VFP) b do_vfp @ CP#11 (VFP)#else mov pc, lr @ CP#10 (VFP) mov pc, lr @ CP#11 (VFP)#endif mov pc, lr @ CP#12 mov pc, lr @ CP#13 mov pc, lr @ CP#14 (Debug) mov pc, lr @ CP#15 (Control)do_fpe: ldr r4, .LCfp add r10, r10, #TI_FPSTATE @ r10 = workspace ldr pc, [r4] @ Call FP module USR entry point/* * The FP module is called with these registers set: * r0 = instruction * r2 = PC+4 * r9 = normal "successful" return address * r10 = FP workspace * lr = unrecognised FP instruction return address */ .dataENTRY(fp_enter) .word fpundefinstr .textfpundefinstr: mov r0, sp adr lr, ret_from_exception b do_undefinstr
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -