IMX8 UBOOT源码分析(六)main函数分析

时间:2024-03-28 16:54:00

在start.S做完基础的初始化后,程序进入到main函数中,本博客主要分析main函数的框架(在crt0_64.S)

ENTRY(_main)
#if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK)
    ldr    x0, =(CONFIG_TPL_STACK)
#elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
    ldr    x0, =(CONFIG_SPL_STACK)
#elif defined(CONFIG_SYS_INIT_SP_BSS_OFFSET)
    adr    x0, __bss_start
    add    x0, x0, #CONFIG_SYS_INIT_SP_BSS_OFFSET
#else
    ldr    x0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif

/*CONFIG_TPL_BUILD、CONFIG_TPL_NEEDS_SEPARATE_STACK和CONFIG_SYS_INIT_SP_BSS_OFFSET在U-BOOT中都没有定义

include/configs/imx8qxp_mek.h:134:#define CONFIG_SYS_INIT_SP_ADDR         0x80200000

include/configs/imx8qxp_mek.h:21:#define CONFIG_SPL_STACK        0x013E000

所以把CONFIG_SYS_INIT_SP_ADDR的值赋值给x0,即x0 = 0x80200000*/

    bic    sp, x0, #0xf                                             //将x0的后四位清零,即16字节对齐后赋值给sp,后续可以调用c函数
    mov    x0, sp                                                   //存储sp的地址到x0中
    bl    board_init_f_alloc_reserve                      //调用board_init_f_alloc_reserve函数

   //board_init_f_alloc_reserve 在board_init.c中定义

   ulong board_init_f_alloc_reserve(ulong top)                 //此处top为传入的参数x0,top = sp = 0x80200000
   {
      #if CONFIG_VAL(SYS_MALLOC_F_LEN)               

      /*#define CONFIG_VAL(option)  config_val(option)            //等价于config_val(SYS_MALLOC_F_LEN)

        #define config_val(cfg) _config_val(_IS_SPL, cfg)           //等价于_config_val(_IS_SPL,SYS_MALLOC_F_LEN)
       #define _config_val(x, cfg) __config_val(x, cfg)                //等价于__config_val(_IS_SPL,SYS_MALLOC_F_LEN)
       #define __config_val(x, cfg) ___config_val(__ARG_PLACEHOLDER_##x, cfg)        

            //等价于___config_val(__ARG_PLACEHOLDER__IS_SPL,SYS_MALLOC_F_LEN)
       #define ___config_val(arg1_or_junk, cfg)  \
       ____config_val(arg1_or_junk CONFIG_SPL_##cfg, CONFIG_##cfg)

           //等价于____config_val( __ARG_PLACEHOLDER__IS_SPL CONFIG_SPL_SYS_MALLOC_F_LEN,                                                                                 CONFIG_SYS_MALLOC_F_LEN)
       #define ____config_val(__ignored, val, ...) val             //等价于CONFIG_SYS_MALLOC_F_LEN      

      //在configs/imx8qxp_mek_defconfig中CONFIG_SYS_MALLOC_F_LEN=0x2000           
          top -= CONFIG_VAL(SYS_MALLOC_F_LEN);        //top = 0x80200000 - 0x2000  = 0x801FE000
      #endif
      top = rounddown(top-sizeof(struct global_data), 16);

      //rounddown定义在在kernel.h中

       #define rounddown(x, y) (                \        //x=top-sizeof(struct global_data), y=16
      {                            \
            typeof(x) __x = (x);                \             //__x =top-sizeof(struct global_data)
            __x - (__x % (y));                \               //top = top-sizeof(struct global_data) - (top-sizeof(struct global_data))%16
       }                                                               //此处相当于top-sizeof(struct global_data)16字节对齐

       return top;                                                 //返回top值
 }

  /*此处由于struct global_data的大小受config项的影响,无法直接计算,我们可以通过看汇编代码得知

   000000008002cc04 <board_init_f_alloc_reserve>:
    8002cc04:    928433e1     mov    x1, #0xffffffffffffde60            // #-8608
    8002cc08:    8b010000     add    x0, x0, x1                            //x0 -8608 = 0x801FBE60
    8002cc0c:    927cec00     and    x0, x0, #0xfffffffffffffff0          //16字节对齐 x0 =0x801FBE60
    8002cc10:    d65f03c0     ret

   可以看到x0减少了8608字节,即struct global_data为8608个字节*/

   //此时内存的情况如下:

     IMX8 UBOOT源码分析(六)main函数分析
    mov    sp, x0                                                  //将函数board_init_f_alloc_reserve的返回值赋值给sp=0x801FBE60
    mov    x18, x0                                                //将x0的值存入x18中,方便以后调用x18=0x801FBE60
    bl    board_init_f_init_reserve                        //跳到board_init_f_init_reserve 中

      //board_init_f_alloc_reserve 也在board_init.c中定义

   void board_init_f_init_reserve(ulong base)              //base即为x0,base=0x801FBE60
   {
        struct global_data *gd_ptr;           

        gd_ptr = (struct global_data *)base;                   //gd_ptr指向base,即为分配的sizeof(struct global_data)空间
        memset(gd_ptr, '\0', sizeof(*gd));                       //将分配的sizeof(struct global_data)空间清零
       #if !defined(CONFIG_ARM)
          arch_setup_gd(gd_ptr);
       #endif

       //CONFIG_ARM并没有定义,arch_setup_gd的功能只是gd = gd_ptr
       base += roundup(sizeof(struct global_data), 16);

       //roundup的定义如下:

        #define roundup(x, y) (                    \         //x=sizeof(struct global_data), y=16
        {                            \
              const typeof(y) __y = y;            \         //__y =16
              (((x) + (__y - 1)) / __y) * __y;        \     //base += ((sizeof(struct global_data)+15)/16)*16    16字节对齐
        }    

       //此时base跳到0x801FE000处

       #if CONFIG_VAL(SYS_MALLOC_F_LEN)
          gd->malloc_base = base;             //将全局变量gd(即分配的sizeof(struct global_data)内存空间)的base指向0x801FE000处
          base += CONFIG_VAL(SYS_MALLOC_F_LEN);         //base=0x80200000
      #endif
   }

   //board_init_f_alloc_reserve的主要功能是清空全局变量gd区,并初始化gd的malloc_base的地址,用于后续内存分配申请

    mov    x0, #0
    bl    board_init_f

   //board_init_f为主要的初始化函数之一,这个下次单独分析

   #if !defined(CONFIG_SPL_BUILD)

        ldr    x0, [x18, #GD_START_ADDR_SP]        //x0存入gd->start_addr_sp的地址
        bic    sp, x0, #0xf                                            //sp指向x0并且16字节对齐
        ldr    x18, [x18, #GD_NEW_GD]                    //x18存入gd->new_gd的地址

        adr    lr, relocation_return                             //设置lr为relocation_return的地址

        #if CONFIG_POSITION_INDEPENDENT
            adr    x0, _start        /* x0 <- Runtime value of _start */
            ldr    x9, _TEXT_BASE        /* x9 <- Linked value of _start */
            sub    x9, x9, x0        /* x9 <- Run-vs-link offset */
            add    lr, lr, x9
       #endif

       //CONFIG_POSITION_INDEPENDENT在U-BOOT中未定义

       ldr    x9, [x18, #GD_RELOC_OFF]               //x9存入gd->reloc_off 的地址
       add    lr, lr, x9                                                //设置新的返回地址为lr+x9
       ldr    x0, [x18, #GD_RELOCADDR]             //x0存入 gd->relocaddr 
       b    relocate_code

       //重定位 代码后续博客继续分析

       relocation_return:

          bl    c_runtime_cpu_setup

        //c_runtime_cpu_setup在start.S中定义

       ENTRY(c_runtime_cpu_setup)
       #if defined(CONFIG_ARMV8__SPL_EXCEPTION_VECTORS) || !defined(CONFIG_SPL_BUILD)
            adr    x0, vectors
            switch_el x1, 3f, 2f, 1f
     3:    msr    vbar_el3, x0
            b    0f
     2:    msr    vbar_el2, x0
           b    0f
     1:    msr    vbar_el1, x0
     0:
     #endif

     ret
     ENDPROC(c_runtime_cpu_setup)

     //根据当前的中断等级设置对应的中断向量表地址

    #endif /* !CONFIG_SPL_BUILD */
    #if defined(CONFIG_SPL_BUILD)
        bl    spl_relocate_stack_gd           /* may return NULL */
        cmp    x0, #0
        csel    x18, x0, x18, ne
        mov    x1, sp
        cmp    x0, #0
        csel    x0, x0, x1, ne
        mov    sp, x0
    #endif

   //CONFIG_SPL_BUILD在U-BOOT中未定义

    ldr    x0, =__bss_start        
    ldr    x1, =__bss_end            
clear_loop:
    str    xzr, [x0], #8
    cmp    x0, x1
    b.lo    clear_loop

   //清空bss段
    mov    x0, x18                /* gd_t */
    ldr    x1, [x18, #GD_RELOCADDR]    /* dest_addr */
    b    board_init_r   

   // board_init_r 也是U-BOOT中比较重要的一项初始化函数,后续博客单独分析      

ENDPROC(_main)
main函数的大致框架就结束了,后面会继续深入分析board_init_f、relocate_code和board_init_r 的代码