📄 entry-armo.s
字号:
/* * linux/arch/arm/lib/traps.S * * Copyright (C) 1995, 1996 Russell King. * * Low-level vector interface routines * * 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. * * Ok, so this file may be a mess, but its as efficient as possible while * adhering to the above criteria. */#include <asm/assembler.h>#include <asm/errno.h>#include <asm/hardware.h>#if 0/* * Uncomment these if you wish to get more debugging into about data aborts. */#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_USER 0x01 .text/* Offsets into task structure * --------------------------- */#define STATE 0#define COUNTER 4#define PRIORITY 8#define SIGNAL 12#define BLOCKED 16#define FLAGS 20#define ERRNO 24#define PF_TRACESYS 0x20/* Bad Abort numbers * ----------------- */#define BAD_PREFETCH 0#define BAD_DATA 1#define BAD_ADDREXCPTN 2#define BAD_IRQ 3/* OS version number used in SWIs * RISC OS is 0 * RISC iX is 8 */#define OS_NUMBER 9/* Stack format (ensured by USER_* and SVC_*) */#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#include "../lib/constants.h"#define USER_SAVE_ALL \ str r0, [sp, #-4]! ;\ str lr, [sp, #-4]! ;\ sub sp, sp, #15*4 ;\ stmia sp, {r0 - lr}^ ;\ mov r0, r0 ;\ mov fp, #0#define SVC_SAVE_ALL \ 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] ;\ mov fp, #0#define SVC_IRQ_SAVE_ALL \ str sp, [sp, #-16]! ;\ str lr, [sp, #4] ;\ ldr lr, [pc, #LC4 - . - 8] ;\ ldr lr, [lr] ;\ str lr, [sp, #8] ;\ stmfd sp!, {r0 - r12} ;\ mov r0, #-1 ;\ str r0, [sp, #S_OLD_R0] ;\ mov fp, #0#define USER_RESTORE_ALL \ ldmia sp, {r0 - lr}^ ;\ mov r0, r0 ;\ add sp, sp, #15*4 ;\ ldr lr, [sp], #8 ;\ movs pc, lr#define SVC_RESTORE_ALL \ ldmfd sp, {r0 - pc}^ .global _ret_from_sys_call/* * Interrupt table (incorporates priority). First set is indexed using * IRQSTATB. */Lirq_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,10Lirq_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/************************************************************************** * Interrupt (IRQ) handler (r13 points to irq temp save area) * Note: if in user mode, then *no* kernel routine is running, so dont have * to save svc lr */LC4: .word Lirq_tempLC5: .word _irqjumpLvector_IRQ: ldr r13, [pc, #LC4 - . - 8] @ Ill leave this one in just in case... sub lr, lr, #4 str lr, [r13] tst lr, #3 bne LIRQ_not_user teqp pc, #0x08000003 mov r0, r0 ldr lr, [pc, #LC4 - . - 8] ldr lr, [lr] USER_SAVE_ALL mov r4, #IOC_BASE @ point at IOC ldrb r1, [r4, #0x24] @ get high priority first adr r2, Lirq_prio_h teq r1, #0 ldreqb r1, [r4, #0x14] @ get low priority adreq r2, Lirq_prio_l teq r1, #0 beq _ret_from_sys_call ldrb r0, [r2, r1] @ Get IRQ number ldr r2, [pc, #LC5 - . - 8] mov r1, sp mov lr, pc /* * routine gets called with r0 = interrupt number, r1 = struct pt_regs * */ ldr pc, [r2, r0, lsl#2] mov r2, #0 teq r0, #0 @ Check to see if it is a fast IRQ beq _ret_from_sys_call USER_RESTORE_ALLLC65: .word _intr_count @ -8 .word _bh_mask @ -4 .word _bh_active @ -0Lirq_illegal_mode: mov r0, sp mov r1, #BAD_IRQ b _bad_modeLIRQ_not_user: teqp pc, #0x08000003 mov r0, r0 SVC_IRQ_SAVE_ALL and r2, lr, #3 teq r2, #3 bne Lirq_illegal_modeLsrepeat: mov r4, #IOC_BASE @ point at IOC ldrb r1, [r4, #0x24] @ get high priority first adr r2, Lirq_prio_h teq r1, #0 ldreqb r1, [r4, #0x14] @ get low priority adreq r2, Lirq_prio_l teq r1, #0 beq Lno_irq2 ldrb r0, [r2, r1] @ Get IRQ number ldr r2, [pc, #LC5 - . - 8] mov r1, sp mov lr, pc /* * routine gets called with r0 = interrupt number, r1 = struct pt_regs * */ ldr pc, [r2, r0, lsl#2] mov r2, #1 teq r0, #0 @ Check to see if it is a fast IRQ bne Lsrepeat ldr r0, [pc, #LC65 - . - 8] ldr r1, [r0] teq r1, #0 bne Lsrepeat mov r4, r0 mov r5, r1 ldr r6, [pc, #LC65 - . - 4] ldr r7, [pc, #LC65 - . - 0]Lrecheck_bh2: ldr r0, [r6] ldr r1, [r7] tst r0, r1 beq Lsrepeat add r0, r5, #1 str r0, [r4] mov r8, pc teqp pc, #0x00000003 bl _do_bottom_half teqp r8, #0 str r5, [r4] b Lrecheck_bh2Lno_irq2: SVC_RESTORE_ALL/************************************************************************** * 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). */Lswi_reset: swi SYS_ERROR0 ldr pc, . + 4 .long _unexp_fiqLfiqmsg: .ascii "*** Unexpeced FIQ\n\0" .align_unexp_fiq: mov r12, #IOC_BASE strb r12, [r12, #0x38] @ Disable FIQ register teqp pc, #0x0c000003 mov r0, r0 stmfd sp!, {r0 - r3, ip, lr} adr r0, Lfiqmsg bl _printk ldmfd sp!, {r0 - r3, ip, lr} teqp pc, #0x0c000001 mov r0, r0 movs pc, lrLvectors: .long Lvector_undefinstr - Lvectors - 12 .long Lvector_swi - Lvectors - 16 .long Lvector_prefetch - Lvectors - 20 .long Lvector_data - Lvectors - 24 .long Lvector_addrexcptn - Lvectors - 28 .long Lvector_IRQ - Lvectors - 32 .long 0xea000000 .global _trap_init_trap_init: stmfd sp !,{r4 - r9,lr} @ Save link register teqp pc, #0x0c000003 mov r0, #IOC_BASE str r0, [r0, #0x18] str r0, [r0, #0x28] str r0, [r0, #0x38] mov r0, #0 @ Lowest location adr r1, Lvectors ldmia r1, {r2, r3, r4, r5, r6, r7, ip} add r1, ip, r1, asr #2 add r2, r1, r2, asr #2 add r3, r1, r3, asr #2 add r4, r1, r4, asr #2 add r5, r1, r5, asr #2 add r6, r1, r6, asr #2 add r7, r1, r7, asr #2 adr r1, Lswi_reset ldmia r1, {r1, r8, r9} stmia r0!, {r1 - r9} @ Save all into page 0 ram ldmfd sp!, {r4 - r9, pc}^/************************************************************************** * Prefetch abort handler */#ifdef DEBUG_UNDEFt: .ascii "*** undef ***\r\n\0" .align#endifLvector_prefetch: sub lr, lr, #4 tst lr, #3 bne Lprefetch_not_user USER_SAVE_ALL teqp pc, #0x00000003 @ NOT a problem - doesnt change mode bic r0, lr, #0xfc000003 @ Address of abort mov r1, #FAULT_CODE_PREFETCH|FAULT_CODE_USER @ Error code mov r2, sp @ Tasks registers bl _do_PrefetchAbort teq r0, #0 @ If non-zero, we believe this abort.. bne _ret_from_sys_call#ifdef DEBUG_UNDEF adr r0,t @ Otherwise it was probably an undefined bl _printk @ instruction. (I do wish that I had a#endif ldr lr, [sp,#S_PC] @ program to test this on. I think its b _undefinstr @ broken at the moment though!)Lprefetch_not_user: SVC_SAVE_ALL @ Prefetch aborts are definitely *not* mov r0, sp @ allowed in non-user modes. We cant mov r1, #BAD_PREFETCH @ recover from this problem. and r2, lr, #3 b _bad_mode @ Doesnt return/************************************************************************** * Undefined instruction handler */LC8: .word _last_task_used_math .word _currentLC9: .word _fp_enter .word _fp_save .word _fp_restoreLundef_not_user: SVC_SAVE_ALL @ Non-user mode bic r0, lr, #0xfc000003 and r2, lr, #3 sub r0, r0, #4 mov r1, sp bl _do_undefinstr SVC_RESTORE_ALL .global _fpreturn .global _fpundefinstrLvector_undefinstr: tst lr,#3 bne Lundef_not_user USER_SAVE_ALL @ USER mode undefined instructions teqp pc, #0x08000003 @ MUST disable interrupts._undefinstr:@@ before calling FP, must call math_state_restore!!!@ something along the lines of:@ adr r3, LC8 ldmia r3, {r1, r2, r3} ldr r1, [r1] @ last task used math ldr r2, [r2] @ current task teq r1, r2 stmnefd sp!, {ip, lr} blne _math_state_restore ldmnefd sp!, {ip, lr} ldr r3, [pc, #LC9 - . - 8] ldr pc, [r3] @ Call FP module (when loaded)_fpundefinstr: mov r1,sp @ Called by FP module on undefined instr teqp pc, #3 @ Enable interrupts mov r2,#0 mov lr, pc@ Change!! add lr, lr, #_ret_from_sys_call - . - 4 b _do_undefinstr/************************************************************************** * 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. */Laddrexcptn_illegal_mode:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -