U-Boot中Distro_bootcmd的实现分析

Distro Boot

Distro Bootcmd 是U-Boot中设计的一种启动机制,用来自适应各种不同的启动媒介,并从中找到可用的启动镜像然后启动,具体实现逻辑如下:

  1. 板级自定义启动设备

    #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 
    
  2. BOOT TARGETS
    U-Boot中Distro_bootcmd的实现分析_第1张图片

  3. 定义启动环境变量
    U-Boot中Distro_bootcmd的实现分析_第2张图片

从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
    在这里插入图片描述

你可能感兴趣的:(U-Boot)