3.7.4. 环境变量加载
如前面所述,环境变量的处理有两个阶段:
环境变量初始
环境变量读取
如下面的调用流程, env_init()
在 board_init_f()
阶段执行,但具体的加载过程
在 board_init_r()
阶段执行。
reset // 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
|-> invalidate_icache_all()
|-> flush_dcache_all()
|-> board_init_r();
| // 逐个调用 init_sequence_r 里面的函数,其中包括 initr_env
|-> initr_env(); // common/board_r.c
|-> should_load_env(void);// common/board_r.c
| // 由于没有在 DTS 中进行配置,总是返回 1
| // fdtdec_get_config_int(gd->fdt_blob, "load-environment", 1);
|-> env_relocate(); // env/common.c
|-> env_load(); // env/env.c
U-Boot 支持在多种存储介质中保存环境变量,并且提供了一个插拔式的机制,用于实现从 不同的存储介质中加载环境变量内容。
在添加新的环境变量加载器时,只需要实现对应存储介质的 load
和 save
函数,
然后通过宏 U_BOOT_ENV_LOCATION
将对应的信息添加到 .u_boot_list_2
链接段中。
比如下面的定义,将生成 .u_boot_list_2_env_driver_2_spinand
信息。
U_BOOT_ENV_LOCATION(spinand) = {
.location = ENVL_SPINAND,
ENV_NAME("SPINAND")
.load = env_spinand_load,
#if defined(CMD_SAVEENV)
.save = env_save_ptr(env_spinand_save),
#endif
};
env_driver_lookup()
函数首先通过检查当前的启动设备,然后从 .u_boot_list_2
段中查找对应启动设备的 ENV 加载驱动,最后调用对应的驱动读取并导入环境变量内容。
env_load(); // env/env.c
|-> env_driver_lookup(ENVOP_LOAD, prio);
| |-> loc = env_get_location(); // board/zx/m4/env_location.c
| | |-> bd = aic_get_boot_device(); // 获取当前的启动设备
| |
| |-> _env_driver_lookup(loc);
| |-> drv = ll_entry_start();
| // 查找指定存储介质的 env 加载驱动
|
|-> drv->load();
// 此处调用个存储介质的对应函数
env_ram_load(); // board/zx/m4/env_location.c
env_spinand_load(); // env/spinand.c
env_sf_load(); // env/sf.c
env_mmc_load(); // env/mmc.c
具体各种存储介质中,环境变量保存的位置可参考 存储介质上的保存 。