1. bootcmd
(Boot Command)
bootcmd
是 U-Boot 在启动时自动执行的命令序列。它决定了系统如何加载内核和根文件系统,从而完成启动过程。
204 #define CONFIG_BOOTCOMMAND \
205 "run findfdt;" \
......
216 "else run netboot; fi"
2. bootargs
(Boot Arguments)
bootargs
是传递给 Linux 内核的命令行参数,影响内核的行为。
99 "mfgtool_args=setenv bootargs console=${console},${baudrate} " \
......
111 "bootcmd_mfg=run mfgtool_args;bootz ${loadaddr} ${initrd_addr} ${fdt_addr};\0" \
uboot 中有两个非常重要的环境变量 bootcmd 和 bootargs,接下来看一下这两个环境变量。 bootcmd 和 bootagrs 是采用类似 shell 脚本语言编写的,里面有很多的变量引用,这些变量其实 都 是 环 境 变 量 , 有 很 多 是 NXP 自 己 定 义 的 。 文 件 mx6ull_alientek_emmc.h 中 的 宏 CONFIG_EXTRA_ENV_SETTINGS 保存着这些环境变量的默认值,内容如下:
113 #if defined(CONFIG_SYS_BOOT_NAND)
114 #define CONFIG_EXTRA_ENV_SETTINGS \
115 CONFIG_MFG_ENV_SETTINGS \
116 "panel=TFT43AB\0" \
117 "fdt_addr=0x83000000\0" \
118 "fdt_high=0xffffffff\0" \
......
126 "bootz ${loadaddr} - ${fdt_addr}\0"
127
128 #else
129 #define CONFIG_EXTRA_ENV_SETTINGS \
130 CONFIG_MFG_ENV_SETTINGS \
131 "script=boot.scr\0" \
132 "image=zImage\0" \
133 "console=ttymxc0\0" \
134 "fdt_high=0xffffffff\0" \
135 "initrd_high=0xffffffff\0" \
136 "fdt_file=undefined\0" \
......
194 "findfdt="\
195 "if test $fdt_file = undefined; then " \
196 "if test $board_name = EVK && test $board_rev = 9X9; then " \
197 "setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \
198 "if test $board_name = EVK && test $board_rev = 14X14; then " \
199 "setenv fdt_file imx6ull-14x14-evk.dtb; fi; " \
200 "if test $fdt_file = undefined; then " \
201 "echo WARNING: Could not determine dtb to use; fi; " \
202 "fi;\0" \
宏 CONFIG_EXTRA_ENV_SETTINGS 是个条件编译语句,使用 NAND 和 EMMC 的时候 宏 CONFIG_EXTRA_ENV_SETTINGS 的值是不同的。
bootcmd 在前面已经说了很多次了,bootcmd 保存着 uboot 默认命令,uboot 倒计时结束以 后就会执行 bootcmd 中的命令。这些命令一般都是用来启动 Linux 内核的,比如读取 EMMC 或 者 NAND Flash 中的 Linux 内核镜像文件和设备树文件到 DRAM 中,然后启动 Linux 内核。可 以在 uboot 启动以后进入命令行设置 bootcmd 环境变量的值。如果 EMMC 或者 NAND 中没有 保存 bootcmd 的值,那么 uboot 就会使用默认的值,板子第一次运行 uboot 的时候都会使用默 认值来设置 bootcmd 环境变量。
很多环境变量的默认值,比如 bootcmd 的默认值就是 CONFIG_BOOTCOMMAND,bootargs 的默认值就是 CONFIG_BOOTARGS。我们可以在 mx6ull_alientek_emmc.h 文件中通过设置宏 CONFIG_BOOTCOMMAND 来设置 bootcmd 的默认 值,NXP 官方设置的 CONFIG_BOOTCOMMAND 值。
run findfdt;使用的是 uboot 的 run 命令来运行 findfdt,findfdt 是 NXP 自行添加 的环境变量。findfdt 是用来查找开发板对应的设备树文件(.dtb)。IMX6ULL EVK 的设备树文件 为 imx6ull-14x14-evk.dtb,findfdt 内容如下:
"findfdt="\
"if test $fdt_file = undefined; then " \
"if test $board_name = EVK && test $board_rev = 9X9; then " \
"setenv fdt_file imx6ull-9x9-evk.dtb; fi; " \
"if test $board_name = EVK && test $board_rev = 14X14; then " \
"setenv fdt_file imx6ull-14x14-evk.dtb; fi; " \
"if test $fdt_file = undefined; then " \
"echo WARNING: Could not determine dtb to use; fi; " \
"fi;\0" \
findfdt 里面用到的变量有 fdt_file,board_name,board_rev,这三个变量内容如下:
fdt_file=undefined,board_name=EVK,board_rev=14X14
findfdt 做的事情就是判断,fdt_file 是否为 undefined,如果 fdt_file 为 undefined 的话那就要 根据板子信息得出所需的.dtb 文件名。此时 fdt_file 为 undefined,所以根据 board_name 和 board_rev 来判断实际所需的.dtb 文件,如果 board_name 为 EVK 并且 board_rev=9x9 的话 fdt_file 就为 imx6ull-9x9-evk.dtb。如果 board_name 为 EVK 并且 board_rev=14x14 的话 fdt_file 就设置 为 imx6ull-14x14-evk.dtb。因此 IMX6ULL EVK 板子的设备树文件就是 imx6ull-14x14-evk.dtb, 因此 run findfdt 的结果就是设置 fdt_file 为 imx6ull-14x14-evk.dtb。 第 206 行,mmc dev ${mmcdev}用于切换 mmc 设备,mmcdev 为 1,因此这行代码就是:mmc dev 1,也就是切换到 EMMC 上。 第 207 行,先执行 mmc dev ${mmcdev}切换到 EMMC 上,然后使用命令 mmc rescan 扫描 看有没有 SD 卡或者 EMMC 存在,如果没有的话就直接跳到 216 行,执行 run netboot,netboot 也是一个自定义的环境变量,这个变量是从网络启动 Linux 的。如果 mmc 设备存在的话就从 mmc 设备启动。
这也就是为什么uboot启动内核之后对应的fdt文件系统能映射到内核的原图了。
如果读取.dtb 文件成功的话那就调用命令 bootz 启动 linux,调用方法如下:
bootz ${loadaddr} - ${fdt_addr};
bootz 0x80800000 - 0x83000000 (注意‘-’前后要有空格)
至此 Linux 内核启动,如此复杂的设置就是为了从 EMMC 中读取 zImage 镜像文件和设备 树文件。经过分析,浓缩出来的仅仅是 4 行精华:
mmc dev 1 //切换到 EMMC
fatload mmc 1:1 0x80800000 zImage //读取 zImage 到 0x80800000 处
fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb //读取设备树到 0x83000000 处
bootz 0x80800000 - 0x83000000 //启动 Linux
环境变量 bootargs
bootargs 保存着 uboot 传递给 Linux 内核的参数,在上一小节讲解 bootcmd 的时候说过, bootargs 环境变量是由 mmcargs 设置的,mmcargs 环境变量如下:
mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}
其中 console=ttymxc0,baudrate=115200,mmcroot=/dev/mmcblk1p2 rootwait rw,因此将 mmcargs 展开以后就是:
mmcargs=setenv bootargs console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw
可以看出环境变量 mmcargs 就是设置 bootargs 的值为“console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw”,bootargs 就是设置了很多的参数的值,这些参数 Linux 内核会使 用到,常用的参数有:
1、console console 用来设置 linux 终端(或者叫控制台),也就是通过什么设备来和 Linux 进行交互,是 串口还是 LCD 屏幕?如果是串口的话应该是串口几等等。一般设置串口作为 Linux 终端,这样 我们就可以在电脑上通过 SecureCRT 来和 linux 交互了。这里设置 console 为 ttymxc0,因为 linux 启动以后 I.MX6ULL 的串口 1 在 linux 下的设备文件就是/dev/ttymxc0,在 Linux 下,一切皆文 件。 ttymxc0 后面有个“,115200”,这是设置串口的波特率,console=ttymxc0,115200 综合起来就是设置 ttymxc0(也就是串口 1)作为 Linux 的终端,并且串口波特率设置为 115200。
2、root root 用来设置根文件系统的位置,root=/dev/mmcblk1p2 用于指明根文件系统存放在 mmcblk1 设备的分区 2 中。EMMC 版本的核心板启动 linux 以后会存在/dev/mmcblk0、 /dev/mmcblk1、/dev/mmcblk0p1、/dev/mmcblk0p2、/dev/mmcblk1p1 和/dev/mmcblk1p2 这样的文 件,其中/dev/mmcblkx(x=0~n)表示 mmc 设备,而/dev/mmcblkxpy(x=0~n,y=1~n)表示 mmc 设备 x 的分区 y。在 I.MX6U-ALPHA 开发板中/dev/mmcblk1 表示 EMMC,而/dev/mmcblk1p2 表示 EMMC 的分区 2。 root 后面有“rootwait rw”,rootwait 表示等待 mmc 设备初始化完成以后再挂载,否则的话 mmc 设备还没初始化完成就挂载根文件系统会出错的。rw 表示根文件系统是可以读写的,不加 rw 的话可能无法在根文件系统中进行写操作,只能进行读操作。
3、rootfstype 此选项一般配置 root 一起使用,rootfstype 用于指定根文件系统类型,如果根文件系统为 ext 格式的话此选项无所谓。如果根文件系统是 yaffs、jffs 或 ubifs 的话就需要设置此选项,指 定根文件系统的类型。 bootargs 常设置的选项就这三个,后面遇到其他选项的话再讲解。