美文网首页嵌入式
BeagleBoneBlack的U-Boot是如何引导系统的

BeagleBoneBlack的U-Boot是如何引导系统的

作者: 外星间谍 | 来源:发表于2020-05-17 15:33 被阅读0次

    2014-8-27 10:45:11
    BeagleBoneBlack U-Boot 是如何引导系统的

    连接到开发板

    通过串口连接BeagleBone Black,参见Beagleboard:Terminal Shells
    启动到U-Boot的时候,会看到

    Hit any key to stop autoboot:0
    

    按下任意键则放弃了自动引导,从而进入了U-Boot的命令行。
    在这里你可以手动进行接下来系统的引导。但是我不会。
    虽然不会,但是用于板子上的系统有自动引导,
    我们可以分析自动引导,来了解U-Boot是如何引导系统的。


    资料

    在U-Boot的官网手册中看到了2个关键的环境变量和1个命令。
    5.10. U-Boot Environment Variables

    • bootcmd: This variable defines a command string that is automatically >executed
           when the initial countdown is not interrupted.
           This command is only executed when the variable bootdelay is also defined!
    • bootargs: The contents of this variable are
           passed to the Linux kernel
           as boot arguments (aka "command line").

    5.9.6. Environment Variables Commands

    5.9.6.4. run - run commands in an environment variable

    bootcmd中的命令就是出现“Hit any key to stop autoboot”提示后,不按任意键,会自动运行的命令。
    bootargs是传递给Linux内核的参数。
    run是运行环境变量中的命令,bootcmd中包含run命令。


    分析

    所以分析引导过程要从bootcmd开始。

    环境变量

    在U-Boot的命令行中输入printenv可显示所有的环境变量,

    U-Boot# printenv
    arch=arm
    baudrate=115200
    board=am335x
    board_name=A335BNLT
    board_rev=t\
    ue
    boot_fdt=try
    bootcmd=run findfdt; run mmcboot;setenv mmcdev 1; setenv bootpart 1:2; run mmcboot;run nandboot;
    bootcount=2
    bootdelay=1
    bootdir=/boot
    bootenv=uEnv.txt
    bootfile=zImage
    bootpart=0:2
    console=ttyO0,115200n8
    cpu=armv7
    dfu_alt_info_emmc=rawemmc mmc 0 3751936
    dfu_alt_info_mmc=boot part 0 1;rootfs part 0 2;MLO fat 0 1;MLO.raw mmc 100 100;u-boot.img.raw mmc 300 400;spl-os-args.raw mmc 80 80;spl-os-image.raw mmc 900 2000;spl-os-args fat 0 1;spl-os-image fat 0 1;u-boot.img fat 0 1;uEnv.txt fat 0 1
    dfu_alt_info_ram=kernel ram 0x80200000 0xD80000;fdt ram 0x80F80000 0x80000;ramdisk ram 0x81000000 0x4000000
    eth1addr=c8:a0:30:ac:87:2a
    ethact=cpsw
    ethaddr=c8:a0:30:ac:87:28
    fdt_high=0xffffffff
    fdtaddr=0x80F80000
    fdtfile=undefined
    findfdt=if test $board_name = A335BONE; then setenv fdtfile am335x-bone.dtb; fi; if test $board_name = A335BNLT; then setenv fdtfile am335x-boneblack.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 $fdtfile = undefined; then echo WARNING: Could not determine device tree to use; fi;
    importbootenv=echo Importing environment from mmc ...; env import -t $loadaddr $filesize
    loadaddr=0x80200000
    loadbootenv=load mmc ${mmcdev} ${loadaddr} ${bootenv}
    loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile}
    loadimage=load mmc ${bootpart} ${loadaddr} ${bootdir}/${bootfile}
    loadramdisk=load mmc ${mmcdev} ${rdaddr} ramdisk.gz
    mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype}
    mmcboot=mmc dev ${mmcdev}; if mmc rescan; then echo SD/MMC found on device ${mmcdev};if run loadbootenv; then echo Loaded environment from ${bootenv};run importbootenv;fi;if test -n $uenvcmd; then echo Running uenvcmd ...;run uenvcmd;fi;if run loadimage; then run mmcloados;fi;fi;
    mmcdev=0
    mmcloados=run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootz ${loadaddr} - ${fdtaddr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
    mmcroot=/dev/mmcblk0p2 ro
    mmcrootfstype=ext4 rootwait
    netargs=setenv bootargs console=${console} ${optargs} root=/dev/nfs nfsroot=${serverip}:${rootpath},${nfsopts} rw ip=dhcp
    netboot=echo Booting from network ...; setenv autoload no; dhcp; tftp ${loadaddr} ${bootfile}; tftp ${fdtaddr} ${fdtfile}; run netargs; bootz ${loadaddr} - ${fdtaddr}
    nfsopts=nolock
    ramargs=setenv bootargs console=${console} ${optargs} root=${ramroot} rootfstype=${ramrootfstype}
    ramboot=echo Booting from ramdisk ...; run ramargs; bootz ${loadaddr} ${rdaddr} ${fdtaddr}
    ramroot=/dev/ram0 rw ramdisk_size=65536 initrd=${rdaddr},64M
    ramrootfstype=ext2
    rdaddr=0x81000000
    rootpath=/export/rootfs
    soc=am33xx
    spiargs=setenv bootargs console=${console} ${optargs} root=${spiroot} rootfstype=${spirootfstype}
    spiboot=echo Booting from spi ...; run spiargs; sf probe ${spibusno}:0; sf read ${loadaddr} ${spisrcaddr} ${spiimgsize}; bootz ${loadaddr}
    spibusno=0
    spiimgsize=0x362000
    spiroot=/dev/mtdblock4 rw
    spirootfstype=jffs2
    spisrcaddr=0xe0000
    static_ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off
    stderr=serial
    stdin=serial
    stdout=serial
    usbnet_devaddr=c8:a0:30:ac:87:2a
    vendor=ti
    ver=U-Boot 2014.04 (May 16 2014 - 16:42:23)
    
    Environment size: 3515/131067 bytes
    U-Boot#
    

    我已经把相关的粘贴到了下面。
    为方便阅读我添加了换行。

    bootcmd

    bootcmd=
      run findfdt; 
      run mmcboot;
      setenv mmcdev 1; 
      setenv bootpart 1:2; 
      run mmcboot;
      run nandboot;
    

    提前给出结论,
    一共有6条,但通常前2条就可以启动了,
    第3条是在mmcboot失败的情况下,切换mmc设备。
    然后从新的mmc设备启动,
    如果又失败,从nand启动。

    findfdt 设置设备树文件

    findfdt=
      if test $board_name = A335BONE; 
      then 
        setenv fdtfile am335x-bone.dtb; 
      fi; 
      if test $board_name = A335BNLT; 
      then 
        setenv fdtfile am335x-boneblack.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 $fdtfile = undefined; 
      then 
        echo WARNING: Could not determine device tree to use; 
      fi;
    
    board_name=A335BNLT
    

    首先是运行findfdt中的命令,目的是通过board_name来设置fdtfile,
    结果是fdtfile的值为 am335x-boneblack.dtb。
    就是BeagleBone Black的设备树文件。


    mmcboot 从mmc启动

    接下来运行mmcboot中的命令。

    mmcboot=
      mmc dev ${mmcdev}; 
      if mmc rescan; 
      then 
        echo SD/MMC found on device ${mmcdev};
        if run loadbootenv; 
        then 
          echo Loaded environment from ${bootenv};
          run importbootenv;
        fi;
        if test -n $uenvcmd; 
        then 
          echo Running uenvcmd ...;
          run uenvcmd;
        fi;
        if run loadimage; 
        then 
          run mmcloados;
        fi;
      fi;
    
    # 相关变量
    mmcdev=0
    

    "mmc dev 0"是将设备切换到0,通常有2个设备一个是SD卡,一个是eMMC。
    mmc rescan 扫描当前mmc设备。


    loadbootenv

    loadbootenv=load mmc ${mmcdev} ${loadaddr} ${bootenv}
    
    # 相关变量
    mmcdev=0
    loadaddr=0x80200000
    bootenv=uEnv.txt
    

    这应该是从设备0的第1个分区装载uEnv.txt到地址0x80200000。
    当默认的环境变量不符合要求时,可以用uEnv.txt设置新的环境变量。
    没有它也可以,先不用管,后面说。
    如果装载成功,执行importbootenv。

    importbootenv

    importbootenv=
      echo Importing environment from mmc ...;
      env import -t $loadaddr $filesize
    

    这是把uEnv.txt中的环境变量导入到U-Boot的环境变量中。
    “filesize”没有在我的环境变量中指定。

    uenvcmd

    由于我没有“uenvcmd”这个环境变量,所以那个条件语句中的内容没有执行。
    我记着Arch Linux好像用了那个,那个变量应该在uEnv.txt中。
    于是直接到了loadimage。


    loadimage 载入Linux内核

    loadimage=load mmc ${bootpart} ${loadaddr} ${bootdir}/${bootfile}
    
    # 相关变量
    bootpart=0:2
    loadaddr=0x80200000
    bootdir=/boot
    bootfile=zImage
    

    这里和载入uEnv.txt是相似的, 都用了load命令。
    “0:2”的意思是设备0的第2个分区。
    如果不指定,为默认第一个分区,
    载入uEnv.txt时就没有指定分区。

    loadimage的目的是将Linux内核载入内存。
    到目前为止,主要做了2件事:

    • 设置设备树文件
    • 载入Linux内核

    成功后执行 mmcloados。


    mmcloados

    mmcloados=
        run mmcargs;
        if test ${boot_fdt} = yes || test ${boot_fdt} = try;
        then
            if run loadfdt;
            then
                bootz ${loadaddr} - ${fdtaddr};
            else
                if test ${boot_fdt} = try;
                then
                    bootz;
                else
                    echo WARN: Cannot load the DT;
                fi;
            fi;
        else
            bootz;
        fi;
    

    首先执行mmcargs

    mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype}
    
    # 相关变量值
    console=ttyO0,115200n8
    mmcroot=/dev/mmcblk0p2 ro
    mmcrootfstype=ext4 rootwait
    

    目的就是设置bootargs这个环境变量而已,用于向内核传递参数。

    然后判断 boot_fdt 的值决定下一步,

    # 相关变量
    boot_fdt=try
    

    判断通过,执行 loadfdt:

    loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/${fdtfile}
    
    # 相关变量
    bootpart=0:2
    fdtaddr=0x80F80000
    bootdir=/boot
    # fdtfile的值为第一步执行findfdt设置的am335x-boneblack.dtb
    

    这里载入了设备树文件,和载入Linux内核是很像的。

    至此又做了2件事:

    • 设置Linux内核启动参数
    • 载入设备树文件

    启动Linux需要的东西就齐了:

    • Linux内核启动参数
    • Linux内核文件
    • 设备树文件

    如果载入设备树成功,
    通过bootz后接2个地址就启动了系统。


    总结如下

    # 切换到启动设备
    mmc dev 0;
    # 载入Linux内核
    load mmc 0:2 0x80200000 /boot/zImage
    # 设置Linux内核启动参数
    setenv bootargs concole=ttyO0,115200n8 root=mmcroot=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait
    # 载入设备树
    load mmc 0:2 0x80F80000 /boot/am335x-boneblack.dtb
    # 启动Linux
    bootz 0x80200000 - 0x80F80000
    

    这是默认环境变量的行为。
    而我们的系统可能与其不同。这就要修改环境变量。
    我知道有2种方式,
    一种是在U-Boot的命令行中通过命令修改,
    另一种就是通过uEnv.txt了。

    uEnv.txt

    使用eEnv.txt更加方便点。就是个文本文件。
    先列出我uEnv.txt的内容,不用详细看,看我下面的说明。

    bootfile=uImage
    loadfdt=load mmc ${bootpart} ${fdtaddr} ${bootdir}/dts/${fdtfile}
    mmcloados=run mmcargs; if test ${boot_fdt} = yes || test ${boot_fdt} = try; then if run loadfdt; then bootm ${loadaddr} - ${fdtaddr}; else if test ${boot_fdt} = try; then bootz; else echo WARN: Cannot load the DT; fi; fi; else bootz; fi;
    mmcroot=/dev/mmcblk0p2 rw
    mmcargs=setenv bootargs console=${console} ${optargs} root=${mmcroot} rootfstype=${mmcrootfstype} init=/usr/lib/systemd/systemd
    
    

    一共6行,最后一行空白。

    • bootfile修改了内核名字,
    • loadfdt中只是在目录中加了“dts/”,
    • mmcloados主要是把bootz改成bootm。
    • mmcroot把只读改成了可读写。
    • mmcargs只是在后面指定了init为systemd。也有其他方法,比如在Linux系统中将init设置成指向systemd的软链接。

    U-Boot常用命令

    上面是从设备0启动系统,怎样知道自己的系统位于哪个设备呢,
    也许有某种约定,比如如果有SD卡,那么SD卡是0。
    我不知道的话,可以在U-Boot的命令行中通过命令判断。如,

    # 列出 mmc 设备。  
    U-Boot# mmc list
    OMAP SD/MMC: 0
    OMAP SD/MMC: 1
    
    # 显示当前是哪个设备。
    U-Boot# mmc dev
    mmc0 is current device
    
    # 显示当前设备的分区信息。
    U-Boot# mmc part
    
    Partition Map for MMC device 0  --   Partition Type: DOS
    
    Part    Start Sector    Num Sectors     UUID            Type
      1     2048            131072          29942d7e-01     0c Boot
      2     133120          15390720        29942d7e-02     83
    
    # 列出设备0第1个分区"/"目录的文件,我没有指定,默认为“/”。
    U-Boot# ls mmc 0:1
       100688   mlo
       308232   u-boot.img
          510   uenv.txt
    
    3 file(s), 0 dir(s)
    

    相关文章

      网友评论

        本文标题:BeagleBoneBlack的U-Boot是如何引导系统的

        本文链接:https://www.haomeiwen.com/subject/ykrsohtx.html