ARM Linux中断向量表搬移设计过程

590阅读 0评论2013-04-23 puppypyb
分类:嵌入式

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之间的代码,而第二部分是copyvectors + 0x200起始的位置。也就是说,两部分之间的距离是0x200,512个字节。

我们来看__vectors_start__vectors_endfont 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_stub    irq, IRQ_MODE, 4

// 请注意这里:vector_stub是一个宏,展开后是一块代码,下面是个跳转表,我们将代码结// 构展开,大致是这样的结构: (后面的vector_stub    dabt, ABT_MODE, 8等展开过程全一样,在此略过不提)


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


.align       5


vector_irq:


       sub  lr, lr, 4


      


       @ Save r0, lr_ (parent PC) and spsr_


       @ (parent CPSR)


       @


       stmia       sp, {r0, lr}            @ save r0, lr


       mrs  lr, spsr


       str   lr, [sp, #8]             @ save spsr


      


       @ Prepare for SVC32 mode.  IRQs remain disabled.


       @


       mrs  r0, cpsr


       eor   r0, r0, IRQ_MODE ^ SVC_MODE)


       msr  spsr_cxsf, r0


      


       @ the branch table must immediately follow this code


       @


       and  lr, lr, #0x0f


       mov r0, sp


       ldr   lr, [pc, lr, lsl #2]


       movs      pc, 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_stub    dabt, 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_stub    pabt, 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_svc                   @  3 (SVC_26 / SVC_32)

。。。

       .long       __pabt_invalid               @  f

 


/*

 * Undef instr entry dispatcher

 * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC

 */

       vector_stub    und, UND_MODE

 


       .long       __und_usr                    @  0 (USR_26 / USR_32)

       .long       __und_invalid                @  1 (FIQ_26 / FIQ_32)

       .long       __und_invalid                @  2 (IRQ_26 / IRQ_32)

       .long       __und_svc                    @  3 (SVC_26 / SVC_32)

    。。。

       .long       __und_invalid                @  f

 


       .align       5

 


vector_fiq:

       disable_fiq

       subs pc, lr, #4

 


vector_addrexcptn:

       b     vector_addrexcptn

/*

 * We group all the following data together to optimise

 * for CPUs with separate I & D caches.

 */

       .align       5

 


.LCvswi:

       .word      vector_swi

 


       .globl      __stubs_end


__stubs_end:


 


       .equ stubs_offset, __vectors_start + 0x200 - __stubs_start

 


       .globl      __vectors_start


__vectors_start:


       swi  SYS_ERROR0

       b     vector_und + stubs_offset

       ldr   pc, .LCvswi + stubs_offset

       b     vector_pabt + stubs_offset

       b     vector_dabt + stubs_offset

       b     vector_addrexcptn + stubs_offset

       b     vector_irq + stubs_offset

       b     vector_fiq + stubs_offset

 


       .globl      __vectors_end


__vectors_end:


 


为了让大家看得更清,我把代码的结构再次简化成这样:

       .globl      __stubs_start


__stubs_start:


.align       5


vector_irq:


[code part]                // 展开代码


[jump table part]           // 地址跳转表


。。。

.align       5


vector_dabt:


[code part]


[jump table part]


 


。。。


.align       5


vector_ pabt:


[code part]


[jump table part]


 


。。。


.align       5


vector_und:


[code part]


[jump table part]


 


。。。


.align       5


vector_fiq:


。。。


 


       .globl      __stubs_end


__stubs_end:


 


       .globl      __vectors_start


__vectors_start:


       swi  SYS_ERROR0

       b     vector_und + stubs_offset

       ldr   pc, .LCvswi + stubs_offset

     &nb

上一篇:没有了
下一篇:浅析Linux的软中断的实现