微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux中断机制分析

ARM Linux中断机制分析

时间:11-09 来源:互联网 点击:

__stubs_start:

/*

* Interrupt dispatcher

*/

vector stub irq,IRQ_MODE,4 //vector_stub是一个宏,展开后是一块代码,后面紧跟着跳转表

.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

……

……

……

……

.globl__stubs_end

__stubs_end:

.equ stubs_offset, __vectors_start + 0x200 - __stubs_start

vector_stub irq, IRQ_MODE, 4展开后如下:

// -------------------------------- begin展开

.align5//将异常入口强制进行2^5字节对齐,即一个cache line大小对齐,出于性能考虑

vector_irq:

sublr, lr, 4//需要调整pc返回值,对于irq异常,将lr减去4,对于其他异常需要作出不同调整

@ Save r0, lr_ (parent PC) and spsr_

@ (parent CPSR)

@

stmiasp, {r0, lr}@ save r0, lr

mrslr, spsr

strlr, [sp, #8]@ save spsr

@ Prepare for SVC32 mode.IRQs remain disabled.

@

mrsr0, cpsr

eorr0, r0, IRQ_MODE ^ SVC_MODE)

msrspsr_cxsf, r0

@ the branch table must immediately follow this code

@

andlr, lr, #0x0f

movr0, sp

ldrlr, [pc, lr, lsl #2]

movspc, lr@ branch to handler in SVC mode

// -------------------------------- end展开


异常向量表的拷贝过程用图表示比较清晰,如下图所示:

图一 向量表搬移及offset偏移量计算示图

图一说明:上面两条有方向的横线,横线方向代表地址生长方向,下面那个是Code/Load视图,是搬移前的代码在生成的二进制内核中的组织情况,上面的Exec view是代码在内存中开始执行后的分配情况。

2.linux对ARM异常、中断的处理流程

2.1当IRQ发生时,硬件完成的操作

R14_irq= address of next instruction to be executed + 4/*将寄存器lr_mode设置成返回地址*/

SPSR_irq = CPSR /*保存处理器当前状态、中断屏蔽位以及各条件标志位*/

CPSR[4:0] = 0b10010 /*设置当前程序状态寄存器CPSR中相应的位进入IRQ模式*/

CPSR[5] = 0 /*在ARM状态执行*/

/*CPSR[6] 不变*/

CPSR[7] = 1 /*禁止正常中断*/

If high vectors configured then

PC=0xFFFF0018 /*将程序计数器(PC)值设置成该异常中断的中断向量地址,从

*而跳转到相应的异常中断处理程序处执行,对于ARMv7向量表普遍是0xFFFF0018

*/

else

PC=0x00000018

2.2 指令流跳转过程

以上CPU操作完成后,PC跳转到0xFFFF0018,该地址就是指令W(b) vector_irq + stubs_offset所在地址。然后跳转到vector_stub irq,IRQ_MODE, 4,去执行相应的异常、中断处理函数。

接下来具体看代码:

.globl __vectors_start //异常向量表开始0xFFFF0000

__vectors_start:

ARM( swi SYS_ERROR0 )

THUMB( svc #0 )

THUMB( nop )

W(b) vector_und + stubs_offset

W(ldr) pc, .LCvswi + stubs_offset

W(b) vector_pabt + stubs_offset

W(b) vector_dabt + stubs_offset

W(b) vector_addrexcptn + stubs_offset

W(b) vector_irq + stubs_offset //中断发生后的跳转地址0xFFFF0018

W(b) vector_fiq + stubs_offset

.globl __vectors_end

__vectors_end:

stubs_offset只是个偏移量,用来修正跳转地址的,主要的操作是vector_irq执行。vector_irq是由宏vector_stub irq,IRQ_MODE,4(IRQ_MODE在include\asm\ptrace.h中定义:0x12)生成。以下是vector_irq生成后的代码(汇编代码中,@开始的语句、//、//都代表注释):

.align 5

vector_irq:

sub lr, lr, 4//因为异常发生时,cpu将pc地址+4赋值给lr,这里做修正。

@ Save r0, lr_ (parent PC) and spsr_

@ (parent CPSR)

@

stmia sp, {r0, lr}//保存r0, lr,到irq堆栈中(每个异常都有属于自己的堆栈)

mrs lr, spsr //lr保存spsr_irq的值,即usr状态的cpsr的值(见2.1)

str lr, [sp, #8]//保存spsr到[sp+8]处

@ Prepare for SVC32 mode. IRQs remain disabled.

@

mrs r0, cpsr

eor r0, r0,#( IRQ_MODE ^ SVC_MODE| PSR_ISETSTATE) // PSR_ISETSTATE:选择ARM/Thumb指令集

msr spsr_cxsf, r0//这里的cxsf表示从低到高分别占用的4个8bit的数据域

异或运算是可以交换位置的,也即A^B^C等价于A^C^B。所以这里的r0^( IRQ_MODE ^ SVC_MODE| PSR_ISETSTATE)等价于r0^ IRQ_MODE ^SVC_MODE,由于r0的低5位模式位与IRQ_MODE相同,所以r0^ IRQ_MODE的运算结果的低5位全被清零,然后再^SVC_MODE,也即低5位被设置为SV

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top