Distro Boot
Distro Bootcmd 是U-Boot中设计的一种启动机制,用来自适应各种不同的启动媒介,并从中找到可用的启动镜像然后启动,具体实现逻辑如下:
板级自定义启动设备
#define BOOT_TARGET_DEVICES(func) \
func(MMC, mmc, 0) \
func(MMC, mmc, 1) \
func(USB, usb, 0) \
func(PXE, pxe, na) \
func(DHCP, dhcp, na)
#include
从3.H可以看到,distro_bootcmd是一个循环,针对每一个$(boot_targets)运行对应的bootcmd_$(target)。这其间只要有任何一个命令运行成功,就会启动系统,后面的命令不会再运行,否则继续运行后面的命令。
$(boot_targets)是什么
3.B中,宏BOOTENV_BOOT_TARGETS。
该宏定义的原型在2.E中:
#define BOOTENV_DEV_NAME(devtypeu, devtypel, instance) \
BOOTENV_DEV_NAME_##devtypeu(devtypeu, devtypel, instance)
#define BOOTENV_BOOT_TARGETS \
"boot_targets=" BOOT_TARGET_DEVICES(BOOTENV_DEV_NAME) "\0"
宏BOOT_TARGET_DEVICES在1中的板级自定义启动设备定义,将其带入,则BOOTENV_BOOT_TARGETS展开为:
boot_targets = BOOTENV_DEV_NAME(MMC, mmc, 0) \
BOOTENV_DEV_NAME(MMC, mmc, 1) \
BOOTENV_DEV_NAME(USB, usb, 0) \
BOOTENV_DEV_NAME(PXE, pxe, na) \
BOOTENV_DEV_NAME(DHCP, dhcp, na)
根据:
#define BOOTENV_DEV_NAME(devtypeu, devtypel, instance) \
BOOTENV_DEV_NAME_##devtypeu(devtypeu, devtypel, instance)
这个宏里面有个看着比较奇怪的命名,devtypeu、devtypel,结合宏定义的形式,我猜测这里的u代表upper(大写),l代表lower(小写)的意思。
所以上面的boot_targets可以进一步展开:
boot_targets = BOOTENV_DEV_NAME_MMC(MMC, mmc, 0) \
BOOTENV_DEV_NAME_MMC(MMC, mmc, 1) \
BOOTENV_DEV_NAME_USB(USB, usb, 0) \
BOOTENV_DEV_NAME_PXE(PXE, pxe, na) \
BOOTENV_DEV_NAME_DHCP(DHCP, dhcp, na)
后续的继续展开分析我们只以mmc 0为例,其他的mmc 1,usb,pxe,dhcp的展开原理相同。
根据2.D:
#define BOOTENV_DEV_NAME_MMC BOOTENV_DEV_NAME_BLKDEV
boot_targets可以继续展开:
boot_targets = BOOTENV_DEV_NAME_BLKDEV(MMC, mmc, 0) \
BOOTENV_DEV_NAME_BLKDEV(MMC, mmc, 1) \
BOOTENV_DEV_NAME_BLKDEV(USB, usb, 0) \
BOOTENV_DEV_NAME_PXE(PXE, pxe, na) \
BOOTENV_DEV_NAME_DHCP(DHCP, dhcp, na)
根据2.C:
#define BOOTENV_DEV_NAME_BLKDEV(devtypeu, devtypel, instance) \
#devtypel #instance " "
boot_targets最终展开为:
boot_targets = mmc0 mmc 1 usb0 pxe dhcp
所以对于这些boot_targets最终的启动命令bootcmd_$(target)分别为:bootcmd_mmc0, bootcmd_mmc1,
bootcmd_usb0, bootcmd_pxe, bootcmd_dhcp。
下面进一步分析bootcmd_mmc0来自哪里:
3.G中有宏BOOT_TARGET_DEVICES(BOOTENV_DEV) 结合BOOT_TARGET_DEVICES在1中的定义展开,如下:
BOOTENV_DEV(MMC, mmc, 0) \
BOOTENV_DEV(MMC, mmc, 1) \
BOOTENV_DEV(USB, usb, 0) \
BOOTENV_DEV(PXE, pxe, na) \
BOOTENV_DEV(DHCP, dhcp, na)\
2.F中BOOTENV_DEV的宏定义如下:
#define BOOTENV_DEV(devtypeu, devtypel, instance) \
BOOTENV_DEV_##devtypeu(devtypeu, devtypel, instance)
所以可以继续展开:
BOOTENV_DEV_MMC(MMC, mmc, 0) \
BOOTENV_DEV_MMC(MMC, mmc, 1) \
BOOTENV_DEV_USB(USB, usb, 0) \
BOOTENV_DEV_USB(PXE, pxe, na) \
BOOTENV_DEV_DHCP(DHCP, dhcp, na)\
根据2.D:
#define BOOTENV_DEV_MMC BOOTENV_DEV_BLKDEV
进一步展开:
BOOTENV_DEV_BLKDEV(MMC, mmc, 0) \
BOOTENV_DEV_BLKDEV(MMC, mmc, 1) \
BOOTENV_DEV_BLKDEV(USB, usb, 0) \
BOOTENV_DEV_DHCP(PXE, pxe, na) \
BOOTENV_DEV_DHCP(DHCP, dhcp, na)\
根据2.B:
#define BOOTENV_DEV_BLKDEV(devtypeu, devtypel, instance) \
"bootcmd_" #devtypel #instance "=" \
"setenv devnum " #instance "; " \
"run " #devtypel "_boot\0"
这里以mmc0为例,带入,则得到bootcmd_mmc0:
bootcmd_mmc0 = "setenv devnum 0"; " \
"run mmc_boot\0"
这里又引入了mmc_boot这命令,它来自何方:
3.A中定义了宏BOOTENV_SHARED_MMC ,根据2.D:
#define BOOTENV_SHARED_MMC BOOTENV_SHARED_BLKDEV(mmc)
带入2.A:
#define BOOTENV_SHARED_BLKDEV_BODY(devtypel) \
"if " #devtypel " dev ${devnum}; then " \
"setenv devtype " #devtypel "; " \
"run scan_dev_for_boot_part; " \
"fi\0"
#define BOOTENV_SHARED_BLKDEV(devtypel) \
#devtypel "_boot=" \
BOOTENV_SHARED_BLKDEV_BODY(devtypel)
得到mm_boot命令如下:
mmc_boot ="if mmc dev ${devnum}; then " \
"setenv devtype mmc "; " \
"run scan_dev_for_boot_part; " \
"fi\0"
scan_dev_for_boot_part来自3.F, 后面的分析就很容易了。
把上面分析理清楚后,在u-boot启动的时候可以中断u-boot启动流程(一般是按键盘上的任意按键,或者空格键,也有的需要按Ctrl + C)进入u-boot命令行,输入printenv命令,就能看到上面分析的各个变量或者命令的内容。
原创博文,转载请著名出处,欢迎关注博主公众号:HackforFun