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键,执行用户输入命令 */ |--> ... ...程序框图如下