3.10.2. 加载内核

本节介绍 ZX 平台从存储介质中加载内核和启动的流程。

U-Boot 中启动所需的数据,以及启动内核通过命令行来实现,一系列的命令组成启动脚本。

ZX 的方案中,相关的启动脚本在 env.txt 环境变量中提供,并且最终由变量 autoboot= 串在一起。

U-Boot 在执行自动启动时,首先读取和执行环境变量 bootcmd 的内容,bootcmd 被设置为 run autoboot

3.10.2.1. autoboot

autoboot 变量的内容被设置为一个启动命令脚本。该脚本通过检测当前的启动存储介质类型 来执行不同的内核加载和启动命令。

例如:

autoboot=if test ${boot_device} = nand; then \
                run nand_boot; \
        elif test ${boot_device} = nor; then \
                run nor_boot; \
        elif test ${boot_device} = mmc; then \
                if test $? -eq 1; then \
                        echo "Run sd card upgrade program"; \
                        aicupg mmc 1; \
                fi; \
                if test $? -eq 1; then \
                        echo "Run sd card fat32 upgrade program"; \
                        aicupg fat mmc 1; \
                fi; \
                run mmc_boot; \
        elif test ${boot_device} = usb; then \
                echo "Run USB upgrade program"; \
                aicupg usb 0; \
        fi; \
    if test $? -eq 1; then \
                echo "Try NFS boot ..."; \
            run nfs_boot; \
    fi
bootcmd=run autoboot;

3.10.2.2. MMC 启动脚本

无论是 SD 卡还是 eMMC,ZX 平台上都采用 GPT 的方式对存储空间进行分区。 Kernel 以及 DTB 都存放在单独的分区中,U-Boot 通过分区名字读取指定分区的内容。

mmc_boot=echo "Try to boot from MMC..."; \
         run set_mmc_args; \
         mmc dev ${boot_devnum}; \
         run mmc_loaddtb; \
         run mmc_loadknl; \
         booti ${knl_addr} - ${dtb_addr};

上述启动脚本中,通过 U-Boot 已有的命令对 MMC 设备进行数据读取,加载内核和 DTB 数据。

其中 MMC 的设备 ID boot_devnum 通过 BROM/SPL 传递的参数信息来获取,并在 board_late_init() 被调用时修改到环境变量 boot_devnum 中。

Kernel 和 DTB 相关的加载地址 knl_addr, dtb_addrenv.txt 中根据项目实际情况进行设置。

其他使用到的命令可参考源码:

  • cmd/mmc.c

  • cmd/bootm.c

  • cmd/booti.c

  • cmd/booti32.c

3.10.2.3. SPI NAND 启动脚本

对于使用 NAND 的项目,Kernel 和 DTB 保存的方式可能是 MTD 分区,或者 UBI Volume, 具体项目根据需要进行选择。

Kernel 保存在 MTD 分区

对于使用 MTD 分区保存 Kernel 和 DTB 的项目,在启动脚本中,使用 MTD 命令加载对应的分区内容。

nand_boot=echo "Try to boot from nand flash..."; \
          run set_nand_args; \
          setenv nand_boot_mtdparts_cnt 7; \
          mtd read kernel ${knl_addr} 0 0x590000; \
          mtd read dtb ${dtb_addr} 0 0x6000; \
          booti ${knl_addr} - ${dtb_addr};

Kernel 保存在 UBI

对于使用 UBI Volume 保存 Kernel 和 DTB 的项目,在启动脚本中,使用 UBI 命令加载对应的分区内容。

nand_boot=echo "Try to boot from nand flash..."; \
          run set_nand_args; \
          setenv nand_boot_mtdparts_cnt 5; \
          ubi part ubiboot; \
          ubi read ${knl_addr} kernel && ubi read ${dtb_addr} dtb; \
          booti ${knl_addr} - ${dtb_addr};

这里将 MTD 分区 ubiboot 做成 UBI 设备,然后在该 UBI 设备中划分 kerneldtb 两个 Volume。在操作 UBI Volume 前,必须先使用 ubi part Attach 对应的 MTD 分区。

Kernel 和 DTB 相关的加载地址 knl_addr, dtb_addr 在 env.txt 中根据项目实际情况进行设置。

其他使用到的命令可参考源码:

  • cmd/mtd.c

  • cmd/ubi.c

  • cmd/bootm.c

  • cmd/booti.c

  • cmd/booti32.c

3.10.2.4. SPI NOR 启动脚本

对于使用 SPI NOR 的项目,使用 MTD 分区的方式保存 Kernel 和 DTB,执行 NOR 启动时首先初始化相关的 NOR 分区,然后使用 MTD 命令读取分区的内容。

nor_boot=echo "Try to boot from nor flash..."; \
         sf probe; \
         run set_nor_args; \
         mtd read kernel ${knl_addr} 0 0x500000 && mtd read dtb ${dtb_addr} 0 0x20000; \
         booti ${knl_addr} - ${dtb_addr};

此处读取的分区内容大小可根据项目的具体需要进行设定。

Kernel 和 DTB 相关的加载地址 knl_addr, dtb_addr 在 env.txt 中根据项目实际情况进行设置。

其他使用到的命令可参考源码:

  • cmd/mtd.c

  • cmd/bootm.c

  • cmd/booti.c

  • cmd/booti32.c