arm+linux+entry.s,linux kernel 之底层中断机制entry_armv.S

entry-armv.s中

当ARM处理器发生异常(中断是一种异常)时,会跳转到异常向量表(起始地址为0xFFFF_0000或

0x0000_0000)。

如3.2节中所述,在中断机制的初始化过程中,把在arch/arm/kernel/entry-armv.S中的异常向量表及其处理程序的stub重定

位到了0xFFFF_0000处,这样才使得ARM处理器能够正常处理异常,而且事实上执行的就是entry-armv.S中的异常处理程序

.equ stubs_offset, __vectors_start + 0x200 - __stubs_start

异常向量表:

@下面这些才是最初的入口点,__vector_start和__vector_end之间的代码会被移动到CONFIG_VECTORS_BASE开始的地方,例如0xc000000

.globl __vectors_start

__vectors_start:

swi SYS_ERROR0                                      @Reset

b vector_und + stubs_offset

ldr pc, .LCvswi + stubs_offset                      @swi instructionSWI指令用于产生软件中断,从而实现从用户模式到管理模式的变换

b vector_pabt + stubs_offset

b vector_dabt + stubs_offset

b vector_addrexcptn + stubs_offset

bvector_irq+ stubs_offset              @irq中断入口

b vector_fiq + stubs_offset

.globl __vectors_end

__vectors_end:

///

__stubs_start和__stubs_end之间,实际上就是异常处理程序的入口

.globl __stubs_start

__stubs_start:

/*

* Interrupt dispatcher

*/

vector_stub irq, IRQ_MODE, 4                       @此处便是vector_irq的声明调用

.long __irq_usr@  0  (USR_26 / USR_32)    用户模式

.long __irq_invalid   @  1  (FIQ_26 / FIQ_32)

.long __irq_invalid   @  2  (IRQ_26 / IRQ_32)

.long __irq_svc   @  3  (SVC_26 / SVC_32)  系统模式

.long __irq_invalid   @  4

.long __irq_invalid   @  5

.long __irq_invalid   @  6

.long __irq_invalid   @  7

.long __irq_invalid   @  8

.long __irq_invalid   @  9

.long __irq_invalid   @  a

.long __irq_invalid   @  b

.long __irq_invalid   @  c

.long __irq_invalid   @  d

.long __irq_invalid   @  e

.long __irq_invalid   @  f

//

/*

* Vector stubs.

*

* This code is copied to 0xffff0200 so we can use branches in the

* vectors, rather than ldr's.  Note that this code must not

* exceed 0x300 bytes.

*

* Common stub entry macro:

*   Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC

*

* SP points to a minimal amount of processor-private memory, the address

* of which is copied into r0 for the mode specific abort handler.

*/

.macro vector_stub, name, mode, correction=0        @看看vector_stub irq, IRQ_MODE, 4 是如何变成vector_irq的。

.align 5

vector_\name:

.if \correction

sub lr, lr, #\correction  @修正返回地址,如果必要的话

.endif

@

@ Save r0, lr_(parent PC) and spsr_@ (parent CPSR)

@

stmia sp, {r0, lr}  @ save r0, lr

mrs lr, spsr

