微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux 中断向量表建立流程

ARM Linux 中断向量表建立流程

时间:11-09 来源:互联网 点击:
一般编写arm的裸机程序的时候,创建中断向量表就把它放在0x00000000~0x0000001c中,一般都放在这个位置上。但是中断向量表也可以放在0xffff0000~0xffff001c中,知道这是怎么设置的么?开始看到的时候真的有点奇怪,因为在学习arm的时候,根本没去看arm中的协处理器CP15中的c1控制寄存器中的v位来控制,我们一般都使用默认的值0,则必须将中断向量表放在0x00000000~0x0000001c中。

在看Linux内核对arm中的中断的初始化的时候,就一直对0xffff0000的地址有点怀疑,果然在网上发现这个地址不是随便写的,当我看到arm的协处理器进行控制,中断向量表的地址的时候,真的是哭笑不得啊!!
有人肯定会问?v位是什么时候设置的呢?其实仔细的朋友就知道在head.S中,在创建完页表的时候,如add pc,r10,#PROCINFO_INITFUNC
别急,r10保存在前面设置的procinfo的地址,但是很多人就觉得PROCINFO_INITFUNC的宏定义就不知道在哪找了,在include/asm/asm-offset.h中有定义。
这些搞懂了,首先必须将中断向量表拷贝到0xffff0000的地址上去,把中断处理函数也拷贝到0xffff0200的地址上去,那么在中断向量表进行跳转的时候,如b vector_irq+stubs_offset,但是stubs_offset的偏移怎么设置呢?如果用b vector_irq的话,它就会跳转到原先的中断处理函数中去,因为它也拷贝到了0xffff0200的地址上去,所以将__vector_start-_stubs_start+0x200的话就转移到拷贝后的地址上去执行了。
很多人应该会有点疑问吧,vector_irq好像找不到,别急,细心点,就在宏定义.macro vector_stubs,name,mode,correction中对各种处理函数有定义,所以很快就将中断向量表创建好了。

Linux Version : 2.6.29

1. start_kernel-->setup_arch-->early_trap_init

1:        memcpy((void   *)vectors, __vectors_start, __vectors_end - __vectors_start);
2:        memcpy((void   *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
3:        memcpy((void   *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);

对于第一行:

__vectors_start 和 __vectors_end 定义在 arch/arm/kernel/entry-armv.S , 它们之间保存了中断向量表。

1:        .globl    __vectors_start
2:    __vectors_start:
3:        swi    SYS_ERROR0 
4:        b    vector_und + stubs_offset
5:        ldr    pc, .LCvswi + stubs_offset
6:        b    vector_pabt + stubs_offset
7:        b    vector_dabt + stubs_offset
8:        b    vector_addrexcptn + stubs_offset
9:        b    vector_irq + stubs_offset
10:        b    vector_fiq + stubs_offset
11:    
12:        .globl    __vectors_end
13:    __vectors_end:

vectors 的地址为CONFIG_VECTORS_BASE , 在.config中定义为0xffff0000

所以 第1行就是把中断向量表拷贝到0xffff0000

对于第二行:

vector_stub是一个带参数的宏,第一个是name,第二个是arm excepiton mode,第三个是为了得到返回地址,lr需要减去的偏移

1:        .macro    vector_stub, name, mode, correction=0
2:        .align    5
3:    
4:    vector_/name:
5:        .if   /correction
6:        sub    lr, lr, #/correction          @得到正确的返回地址
7:        .endif
8:    
9:        @
10:        @ Save r0, lr_ (parent PC) and spsr_
11:        @ (parent CPSR)
12:        @
13:        stmia    sp, {r0, lr}        @ save r0, lr
14:        mrs    lr, spsr
15:        str    lr, [sp, #8]        @ save spsr
16:    
17:        @
18:        @ Prepare for   SVC32 mode.  IRQs remain disabled.
19:        @ 
20:        mrs    r0, cpsr
21:        eor    r0, r0, #(/mode ^ SVC_MODE) @把cpsr内容与(mode^SVC_mode)异或,即r0里为SVC_MODE 
22:        msr    spsr_cxsf, r0  @把r0的值写入整个spsr寄存器(cxsf表示要往哪个字节写入)
23:    
24:        @
25:        @ the branch table must immediately follow this   code
26:        @
27:        and    lr, lr, #0x0f @lr为spsr_的值,此语句取到进入异常前的mode
28:        mov    r0, sp         @ 
29:        ldr    lr, [pc, lr, lsl #2] @lr=pc+mode*4,其中pc为紧接着30的指令,即vector_stub后的第一条指令
30:        movs    pc, lr            @ movs会把spsr的值赋给cpsr,所以branch to handler in   SVC mode
31:    ENDPROC(vector_/name)
32:        .endm

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

网站地图

Top