ARM Linux 中断向量表建立流程
再来看下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_
vector_
= vector_
所以异常入口为“b vector_und + stubs_offset”, 同时stubs_offset= __vectors_start + 0x200 – __stubs_start
我们可以通过objdump反汇编来验证:
00000060 … | |
1d4: e1a00000 .word 0xe1a00000 000001e0 /* … | |
__vectors_start: |
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
5
6 mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
7 msr cpsr_c, r0 @ an
ARMLinux中断向量 相关文章:
- ARM Linux中断向量表搬移设计过程(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)