后初始化
24 Feb 2025
Read time: 3 minute(s)
后初始化阶段是代码重定位之后执行的初始化流程,由下面的 board_init_r
开始。
_start // arch/riscv/cpu/start.S |-> save_boot_params // arch/riscv/mach-artinchip/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();
board_init_r 函数中逐个执行函数列表 init_sequence_r
中的初始化函数。
static init_fnc_t init_sequence_r[] = { initr_trace, initr_reloc, #ifdef CONFIG_ARM initr_caches, #endif initr_reloc_global_data, initr_barrier, initr_malloc, log_init, initr_bootstage, /* Needs malloc() but has its own timer */ initr_console_record, #ifdef CONFIG_SYS_NONCACHED_MEMORY initr_noncached, #endif bootstage_relocate, #ifdef CONFIG_OF_LIVE initr_of_live, #endif #ifdef CONFIG_DM initr_dm, #endif #if defined(CONFIG_ARM) || defined(CONFIG_NDS32) || defined(CONFIG_RISCV) || \ defined(CONFIG_SANDBOX) board_init, /* Setup chipselects */ #endif stdio_init_tables, initr_serial, initr_announce, #if CONFIG_IS_ENABLED(WDT) initr_watchdog, #endif INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_NEEDS_MANUAL_RELOC initr_manual_reloc_cmdtable, #endif #ifdef CONFIG_ADDR_MAP initr_addr_map, #endif #if defined(CONFIG_BOARD_EARLY_INIT_R) board_early_init_r, #endif INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_POST initr_post_backlog, #endif INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_ARCH_EARLY_INIT_R arch_early_init_r, #endif power_init_board, #ifdef CONFIG_MTD_NOR_FLASH initr_flash, #endif INIT_FUNC_WATCHDOG_RESET #ifdef CONFIG_CMD_NAND initr_nand, #endif #ifdef CONFIG_CMD_ONENAND initr_onenand, #endif #ifdef CONFIG_MMC initr_mmc, #endif initr_env, #ifdef CONFIG_SYS_BOOTPARAMS_LEN initr_malloc_bootparams, #endif INIT_FUNC_WATCHDOG_RESET initr_secondary_cpu, #if defined(CONFIG_ID_EEPROM) || defined(CONFIG_SYS_I2C_MAC_OFFSET) mac_read_from_eeprom, #endif INIT_FUNC_WATCHDOG_RESET stdio_add_devices, initr_jumptable, #ifdef CONFIG_API initr_api, #endif console_init_r, /* fully init console as a device */ #ifdef CONFIG_DISPLAY_BOARDINFO_LATE console_announce_r, show_board_info, #endif #ifdef CONFIG_ARCH_MISC_INIT arch_misc_init, /* miscellaneous arch-dependent init */ #endif #ifdef CONFIG_MISC_INIT_R misc_init_r, /* miscellaneous platform-dependent init */ #endif INIT_FUNC_WATCHDOG_RESET interrupt_init, #ifdef CONFIG_ARM initr_enable_interrupts, #endif #ifdef CONFIG_CMD_NET initr_ethaddr, #endif #ifdef CONFIG_BOARD_LATE_INIT board_late_init, #endif #ifdef CONFIG_CMD_NET INIT_FUNC_WATCHDOG_RESET initr_net, #endif #ifdef CONFIG_POST initr_post, #endif #if defined(CONFIG_PRAM) initr_mem, #endif run_main_loop, };
其中下面几个重要的阶段需要留意。
board_init_r(); | |-> initr_dm // 初始化设备驱动,这次扫描所有的设备,并且绑定到匹配的驱动上 | |-> dm_init_and_scan(false); | |-> dm_init(IS_ENABLED(CONFIG_OF_LIVE)); // drivers/core/root.c | |-> dm_scan_platdata(pre_reloc_only=true); | |-> dm_extended_scan_fdt(gd->fdt_blob, pre_reloc_only=true); | |-> dm_scan_other(pre_reloc_only); | |-> initr_flash // SPI NOR 的初始化 | |-> flash_size = flash_init(); | |-> initr_nand // RAW NAND 的初始化 |-> initr_mmc | |-> mmc_initialize(gd->bd); | |-> initr_env | |-> env_relocate(); // env/common.c | |-> env_load(); // env/env.c | |-> stdio_add_devices(); | |-> board_late_init(); // board/artinchip/d211/d211.c |-> setup_boot_device(); |-> env_set("boot_device", "mmc");
Cache Enable
RISCV 上,U-Boot 运行在 S-Mode,没有权限开关 Cache,因此只能由 SPL 来开关 Cache。
Device Model
在后初始化阶段,会扫描所有的设备和驱动,并且将设备和对应的驱动进行绑定。
存储介质的初始化
NOR/NAND/MMC 等存储介质的驱动在这个阶段开始初始化。
环境变量加载
环境变量中保存着 U-Boot 的配置,以及相关的启动信息,此时需要从对应的存储介质中加载使用。
显示驱动
如果项目使能了 U-Boot 阶段的显示,此时在 stdio_add_devices() 中对显示和按键驱动进行初始化。
其他配置
在 board_late_init() 中,将从 SPL 传递过来的启动设备信息,更新到环境变量中,使得后续的启动脚本 可以获知当前的启动设备信息。