U-Boot2017.01的启动过程比较复杂,本文分为6部分讲述,笔者将主要过程和函数调用关系整理成一个文档方便查看,文档链接为
U-Boot2017.01启动过程分析pdf
U-Boot2017.01源码分析及启动命令解析
启动过程6部分内容如下
01-U-Boot2017.01 启动过程概述
02-U-Boot2017.01 SPL阶段分析
03-U-Boot2017.01 U-Boot阶段分析
04-U-Boot2017.01 加载内核过程
05-U-Boot2017.01 bootz加载过程
06-U-Boot2017.01 读取uEnv.txt过程
U-Boot启动阶段函数调用关系如下
/* u-boot阶段 */
u-boot.lds(board/ti/am335x/u-boot.lds)
|--> vectors.S(arch/arm/lib/vectors.S)
|--> start.S(arch/arm/cpu/armv7/start.S)
... ...
|--> _main(arch/arm/lib/crt0.S )
|--> board_init_f_alloc_reserve(common/init/board_init.c) /* 为u-boot的gd结构体分配空间 */
|--> board_init_f_init_reserve(common/init/board_init.c) /* 将gd结构体清零 */
|--> board_init_f(common/board_f.c) /* 将gd结构体清零 */
|--> initcall_run_list(init_sequence_f) (lib/initcall.c)
|--> init_sequence_f[](common/board_f.c) /* 函数指针数组 */
|--> /* 初始化各种外设,比如使能看门狗,串口打印,控制台,并保存板子信息到gd等等 */
|--> relocate_code(arch\arm\lib\relocate.S) /* 运行 relocate_vectors,实现uboot代码的重定位 */
|--> board_init_r(common/board_r.c)
|--> initcall_run_list(init_sequence_r) (lib/initcall.c) /* 遍历数组,一系列初始化 */
|--> initr_reloc(common/board_r.c) /* 设置 gd->flag表示relocation完成 */
|--> board_init(board/ti/am335x/board.c) /* 初始化看门狗,可选使能gpmc和PRU* */
|--> efi_memory_init(lib/efi_loader/efi_memory.c)
|--> interrupt_init(arch/arm/lib/interrupts.c) /* 初始化中断 */
|--> run_main_loop(common/board_r.c)
|--> main_loop(common/main.c)
|--> setenv("ver", version_string) /* 设置版本变量 */
|--> version_string[](cmd/version.c) /* u-boot版本号,编译日期和时间,以及时间区 */
|--> #define U_BOOT_VERSION_STRING U_BOOT_VERSION(include/version.h)
|--> run_preboot_environment_command(common/main.c) /* 从环境变量中获取"preboot"的定义,一般环境变量中不包含该项配置 */
|--> bootdelay_process(common/autoboot.c) /* 从环境变量中取出"bootdelay"和"bootcmd"的配置值 */
|--> s = getenv("bootcmd")(common/autoboot.c)
|--> "bootcmd=" CONFIG_BOOTCOMMAND "\0" /* include/configs/platinum.h */
|--> #define CONFIG_BOOTCOMMAND \ /* include/configs/am335x_evm.h */
"if test ${boot_fit} -eq 1; then " \ /* include/configs/ti_armv7_common.h boot_fit = 0 */
"run update_to_fit;" \ /* 不执行 */
"fi;" \
"run findfdt; " \
"run init_console; " \
"run envboot; " \
"run distro_bootcmd"
|--> "findfdt="\ /* include/configs/am335x_evm.h */
"if test $board_name = A335BONE; then " \ /* (board/ti/am335x/board.h) board_ti_is("A335BONE") */
"setenv fdtfile am335x-bone.dtb; fi; " \
"if test $board_name = A335BNLT; then " \
"setenv fdtfile am335x-boneblack.dtb; fi; " \
"if test $board_name = BBG1; then " \
"setenv fdtfile am335x-bonegreen.dtb; fi; " \
"if test $board_name = A33515BB; then " \
"setenv fdtfile am335x-evm.dtb; fi; " \
"if test $board_name = A335X_SK; then " \
"setenv fdtfile am335x-evmsk.dtb; fi; " \
"if test $board_name = A335_ICE; then " \
"setenv fdtfile am335x-icev2.dtb; fi; " \
"if test $fdtfile = undefined; then " \
"echo WARNING: Could not determine device tree to use; fi; \0" \
|--> "init_console=" \ /* include/configs/am335x_evm.h */
"if test $board_name = A335_ICE; then "\
"setenv console ttyO3,115200n8;" \
"else " \
"setenv console ttyO0,115200n8;" \
"fi;\0" \
|--> "envboot=mmc dev ${mmcdev}; " \ /* include/environment/ti/mmc.h */
"if mmc rescan; then " \
"echo SD/MMC found on device ${mmcdev};" \
"if run loadbootscript; then " \
"run bootscript;" \
"else " \
"if run loadbootenv; then " \
"echo Loaded env from ${bootenvfile};"
"run importbootenv;" \
"fi;" \
"if test -n $uenvcmd; then " \
"echo Running uenvcmd ...;" \
"run uenvcmd;" \
"fi;" \
"fi;" \
"fi;\0" \
|--> "distro_bootcmd=" BOOTENV_SET_SCSI_NEED_INIT
"for target in ${boot_targets}; do "
"run bootcmd_${target}; "
"done\0" /* include/config_distro_bootcmd.h */
|--> #define BOOTENV_SET_SCSI_NEED_INIT "setenv scsi_need_init;"
|--> autoboot_command(common/autoboot.c) /* 倒计时按下执行,没有操作执行bootcmd的参数 */
|--> ... ...
|--> cli_loop(common/cli.c) /* 倒计时按下space键,执行用户输入命令 */
|--> ... ...
程序框图如下