ARM Linux中断向量表搬移设计过程
Preface引言
我在这里用一些篇幅来描述一下arm体系结构下Linux中怎样来初始化中断向量表的,因为这个方法很具有通用性,我把它叫做代码大挪移。您说搬代码谁不会阿,不就是拷贝吗,的确如此,但是拷贝也有技巧。拷贝很简单啦,其实就是memcpy,这不用提,我在这里想说的是,你怎么把你的代码设计成能随便拷贝的,换句专业的术语,叫与位置无关的代码,拷到哪都能用。我以前也用过类似的方法作启动,今天拿来说说。
Scenario 1第一场景copy
我们先看实际动作。代码的位置在arch/arm/traps.c中,kernel version: 2.6.27。这个是初始化部分的代码,setup_arch()->early_trap_init().熟悉初始化部分的朋友们可能见到过这段代码。
void __init early_trap_init(void)
{
unsigned long vectors = CONFIG_VECTORS_BASE;
extern char __stubs_start[], __stubs_end[];
&nsp;extern char __vectors_start[], __vectors_end[];
extern char __kuser_helper_start[], __kuser_helper_end[];
int kuser_sz = __kuser_helper_end - __kuser_helper_start;
/*
* 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);
memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
…
}
实际copy动作一目了然,就是两个memcpy(第三个实际上是拷贝一些别的东西,原理是一样的,这里不提了). Copy的源是vectors,这个值是CONFIG_VECTORS_BASE,一般来讲,是0xffff0000,当然你可以根据硬件的设定自己配制这个值。把什么东西往那copy呢?第一部分是从__vectors_start到__vectors_end之间的代码,第二部分是从__stubs_start到__stubs_end之间的代码,而第二部分是copy到vectors + 0x200起始的位置。也就是说,两部分之间的距离是0x200,即512个字节。
我们来看__vectors_start,__vectors_end,FONT face="Times New Roman">__stubs_start,__stubs_end到底是什么东西,只要知道它们在哪里定义的,就知道怎么回事了。
Scenario 2第二场景主角闪亮登场
它们埋伏在arch/arm/kernel/entry-armv.S中,这个文件是arm中各个模式的入口代码,熟悉arm的朋友们知道arm有几种模式,不知道的自己查查,不说了。我们取一个片断,和我们的阐述相关的部分。为了让大家看得更清楚,我删掉了部分代码和注释,把主干凸显出来。有兴趣的朋友可以查看源代码,研究全部,里面还是比较有内涵的。
.globl__stubs_start
__stubs_start:
/*
* Interrupt dispatcher
*/
vector_stubirq, IRQ_MODE, 4
//请注意这里:vector_stub是一个宏,展开后是一块代码,下面是个跳转表,我们将代码结//构展开,大致是这样的结构: (后面的vector_stubdabt, ABT_MODE, 8等展开过程全一样,在此略过不提)
// -------------------------------- begin展开
.align5
vector_irq:
sublr, lr, 4
@ Save r0, lr_
@ (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展开
.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@f
/*
* Data abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
vector_stubdabt, ABT_MODE, 8
.long__dabt_usr@0(USR_26 / USR_32)
.long__dabt_invalid@1(FIQ_26 / FIQ_32)
.long__dabt_invalid@2(IRQ_26 / IRQ_32)
.long__dabt_svc@3(SVC_26 / SVC_32)
。。。
.long__dabt_invalid@f
/*
* Prefetch abort dispatcher
* Enter in ABT mode, spsr = USR CPSR, lr = USR PC
*/
vector_stubpabt, ABT_MODE, 4
.long__pabt_usr@0 (USR_26 / USR_32)
.long__pabt_invalid@1 (FIQ_26 / FIQ_32)
.long__pabt_invalid@2 (IRQ_26 / IRQ_32)
.long__pabt
ARMLinux中断向量 相关文章:
- ARM Linux 中断向量表建立流程(11-09)
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)