bootcmd 和 bootargs 环境变量

内容来自《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.5.2.pdf》

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 在前面已经说了很多次了, bootcmd 保存着 uboot 默认命令, uboot 倒计时结束以后就会执行 bootcmd 中的命令。这些命令一般都是用来启动 Linux 内核的,比如读取 EMMC 或者 NAND Flash 中的 Linux 内核镜像文件和设备树文件到 DRAM 中,然后启动 Linux 内核。可以在 uboot 启动以后进入命令行设置 bootcmd 环境变量的值。如果 EMMC 或者 NAND 中没有保存 bootcmd 的值,那么 uboot 就会使用默认的值,板子第一次运行 uboot 的时候都会使用默认值来设置 bootcmd 环境变量。打开文件 include/env_default.h,在此文件中有如下所示内容:

13 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
14 env_t environment __PPCENV__ = {
15 ENV_CRC, /* CRC Sum */
16 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
17 1, /* Flags: valid */
18 #endif
19 {
20 #elif defined(DEFAULT_ENV_INSTANCE_STATIC)
21 static char default_environment[] = {
22 #else
23 const uchar default_environment[] = {
24 #endif
25 #ifdef CONFIG_ENV_CALLBACK_LIST_DEFAULT
26 ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
27 #endif
28 #ifdef CONFIG_ENV_FLAGS_LIST_DEFAULT
29 ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
30 #endif
31 #ifdef CONFIG_BOOTARGS
32 "bootargs=" CONFIG_BOOTARGS "\0"
33 #endif
34 #ifdef CONFIG_BOOTCOMMAND
35 "bootcmd=" CONFIG_BOOTCOMMAND "\0"
36 #endif
37 #ifdef CONFIG_RAMBOOTCOMMAND
38 "ramboot=" CONFIG_RAMBOOTCOMMAND "\0"
39 #endif
40 #ifdef CONFIG_NFSBOOTCOMMAND
41 "nfsboot=" CONFIG_NFSBOOTCOMMAND "\0"
42 #endif
43 #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
44 "bootdelay=" __stringify(CONFIG_BOOTDELAY) "\0"
45 #endif
46 #if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
47 "baudrate=" __stringify(CONFIG_BAUDRATE) "\0"
48 #endif
49 #ifdef CONFIG_LOADS_ECHO
50 "loads_echo=" __stringify(CONFIG_LOADS_ECHO) "\0"
51 #endif
52 #ifdef CONFIG_ETHPRIME
53 "ethprime=" CONFIG_ETHPRIME "\0"
54 #endif
55 #ifdef CONFIG_IPADDR
56 "ipaddr=" __stringify(CONFIG_IPADDR) "\0"
57 #endif
58 #ifdef CONFIG_SERVERIP
59 "serverip=" __stringify(CONFIG_SERVERIP) "\0"
60 #endif
61 #ifdef CONFIG_SYS_AUTOLOAD
62 "autoload=" CONFIG_SYS_AUTOLOAD "\0"
63 #endif
64 #ifdef CONFIG_PREBOOT
65 "preboot=" CONFIG_PREBOOT "\0"
66 #endif
67 #ifdef CONFIG_ROOTPATH
68 "rootpath=" CONFIG_ROOTPATH "\0"
69 #endif
70 #ifdef CONFIG_GATEWAYIP
71 "gatewayip=" __stringify(CONFIG_GATEWAYIP) "\0"
72 #endif
73 #ifdef CONFIG_NETMASK
74 "netmask=" __stringify(CONFIG_NETMASK) "\0"
75 #endif
76 #ifdef CONFIG_HOSTNAME
77 "hostname=" __stringify(CONFIG_HOSTNAME) "\0"
78 #endif
79 #ifdef CONFIG_BOOTFILE
80 "bootfile=" CONFIG_BOOTFILE "\0"
81 #endif
82 #ifdef CONFIG_LOADADDR
83 "loadaddr=" __stringify(CONFIG_LOADADDR) "\0"
84 #endif
85 #ifdef CONFIG_CLOCKS_IN_MHZ
86 "clocks_in_mhz=1\0"
87 #endif
88 #if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
89 "pcidelay=" __stringify(CONFIG_PCI_BOOTDELAY)"\0"
90 #endif
91 #ifdef CONFIG_ENV_VARS_UBOOT_CONFIG
92 "arch=" CONFIG_SYS_ARCH "\0"
93 "cpu=" CONFIG_SYS_CPU "\0"
94 "board=" CONFIG_SYS_BOARD "\0"
95 "board_name=" CONFIG_SYS_BOARD "\0"
96 #ifdef CONFIG_SYS_VENDOR
97 "vendor=" CONFIG_SYS_VENDOR "\0"
98 #endif
99 #ifdef CONFIG_SYS_SOC
100 "soc=" CONFIG_SYS_SOC "\0"
101 #endif
102 #endif
103 #ifdef CONFIG_EXTRA_ENV_SETTINGS
104 CONFIG_EXTRA_ENV_SETTINGS
105 #endif
106 "\0"
107 #ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
108 }
109 #endif
110 };

第 13~23 行 , 这 段 代 码 是 个 条 件 编 译 , 由 于 没 有 定 义DEFAULT_ENV_INSTANCE_EMBEDDED 和 CONFIG_SYS_REDUNDAND_ENVIRONMENT,因此 uchar default_environment[]数组保存环境变量。

在示例代码 33.3.1.1 中指定了很多环境变量的默认值,比如 bootcmd 的默认值就是CONFIG_BOOTCOMMAND, bootargs 的默认值就是 CONFIG_BOOTARGS。我们可以在mx6ull_alientek_emmc.h 文件中通过设置宏 CONFIG_BOOTCOMMAND 来设置 bootcmd 的默认值, NXP 官方设置的 CONFIG_BOOTCOMMAND 值如下:

204 #define CONFIG_BOOTCOMMAND \
205     "run findfdt;" \
206     "mmc dev ${mmcdev};" \
207     "mmc dev ${mmcdev}; if mmc rescan; then " \
208         "if run loadbootscript; then " \
209             "run bootscript; " \
210         "else " \
211             "if run loadimage; then " \
212                 "run mmcboot; " \
213             "else run netboot; " \
214             "fi; " \
215         "fi; " \
216     "else run netboot; fi"

第 205 行, 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 设备启动。
第 208 行, 运行 loadbootscript 环境变量,此环境变量内容如下:
loadbootscript=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${script};
其中 mmcdev=1, mmcpart=1, loadaddr=0x80800000, script= boot.scr,因此展开以后就是:

loadbootscript=fatload mmc 1:1 0x80800000 boot.scr;

loadbootscript 就是从 mmc1 的分区 1 中读取文件 boot.src 到 DRAM 的 0X80800000 处。但是 mmc1 的分区 1 中没有 boot.src 这个文件,可以使用命令“ls mmc 1:1”查看一下 mmc1 分区1 中的所有文件,看看有没有 boot.src 这个文件。

第 209 行, 如果加载 boot.src 文件成功的话就运行 bootscript 环境变量, bootscript 的内容如下:

bootscript=echo Running bootscript from mmc ...;
source

因为 boot.src 文件不存在,所以 bootscript 也就不会运行。
第 211 行, 如果 loadbootscript 没有找到 boot.src 的话就运行环境变量 loadimage,环境变量loadimage 内容如下:
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
其中 mmcdev=1, mmcpart=1, loadaddr=0x80800000, image = zImage, 展开以后就是:
loadimage=fatload mmc 1:1 0x80800000 zImage
可以看出 loadimage 就是从 mmc1 的分区中读取 zImage 到内存的 0X80800000 处,而 mmc1的分区 1 中存在 zImage。

第 212 行, 加载 linux 镜像文件 zImage 成功以后就运行环境变量 mmcboot,否则的话运行netboot 环境变量。 mmcboot 环境变量如下:

154 "mmcboot=echo Booting from mmc ...; " \
155     "run mmcargs; " \
156     "if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
157         "if run loadfdt; then " \
158             "bootz ${loadaddr} - ${fdt_addr}; " \
159         "else " \
160             "if test ${boot_fdt} = try; then " \
161                 "bootz; " \
162             "else " \
163                 "echo WARN: Cannot load the DT; " \
164             "fi; " \
165         "fi; " \
166     "else " \
167         "bootz; " \
168     "fi;\0" \

第 154 行, 输出信息“Booting from mmc …”。
第 155 行, 运行环境变量 mmcargs, mmcargs 用来设置 bootargs,后面分析 bootargs 的时候在学习。
第156行, 判断boot_fdt是否为yes或者try,根据uboot输出的环境变量信息可知boot_fdt=try。因此会执行 157 行的语句。
第 157 行, 运行环境变量 loadfdt,环境变量 loadfdt 定义如下:
loadfdt=fatload mmc ${mmcdev}:${mmcpart} ${fdt_addr} ${fdt_file}
展开以后就是:
loadfdt=fatload mmc 1:1 0x83000000 imx6ull-14x14-evk.dtb

因此 loadfdt 的作用就是从 mmc1 的分区 1 中读取 imx6ull-14x14-evk.dtb 文件并放到 0x83000000处。
第 158 行,如果读取.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

NXP 官方将 CONFIG_BOOTCOMMAND 写的这么复杂只有一个目的:为了兼容多个板子,所以写了个很复杂的脚本。当我们明确知道我们所使用的板子的时候就可以大幅简化宏CONFIG_BOOTCOMMAND 的 设 置 , 比 如 我 们 要 从 EMMC 启 动 , 那 么 宏CONFIG_BOOTCOMMAND 就可简化为:

#define CONFIG_BOOTCOMMAND \
    "mmc dev 1;" \
    "fatload mmc 1:1 0x80800000 zImage;" \
    "fatload mmc 1:1 0x83000000 imx6ull-alientek-emmc.dtb;" \
    "bootz 0x80800000 - 0x83000000;"

或者可以直接在 uboot 中设置 bootcmd 的值,这个值就是保存到 EMMC 中的,命令如下:

setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ullalientek-emmc.dtb; bootz 80800000 - 83000000;'

环境变量 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 的话就需要设置此选项,指定根文件系统的类型。

你可能感兴趣的:(嵌入式Linux,驱动开发,bootcmd,bootargs,uboot,U-Boot)