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 的值。