歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux管理 >> Linux維護

淺析Arm Linux中斷Vector向量表建立流程

Linux混入了mmu內存管理之後,ARM的中斷是怎麼樣的呢?和我們在裸板上的中斷有沒有區別?讓我們從源代碼入手,做一個粗略的分析:

init/main.c->start_kernel()->trap_init()
//-----------------------------------------------
1.trap_init()
//gliethttp函數位於arch/arm/kernel/traps.c
void __init trap_init(void)
{
    extern void __trap_init(unsigned long);
    unsigned long base = vectors_base(); //返回中斷base基址0xffff0000
    __trap_init(base);                   //以base為vector基址,初始化中斷向量表
    if (base != 0)
        printk(KERN_DEBUG "Relocating machine vectors to 0x%08lx\n",
            base);
#ifdef CONFIG_CPU_32
    modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
#endif
}
//--------------------------------------
2.vectors_base()
//gliethttp include/arch/asm-arm/proc-armv/system.h
extern unsigned long cr_alignment;
#if __LINUX_ARM_ARCH__ >= 4                //at91rm9200是ARMV4結構
#define vectors_base()    ((cr_alignment & CR_V) ? 0xffff0000 : 0)
#else
#define vectors_base()    (0)
                  #endif

  可以看到ARMv4以下的版本,該地址固定為0;ARMv4及以上版本,ARM中斷向量表的地址由CP15協處理器c1寄存器中V位(bit[13])控制,V和中斷向量表的對應關系如下:

V=0    ~    0x00000000~0x0000001C
V=1    ~    0xffff0000~0xffff001C
//------------------------------------------
2.1 cr_alignment
//gliethttp arch/arm/kernel/entry-armv.S
ENTRY(stext)
        mov    r12, r0
        mov    r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode
        msr    cpsr_c, r0                @ and all irqs disabled
//__lookup_processor_type 查詢處理器類型,[gliethttp 以後補上<淺析head-armv.S>]返回值
//2007-07-04
//r9 = processor ID                    //讀取cp15的c0寄存器
//r10 = pointer to processor structure //下面會add pc, r10, #12,跳轉到__arm920_setup
//gliethttp 在vmlinux-armv.lds.in中
//__proc_info_begin = .;
//             *(.proc.info)
// __proc_info_end = .;
//見2.2
        bl    __lookup_processor_type
        teq    r10, #0                   @ invalid processor?
        moveq    r0, #'p'                @ yes, error 'p'
        beq    __error
        bl    __lookup_architecture_type
        teq    r7, #0                    @ invalid architecture?
        moveq    r0, #'a'                @ yes, error 'a'
        beq    __error
//__create_page_tables 創建arm啟動臨時使用的前4M頁表
        bl    __create_page_tables
        adr    lr, __ret                 @ return address
        add    pc, r10, #12              @ initialise processor
        .type    __switch_data, %object
__switch_data:    .long    __mmap_switched
        .long    SYMBOL_NAME(__bss_start)
        .long    SYMBOL_NAME(_end)
        .long    SYMBOL_NAME(processor_id)
        .long    SYMBOL_NAME(__machine_arch_type)
        .long    SYMBOL_NAME(cr_alignment)
        .long    SYMBOL_NAME(init_task_union)+8192
/*
 * Enable the MMU. This completely changes the structure of the visible
 * memory space. You will not be able to trace execution through this.
 * If you have an enquiry about this, *please* check the linux-arm-kernel
 * mailing list archives BEFORE sending another post to the list.
 */
        .type    __ret, %function
__ret:        ldr    lr, __switch_data
        mcr    p15, 0, r0, c1, c0
//將__arm920_setup中設置的r0值,置入cp15協處理器c1寄存器中
        mrc    p15, 0, r0, c1, c0, 0     @ read it back.
        mov    r0, r0
//填充armv4中的三級流水線:mov r0,
r0 對應一個nop,所以對應2個nop和一個mov pc,lr剛好三個"無用"操作
        mov    r0, r0
        mov    pc, lr
//跳轉到__mmap_switched函數 gliethtttp
/*
 * The following fragment of code is executed with the MMU on, and uses
 * absolute addresses; this is not position independent.
 *
 * r0 = processor control register
 * r1 = machine ID
 * r9 = processor ID
 */
        .align    5
__mmap_switched:
        adr    r3, __switch_data + 4
        ldmia    r3, {r4, r5, r6, r7, r8, sp}@ r2 = compat
//2007-07-04 gliethttp
//r4    ~    __bss_start
//r5    ~    _end
//r6    ~    processor_id
//r7    ~    __machine_arch_type
//r8    ~    cr_alignment
//sp    ~    (init_task_union)+8192
//以下幾步操作對processor_id,__machine_arch_type,cr_alignment賦值gliethttp
        mov    fp, #0                                @ Clear BSS (and zero fp)
1:      cmp    r4, r5                                //bss區清0
        strcc    fp, [r4],#4
        bcc    1b
        str    r9, [r6]                              @ Save processor ID
        str    r1, [r7]                              @ Save machine type
#ifdef CONFIG_ALIGNMENT_TRAP
        orr    r0, r0, #2                            @ ...........A.
#endif
        bic    r2, r0, #2                            @ Clear 'A' bit
//r2存放 禁用TRAP隊列故障 後的r0值
//r8->cr_alignment,cr_no_alignment
//所以stmia    r8, {r0, r2}後,cr_alignment = r0,cr_no_alignment = r2
        stmia    r8, {r0, r2}           @ Save control register values
        b    SYMBOL_NAME(start_kernel)        //進入內核C程序
//--------------------------------------
2.2 __arm920_proc_info
//gliethttp arch/arm/mm/proc-arm920.S
.section ".proc.info", #alloc, #execinstr
    .type    __arm920_proc_info,#object
__arm920_proc_info:
//該地址存儲到r10中
    .long    0x41009200
    .long    0xff00fff0
    .long    0x00000c1e 

sp;  .LCsirq:    .word    __temp_irq
0xffff21a8                     .LCsund:    .word    __temp_und
                  0xffff21ac                     .LCsabt:    .word    __temp_abt


  如果你現在有這樣一種疑惑?程序為什麼編譯地址是0xc0008000,將其直接拷貝到0xffff0000和0xffff2000為什麼還能順利執行,請參考我的另一篇blog《arm相對跳轉到底是怎麼回事》,主要原因是b指令是相對跳轉指令,adr也是基於pc的前後偏移指令,當然對於ldr pc, __real_stubs_start + (.LCvswi - __stubs_start)是絕對地址賦值,所以最後pc會跳轉到0xc000xxxx空間執行代碼,其他的跳轉如:b __real_stubs_start + (vector_IRQ - __stubs_start)都會到0xffff2xxxx相應的vector_IRQ處執行向量中斷處理函數,還有一個要分析的問題是:.equ __real_stubs_start,

  .LCvectors + 0x200,語句b __real_stubs_start

  + (vector_undefinstr - __stubs_start)就是跳轉到LCvectors+0x200空間執行。舉一個例子:

org 0x8000
        reset    b    InitRest
        ...
        InitRest:
        ...
        那麼reset標號的地址為0x8000,他的意思是在0x8000處向前跳轉到InitRest,        我們也可以這樣來構造跳轉:
        org 0x8000
        reset b (0x8000+(.InitRest - .reset))
        ...
        InitRest:
        ...
                          以上的構造語句同樣實現了相對0x8000地址的跳轉

 

Copyright © Linux教程網 All Rights Reserved