内容来自《【正点原子】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 的话就需要设置此选项,指定根文件系统的类型。

bootcmd 和 bootargs 环境变量相关推荐

  1. 嵌入式系统学习笔记之五-- uboot常用命令 环境变量

    uboot 中环境变量的作用就是在不改变源码.不用重新编译的情况下,可以使我们通过设置环境变量的值来改变 uboot 的一些设置.uboot 开机时会一次性从存储介质(启动介质)中读取全部的环境变量到 ...

  2. uboot默认环境变量修改

    uboot的默认环境变量决定了系统是通过何种方式启动的,对于定制化的嵌入式系统,uboot的定制化修改也是必要的. uboot有两种修改方式: 1.直接修改源码或者修改uboot配置 2.在uboot ...

  3. 玩转u-boot之【初探环境变量env/bootcmd/bootargs】

    在linux下玩过boot的人都知道,任何一款linux下的boot程序都会有一些运行参数,也可以叫环境变量或者环境参数.比如友善之臂给mini2440开发板标配的SuperViVi这款boot程序, ...

  4. 从bootm 命令讲起/U-boot的环境变量: bootcmd 和bootargs

    从bootm 命令讲起 1 找到linux的内核入口 Bootm命令通过读取uImage的头部0×40字节的信息,将uImage定位到正确的地址,同时找到linux的内核入口地址. 这个地方就涉及到u ...

  5. 环境变量bootcmd、bootargs的参数含义

    转载于https://www.cnblogs.com/cornflower/archive/2010/03/27/1698279.html 一.U-boot的环境变量值得注意的有两个: bootcmd ...

  6. uboot的常用环境变量(bootdelay、ipaddr、serverip、gatewayip、netmask、ethaddr、bootcmd、bootargs)

    文章目录 Part1:环境变量如何参与程序运行 Part2:自动运行倒计时 Part3:网络设置 Part4:自动运行命令设置 Part5:uboot给kernel传参 Part6:新建.更改.删除一 ...

  7. uboot环境变量(设置bootargs向linux内核传递正确的参数)

    http://blog.csdn.net/workhorse/article/details/7071428 这是我uboot的环境变量设置,在该设置下可以运行initram内核(从内存下载到nand ...

  8. bootargs中的环境变量说明和一些常用的uboot命令

    bootargs中的环境变量说明和一些常用的uboot命令 一些常见的uboot命令: Help [command]在屏幕上打印命令的说明 Boom [addr]启动在内存储器的内核 Tftpboot ...

  9. uboot环境变量实现分析

    u-boot的环境变量用来存储一些经常使用的参数变量,uboot希望将环境变量存储在静态存储器中(如nand nor eeprom mmc). 其中有一些也是大家经常使用,有一些是使用人员自己定义的, ...

最新文章

  1. 几行代码就搞定高端大气的云系统架构图
  2. 在大厂干了几年开发后,太真实了。
  3. python3安卓版下载-QPython3H安卓运行Python神器
  4. 第十七次ScrumMeeting会议
  5. Oracle到出dmp
  6. Servlet3.0注解配置访问路径和urlParttern配置
  7. 199-Pycharm相关
  8. 神经网络技巧篇之寻找最优参数的方法
  9. SecureCRT连接Ubuntu,centos失败解决
  10. HUSTOJ平台的搭建
  11. PM42L-048 步进电机
  12. js 让鼠标右下角有一排小字_JS实现跟随鼠标的链接文字提示框效果
  13. mathtype左对齐
  14. 宏基因组分析步骤Linux,宏基因组分析专题研讨班
  15. VUE动态生成word
  16. Tower of Hanoi (汉诺塔问题)
  17. ImageJ Nikon_尼康“小世界”竞赛的获胜者揭示了微小的彩色世界|尼康|小世界|nikon|显微镜...
  18. 获取数组最大值和最小值的简便方法
  19. 电商服装-销售业绩大盘PPT汇报情况
  20. 海康摄像头中的SADP协议(Smart Active Device Protocol,智能活动设备协议)和ONVIF协议(Open Network Video Interface Forum)是什么?

热门文章

  1. vue openlayer单击地图事件循环多次执行_VUE生命周期函数面试题
  2. tensorflow 集成开发环境 (IDE)
  3. ajax返回一直进入error_解决ajax返回验证的时候总是弹出error错误的方法
  4. 手把手教你使用 1D 卷积和 LSTM 混合模型做 EEG 信号识别
  5. GIF发明者感染新冠后去世,没有他就没有表情包
  6. 跟百万人一起在快手学自动驾驶,是种怎样的体验?
  7. 前紫光展锐CTO创业造芯:主打边缘AI视觉,融资10亿,9个月流片
  8. FCES2021|一起来探讨“开源文化与计算机教育”,7月16日常州见
  9. AI能写出靠谱医学报告了,CVPR2021收录 | 腾讯医典出品
  10. 中文分词最佳记录刷新了,两大模型分别解决中文分词及词性标注问题丨已开源...