一、什么是bootcmd?
bootcmd 是 U-Boot 的环境变量,不是一个函数,它里面存的是一条 / 多条待自动执行的 shell 命令字符串,是自动启动内核的核心配置。
二、bootcmd从哪里来?
有 3 个来源,优先级从高到低
1、Flash 里保存的环境变量(最高)
保存在 eMMC/SPINOR 的 env 分区,printenv bootcmd 看到的就是这个;
可以用 setenv bootcmd xxx; saveenv 修改并固化。
2、代码里默认配置 CONFIG_BOOTCOMMAND(次高)
宏:
#define CONFIG_BOOTCOMMAND "mmc read 0x40000000 0x800 0x800; booti 0x40000000 - 0x48000000"
如果 Flash 里没有保存 bootcmd,U-Boot 启动时 env_get ("bootcmd") 就会读到这个宏定义的字符串。
3、板级代码动态覆盖(很少用)
board_init 里用 env_set 动态赋值,项目里一般不用,不利于调试。
配套变量
bootdelay控制是否执行 bootcmd。
- bootdelay > 0:倒计时,按键打断就进 CLI,不跑 bootcmd
- bootdelay = 0:不等待,直接执行 bootcmd(量产用的配置)
- bootdelay = -1:永远不自动执行 bootcmd,直接进命令行
三、 bootcmd什么时候被调用?
完整调用链路
main_loop()
→ bootdelay_process()
→ env_get("bootcmd") // 取出bootcmd字符串
→ autoboot_command( s ) // s就是bootcmd字符串
→ abortboot(stored_bootdelay) // 判断有没有被按键打断
→ 如果没打断:run_command_list(s, -1, 0)
→ Hush parser 解析分号; 分隔多条命令
→ 逐条查找cmd_table、cmd_process、cmd_call、do_booti
→ 最终 booti 拉起内核
关键点:
① bootcmd 只是字符串,U-Boot 本身不会解析它;交给 Hush 解析器做分词、按顺序执行。
② 分号";"是 Hush 的命令分隔符:前一条执行完,再执行下一条。
mmc read 0x40000000 0x800 0x800; booti 0x40000000 - 0x48000000
拆成两条:
1、mmc read 0x40000000 0x800 0x800:
从 eMMC 块 0x800,读 0x800 个 block,读到 DDR 地址 0x40000000(Image 内核镜像)
2、booti 0x40000000 - 0x48000000:booti 内核地址 initrd 地址 设备树地址
- 代表没有 initramfs

四、 bootcmd调试相关命令
# 查看当前bootcmd
printenv bootcmd
# 临时修改(掉电丢失,适合调试)
setenv bootcmd "mmc read 0x40000000 0x800 0x800; booti 0x40000000 - 0x48000000"
# 保存到eMMC env分区(固化)
saveenv
# 清空bootcmd,自动启动就失效了
setenv bootcmd; saveenv
