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

ARM Linux 中断向量表建立流程

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

再来看下vector 跳转表

1:        .long      __irq_usr            @  0  (USR_26 / USR_32)
2:        .long      __irq_invalid            @  1  (FIQ_26 / FIQ_32)
3:        .long      __irq_invalid            @  2  (IRQ_26 / IRQ_32)
4:        .long      __irq_svc            @  3  (SVC_26 / SVC_32)
5:        .long      __irq_invalid            @  4
6:        .long      __irq_invalid            @  5
7:        .long      __irq_invalid            @  6
8:        .long      __irq_invalid            @  7
9:        .long      __irq_invalid            @  8
10:        .long      __irq_invalid            @  9
11:        .long      __irq_invalid            @  a
12:        .long      __irq_invalid            @  b
13:        .long      __irq_invalid            @  c
14:        .long      __irq_invalid            @  d
15:        .long      __irq_invalid            @  e
16:        .long      __irq_invalid            @  f

这里只有usr 和svc 有入口,而其他都是invalid ,是因为linux只会从usr(application) 和svc(kernel)两种mode跳转到exception来

__stubs_start 和 __stubs_end 之间的代码简化后为:

1:    __stubs_start:
2:       vector_irq:    @vector_stub    irq, IRQ_MODE, 4
3:       vector_dabt: @vector_stub    dabt, ABT_MODE, 8
4:       vector_pabt:   @vector_stub    pabt, ABT_MODE, 4
5:       vector_und: @vector_stub    und, UND_MODE
6:       vector_fiq:
7:       vector_addrexcptn:
8:       .LCvswi:
9:    __stubs_end:

由此可以知道 __stubs_start 和 __stubs_end 之间定义了各种异常的入口

我们再来看为什么异常入口是“b vector_und + stubs_offset”, 同时为什么stubs_offset 的定义如下

.equ    stubs_offset, __vectors_start + 0x200 - __stubs_start

arm 的跳转指令b 是跳转到相对于PC的一个偏移地址( offset ),汇编器在编译时会对label 减去PC 得到offset,同时vector 拷贝后是如下排列的

__vectors_start

B vector_

__vectors_end

+0x200

__stubs_start

vector_

__stubs_end

因此,"b vector_" 的label –PC = offset, 而offset 为 b 指令与vector的offset,即

vector_-__stubs_start + ( 0x200 – ( PC_old – __vectors_start ) )

= vector_ + __vectors_start + 0x200 – __stubs_start – PC_old

所以异常入口为“b vector_und + stubs_offset”, 同时stubs_offset= __vectors_start + 0x200 – __stubs_start

我们可以通过objdump反汇编来验证:

00000060 :
.globl __stubs_start
__stubs_start:
/*
* Interrupt dispatcher
*/
vector_stub irq, IRQ_MODE, 4
60: e24ee004 sub lr, lr, #4 ; 0x4
64: e88d4001 stm sp, {r0, lr}

1d4: e1a00000 .word 0xe1a00000
1d8: e1a00000 .word 0xe1a00000
1dc: e1a00000 .word 0xe1a00000

000001e0 :

/*
* Undef instr entry dispatcher
* Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC
*/

__vectors_start:
swi SYS_ERROR0
284: ef9f0000 svc 0x009f0000
b vector_und + stubs_offset
288: ea0000dd b 604
ldr pc, .LCvswi + stubs_offset
28c: e59ff410 ldr pc, [pc, #1040] ; 6a4
b vector_pabt + stubs_offset
290: ea0000bb b 584
b vector_dabt + stubs_offset
294: ea00009a b 504
b vector_addrexcptn + stubs_offset
298: ea0000fa b 688
b vector_irq + stubs_offset
29c: ea000078 b 484
b vector_fiq + stubs_offset
2a0: ea0000f7 b 684

0x1e0 – 0x60 + 0x200 – ( 0x288 + 8 ) – 0x284 = 0xdd*4

ARM Linux外部中断处理过程

最近在学习arm linux的整套外部中断的处理过程,在网上汇总了一些资料,整个过程差不多都了解到了。如果没有这些资料我真是没信心从汇编开始读代码,感谢 奔腾年代的jimmy.lee和 linux论坛的bx_bird。
在下面的的注释中有一些我读代码时遇到的问题,要是大家知道是怎么回事,希望多多回复。
=============================================
一.ARM linux的中断向量表初始化分析
ARM linux内核启动时,通过start_kernel()->trap_init()的调用关系,初始化内核的中断异常向量表.
/* arch/arm/kernel/traps.c */
void __init trap_init(void)
{
extern void __trap_init(unsigned long);
unsigned long base = vectors_base();
__trap_init(base);
if (base != 0)
oopsprintk(KERN_DEBUG "Relocating machine vectors to 0x%08lxn", base);
#ifdef CONFIG_CPU_32
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
#endif
}
vectors_base是一个宏,它的作用是获取ARM异常向量的地址,该宏在include/arch/asm-arm/proc-armv/system.h中定义:
extern unsigned long cr_no_alignment; /* defined in entry-armv.S */
extern unsigned long cr_alignment; /* defined in entry-armv.S */
#if __LINUX_ARM_ARCH__ >= 4
#define vectors_base() ((cr_alignment & CR_V) ? 0xffff0000 : 0)
#else
#define vectors_base() (0)
#endif
  对于ARMv4以下的版本,这个地址固定为0;ARMv4及其以上的版本,ARM异常向量表的地址受协处理器CP15的c1寄存器(control register)中V位(bit[13])的控制,如果V=1,则异常向量表的地址为0x00000000~0x0000001C;如果V=0,则为:0xffff0000~0xffff001C。(详情请参考ARM Architecture Reference Manual)
  下面分析一下cr_alginment的值是在哪确定的,我们在arch/arm/kernel/entry-armv.S找到cr_alignment的定义:
.globl SYMBOL_NAME(cr_alignment)
.globl SYMBOL_NAME(cr_no_alignment)
SYMBOL_NAME(cr_alignment):
.space 4
SYMBOL_NAME(cr_no_alignment):
.space 4
  分析过head-armv.S文件的朋友都会知道,head-armv.S是非压缩内核的入口:
1 .section ".text.init",#alloc,#execinstr
2 .type stext, #function
3ENTRY(stext)
4 mov r12, r0

6 mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
7 msr cpsr_c, r0 @ an

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

网站地图

Top