uboot relocation

uboot relocation

platform: ARM64

arch/arm/lib/crt0_64.S

uboot分为relocation前和relocation后两个stage,这两个stage stack所在的位置不同

对于relocation前,在_main()里设置sp的初始值为CONFIG_SYS_INIT_SP_ADDR,将这个初始值减去sizeof(struct global_data)以划出global_data struct的空间,这个相减的结果再保存到sp,此时的sp是这个stage的stack top

66 ENTRY(_main)
78 #else
79     ldr    x0, =(CONFIG_SYS_INIT_SP_ADDR)
80 #endif
81     bic    sp, x0, #0xf    /* 16-byte alignment for ABI compliance */
82     mov    x0, sp
83     bl    board_init_f_alloc_reserve
84     mov    sp, x0
85     /* set up gd here, outside any C code */
86     mov    x18, x0
87     bl    board_init_f_init_reserve
88 
89     mov    x0, #0
90     bl    board_init_f
92 #if !defined(CONFIG_SPL_BUILD)
93 /*
94  * Set up intermediate environment (new sp and gd) and call
95  * relocate_code(addr_moni). Trick here is that we'll return
96  * 'here' but relocated.
97  */
98     ldr    x0, [x18, #GD_START_ADDR_SP]    /* x0 <- gd->start_addr_sp */
99     bic    sp, x0, #0xf    /* 16-byte alignment for ABI compliance */
100     ldr    x18, [x18, #GD_NEW_GD]        /* x18 <- gd->new_gd */
101 
102     adr    lr, relocation_return
110     /* Add in link-vs-relocation offset */
111     ldr    x9, [x18, #GD_RELOC_OFF]    /* x9 <- gd->reloc_off */
112     add    lr, lr, x9    /* new return address after relocation */
113     ldr    x0, [x18, #GD_RELOCADDR]    /* x0 <- gd->relocaddr */   /*GD_RELOCADDR是relocaddr成员在global_data struct里的offset,x18即是gd指针*/
114     b    relocate_code

 

然后调用board_init_f,这个函数会执行init_sequece_f数组里的函数,这些函数会设置uboot relocation相关的gd成员,这些成员有:

gd->relocaddr:setup_dest_addr()先给gd->relocaddr设置一个初值,设置为CONFIG_SYS_INIT_SP_ADDR,这个macro一般是define在include/configs/下的相应header里。后面在一些其它函数里还会去+-gd->relocaddr,最后在setup_reloc()里计算relocation offset,即设置gd->reloc_off;

gd->reloc_off:gd->relocaddr和uboot初始加载地址CONFIG_SYS_TEXT_BASE的差值;

gd->start_addr_sp: relocation的新stack pointer;

gd->new_gd: reloation的新的struct global_data的地址

static int setup_dest_addr(void)

    gd->relocaddr = CONFIG_SYS_INIT_SP_ADDR;
727  static int setup_reloc(void)
728  {
729      if (gd->flags & GD_FLG_SKIP_RELOC) {
730          debug("Skipping relocation due to flag\n");
731          return 0;
732      }
733  
734  #ifdef CONFIG_SYS_TEXT_BASE
735  #ifdef ARM
736      gd->reloc_off = gd->relocaddr - (unsigned long)__image_copy_start;
737  #elif defined(CONFIG_M68K)
738      /*
739       * On all ColdFire arch cpu, monitor code starts always
740       * just after the default vector table location, so at 0x400
741       */
742      gd->reloc_off = gd->relocaddr - (CONFIG_SYS_TEXT_BASE + 0x400);
743  #elif !defined(CONFIG_SANDBOX)
744      gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE;
745  #endif
746  #endif
747      memcpy(gd->new_gd, (char *)gd, sizeof(gd_t));
748  
749      debug("Relocation Offset is: %08lx\n", gd->reloc_off);
750      debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n",
751            gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd),
752            gd->start_addr_sp);
753  
754      return 0;
755

然后_main()将board_init_f里设置好的gd->start_addr_sp设置到sp,此时的sp是relocation后运行所使用的stack的stack top,并将gd->new_gd的值读取出来保存到x18,此时x18指向了relocation后的global_data struct的地址

然后调用relocate_code去执行uboot relocation,它只有一个参数,保存在x0里,它的值就是上面确定的gd->relocaddr

 

posted @ 2022-06-09 17:51  aspirs  阅读(111)  评论(0编辑  收藏  举报