歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> linux內核啟動head.s

linux內核啟動head.s

日期:2017/3/3 12:50:07   编辑:Linux內核

linux內核啟動head.s

已知條件: 1.首先通過分析Kernel的Makefile的鏈接知道 之後內核啟動執行的第一個腳本是:../arch/arm/kernel/head.S

2.u-boot啟動內核:

[code]theKernel(0,bd->bi_arch_number,bd->bi_boot_params) //啟動內核
    bd->bi_arch_number  //機器id
    bd->bi_boot_params  //uboot傳入內核參數存放的地址

分析

[code]//head.S:
                                @ and irqs disabled
    mrc p15, 0, r9, c0, c0      @ get processor id
    bl  __lookup_processor_type @ r5=procinfo r9=cpuid
    movs    r10, r5             @ invalid processor (r5=0)?
    beq __error_p               @ yes, error 'p'
    bl  __lookup_machine_type   @ r5=machinfo  //查找機器ID
    movs    r8, r5              @ invalid machine (r5=0)?
    beq __error_a               @ yes, error 'a'
    bl  __create_page_tables

//head-common.S:
3:                              #3b地址定義
    .long   .                   #3b的虛擬地址
    .long   __arch_info_begin
    .long   __arch_info_end

 __lookup_machine_type:
    adr r3, 3b                      #r3 = 3b的物理地址
    ldmia   r3, {r4, r5, r6}        
    sub r3, r3, r4   
    add r5, r5, r3          
    add r6, r6, r3                  @ physical address space
1:  ldr r3, [r5, #MACHINFO_TYPE]    @ get machine type
    teq r3, r1                      @ matches loader number?
    beq 2f                          @ found
    add r5, r5, #SIZEOF_MACHINE_DESC    @ next machine_desc
    cmp r5, r6
    blo 1b
    mov r5, #0                      @ unknown machine
2:  mov pc, lr
//地址轉換過程
adr r3, 3b  #r3 = 3b的物理地址
ldmia   r3, {r4, r5, r6}
# r4= 3標號的虛擬地址
# r5=__arch_info_begin 
# r6 = __arch_info_end
//__arch_info_begin,__arch_info_end在哪兒定義?
vmlinux.lds:
  ......
  __arch_info_begin=.;
  *(.arch.info.init) //這是代碼中定義的一個段
  __arch_info_end=.;

再看看:arch.h
arch.h
  #define MACHINE_START(_type,_name)            \
  static const struct machine_desc __mach_desc_##_type  \
   __used                           \
   __attribute__((__section__(".arch.info.init"))) = {  \
    .nr     = MACH_TYPE_##_type,        \
    .name       = _name,

   #define MACHINE_END              \
  };

 //那麼誰在使用這個宏
 誰在使用這個宏:以s3c2440為例:
MACHINE_START(S3C2440, "SMDK2440")
    /* Maintainer: Ben Dooks <[email protected]> */
    .phys_io    = S3C2410_PA_UART,
    .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
    .boot_params    = S3C2410_SDRAM_PA + 0x100,
    .init_irq   = s3c24xx_init_irq,
    .map_io     = smdk2440_map_io,
    .init_machine   = smdk2440_machine_init,
    .timer      = &s3c24xx_timer,
MACHINE_END

將其展開:
static const struct machine_desc __mach_desc_S3C2440 = {
    .nr     = MACH_TYPE_S3C2440,        
    .name       = "SMDK2440",
    .phys_io    = S3C2410_PA_UART,
    .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
    .boot_params    = S3C2410_SDRAM_PA + 0x100,
    .init_irq   = s3c24xx_init_irq,
    .map_io     = smdk2440_map_io,
    .init_machine   = smdk2440_machine_init,
    .timer      = &s3c24xx_timer,
};
//machine_desc
machine_desc 打開這個結構體
描述一個單板的屬性:
struct machine_desc {
    unsigned int        nr;     /* architecture number  */
    unsigned int        phys_io;    /* start of physical io */
    unsigned int        io_pg_offst;    /* byte offset for io * page tabe entry */

    const char      *name;      /* architecture name    */ 機器id
    unsigned long       boot_params;    /* tagged list      */ 參數

    unsigned int        video_start;    /* start of video RAM   */
    unsigned int        video_end;  /* end of video RAM */

    unsigned int        reserve_lp0 :1; /* never has lp0    */
    unsigned int        reserve_lp1 :1; /* never has lp1    */
    unsigned int        reserve_lp2 :1; /* never has lp2    */
    unsigned int        soft_reboot :1; /* soft reboot      */
    void            (*fixup)(struct machine_desc *,
                     struct tag *, char **,
                     struct meminfo *);
    void            (*map_io)(void);/* IO mapping function  */
    void            (*init_irq)(void);
    struct sys_timer    *timer;     /* system tick timer    */
    void            (*init_machine)(void);
};

在看看head_common.S
    1:  
    ldr r3, [r5, #MACHINFO_TYPE]    @ get machine type
    teq r3, r1                      @ matches loader number? 比較機器id

比較成功之後:
     bl     __create_page_tables    @創建頁表
     ldr    r13, __switch_data      @ address to jump to after
     @ mmu has been enabled
     adr    lr, __enable_mmu        @ return (PIC) address  #使能MMU
     add    pc, r10, #PROCINFO_INITFUNC
創建頁表,使能MMU之後跳轉到__switch_data
 __switch_data:
    .long   __mmap_switched
    .long   __data_loc              @ r4
    .long   __data_start            @ r5
    .long   __bss_start             @ r6
    .long   _end                    @ r7
    .long   processor_id            @ r4
    .long   __machine_arch_type     @ r5
    .long   cr_alignment            @ r6
    .long   init_thread_union + THREAD_START_SP   @ sp

/*
 * The following fragment of code is executed with the MMU on in MMU mode,
 * and uses absolute addresses; this is not position independent.
 *
 *  r0  = cp#15 control register
 *  r1  = machine ID
 *  r9  = processor ID
 */
    .type   __mmap_switched, %function
__mmap_switched:
    adr r3, __switch_data + 4

    ldmia   r3!, {r4, r5, r6, r7}
    cmp r4, r5              @ Copy data segment if needed
1:  cmpne   r5, r6
    ldrne   fp, [r4], #4
    strne   fp, [r5], #4
    bne 1b

    mov fp, #0              @ Clear BSS (and zero fp)
1:  cmp r6, r7
    strcc   fp, [r6],#4
    bcc 1b

    ldmia   r3, {r4, r5, r6, sp}
    str r9, [r4]                @ Save processor ID
    str r1, [r5]                @ Save machine type
    bic r4, r0, #CR_A           @ Clear 'A' bit
    stmia   r6, {r0, r4}        @ Save control register values
    b   start_kernel    #啟動內核 內核的第一個C函數:

總結:Head.s的作用

1、判斷內核支持不支持CPU

2、判斷內核支持不支持單板

3、建立頁表

4、使能MMU

5、跳轉到 start_kernel

Copyright © Linux教程網 All Rights Reserved