str lr, [sp, #8]  @ save spsr

@

@ Prepare for SVC32 mode.  IRQs remain disabled.

@

mrs r0, cpsr

eor r0, r0, #(\mode ^ SVC_MODE)

msr spsr_cxsf, r0

@

@ the branch table must immediately follow this code

@

and lr, lr, #0x0f

mov r0, sp

ldr lr, [pc, lr, lsl #2]

movs pc, lr   @ branch to handler in SVC modeENDPROC(vector_\name)

.endm

.align 5

__irq_svc:

svc_entry

#ifdef CONFIG_TRACE_IRQFLAGS

bl trace_hardirqs_off

#endif

#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

str r8, [tsk, #TI_PREEMPT]  @ restore preempt count

ldr r0, [tsk, #TI_FLAGS]  @ get flags

teq r8, #0    @ if preempt count != 0

movne r0, #0    @ force flags to 0

tst r0, #_TIF_NEED_RESCHED

blne svc_preempt

#endif

ldr r0, [sp, #S_PSR]  @ irqs are already disabled

msr spsr_cxsf, r0

#ifdef CONFIG_TRACE_IRQFLAGS

tst r0, #PSR_I_BIT

bleq trace_hardirqs_on

#endif

ldmia sp, {r0 - pc}^   @ load r0 - pc, cpsr

ENDPROC(__irq_svc)

///

@usr模式中断入口

.align 5

__irq_usr: usr_entry

kuser_cmpxchg_check

#ifdef CONFIG_TRACE_IRQFLAGS

bl trace_hardirqs_off

#endif

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

#ifdef CONFIG_TRACE_IRQFLAGS

bl trace_hardirqs_on

#endif

mov why, #0

b ret_to_user

ENDPROC(__irq_usr)

回看__irq_usr和__irq_svc标号处的代码,在完成了irq_handler中断处理函数后,要完成从中断异常处理程序返回到中断点的工作。如果中断产生于用户空间,则调用ret_to_user来恢复中断现场并返回用户空间继续运行:

//

entry_common.s中

ENTRY(ret_to_user)

ret_slow_syscall:

disable_irq    @ disable interrupts

ldr r1, [tsk, #TI_FLAGS]

tst r1, #_TIF_WORK_MASK

bne work_pending

no_work_pending:

/* perform architecture specific actions before user return */

arch_ret_to_user r1, lr

@ slow_restore_user_regs

ldr r1, [sp, #S_PSR]  @ get calling cpsr

ldr lr, [sp, #S_PC]!  @ get pc

msr spsr_cxsf, r1   @ save in spsr_svc

ldmdb sp, {r0 - lr}^   @ get calling r0 - lr

mov r0, r0

add sp, sp, #S_FRAME_SIZE - S_PC

movs pc, lr    @ return & move spsr_svc into cpsr

ENDPROC(ret_to_user)

/

.macroirq_handler get_irqnr_preamble r5, lr

1: get_irqnr_and_base r0, r6, r5, lr

宏查询ISPR(IRQ待定中断服务寄存器,当有需要处理的中断时,

这个寄存器的相应位会置位,任意时刻,最多一个位会置位)计算出的中断号放在irqnr指定的寄存器中

movne r1, sp                             @如果中断号不等于0,将r1=sp,即pt_regs结构体首地址

@

@routine called with r0 = irq number, r1 = struct pt_regs * @

adrne lr, 1b      @返回到1处,asm_do_IRQ返回后将再次查询发生的中断????@如果r0(中断号)不等于0, lr(返回地址)等于标号1处,即get_irqnr_and_base r0,r6,r5,lr的那行,即循环处理所有的中断

bne asm_do_IRQ@kernel的中断处理函数//中断底层汇编可知asm_do_IRQ函数式中断的C语言总入口函数

///

traps.c中的early_trap_init()函数中

unsigned long vectors = CONFIG_VECTORS_BASE;

/*

* Copy the vectors, stubs and kuser helpers (in entry-armv.S)

* into the vector page, mapped at 0xffff0000, and ensure these

* are visible to the instruction stream.  */

memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);

memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start

//entry_armv.s中有.equ stubs_offset, __vectors_start + 0x200 - __stubs_start

memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

实际copy动作一目了然,就是两个memcpy(第三个实际上是拷贝一些别的东西,原理是一样的,这里不提了). copy的目的地是vectors,这个值是CONFIG_VECTORS_BASE,在2.6.32.7内核中CONFIG_VECTORS_BASE是在各个平台的配置文件中设定的,如:arch/arm/configs/S3C2410_defconfig中CONFIG_VECTORS_BASE=0xffff0000

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值