3.7.2. 代码重定位

通常内核的代码段放在 DRAM 的开始位置,U-Boot 的代码位置放到 DRAM 的末端。 但是由于不同项目所用的 DRAM 大小不一致,为了方便,将 U-Boot 的链接地址也定义在 DRAM 比较前面的固定位置。在加载 U-Boot 初始化完 DRAM 之后,U-Boot 读取当前平台的 DRAM 大小, 然后在加载 Kernel 之前将自身代码段和数据段等信息重定位到 DRAM 的末端继续运行, 将 DRAM 的前端空间让给 Kernel。

_start // arch/riscv/cpu/start.S
|-> save_boot_params // arch/riscv/mach-zx/lowlevel_init.S
|-> ...
|-> board_init_f(); // common/board_f.c
    |-> setup_reloc(); // common/board_f.c
    |-> jump_to_copy(); // common/board_f.c
        |-> relocate_code(); // arch/riscv/cpu/start.S
            |       // RISCV 上的实现,relocate 之后,函数不返回,直接跳转到 board_init_r 执行
            |-> invalidate_icache_all()
            |-> flush_dcache_all()
            |-> board_init_r();

重定位的具体位置 gd->relocaddr 的计算可查看 common/board_f.c

static const init_fnc_t init_sequence_f[] = {
    ...
    setup_dest_addr,
    reserve_round_4k,
    reserve_mmu,
    reserve_video,
    reserve_trace,
    reserve_uboot,
    ...
    setup_reloc,
    NULL,
};

最终 gd->reloc_off 的计算,在 setup_reloc 中完成。

备注

如果 CONFIG_SYS_TEXT_BASE == relocation address,则不需要做重定位的工作, 可以节省启动时间。这个需要根据当前项目的 DRAM 大小进行计算 CONFIG_SYS_TEXT_BASE 的值。