U-Boot 支持通过 环境变量 进行用户配置,这些变量可以通过保存到持久化存储设备(例如闪存)而实现持久化。
- 环境变量(Environment Variables) 本质是
键值对(key-value),是 U-Boot 中一种轻量级的配置机制,类似于 shell 中的环境变量,但专为嵌入式启动阶段设计。 - 持久化(persistent): U-Boot 启动时运行在 RAM 中,若不保存,所有修改都会在重启后丢失。
环境变量通过 env set(别名为 setenv)设置,通过 env print(别名为 printenv)打印,并通过 env save(别名为 saveenv)保存到持久化存储中。
env set若不带值,可用于从环境中删除一个变量。- 只要尚未执行保存操作,你所操作的始终是内存中的副本 (通常是
gd->env_addr指向的缓冲区)。 - 万一包含环境变量的 Flash 区域被意外擦除,U-Boot 会提供一个默认环境(自动回退到编译时内嵌的默认环境)。
- 保留旧命令(如
setenv)是为了向后兼容。现代 U-Boot 推荐使用统一前缀env xxx,体现模块化命令设计思想。 - 在 U-Boot 命令行中输入
help env可以查看env命令详细说明。
部分配置 由环境变量控制,因此通过设置这些变量即可调整 U-Boot 的行为(例如自动启动延时、从 TFTP 自动加载等)。
在量产设备中,应考虑锁定环境变量(通过 CONFIG_ENV_IS_NOWRITE 或硬件写保护),防止恶意篡改启动参数。
基于文本文件定义环境变量
U-Boot 中 基于 文本文件(.env 文件)定义默认环境变量的机制,这是现代 U-Boot(特别是 v2021.10 之后)推荐的、更清晰可维护的默认环境配置方式。
一个开发板的默认环境变量是通过一个采用简单文本格式的 .env 环境文件创建的。该文件的基础文件名由 CONFIG_ENV_SOURCE_FILE 宏定义;若该宏为空,则使用 CONFIG_SYS_BOARD。
该文件必须位于开发板对应的目录下,并具有 .env 扩展名。
-
旧的定义环境变量的方式是在 C 源码中(下一节会讲到),但配置 ≠ 代码,环境变量属于"系统策略",应与"实现逻辑"解耦。使用纯文本文件便于版本控制、差异对比、非程序员参与(如测试工程师修改启动参数)。
-
CONFIG_ENV_SOURCE_FILE是优先选项,允许项目自定义文件名(如 my_custom.env);若未定义,则回退到以板级名称(CONFIG_SYS_BOARD)命名的文件,保证通用性。最终的文件路径为:htmlboard/<vendor>/<board>/<CONFIG_ENV_SOURCE_FILE>.env 或者: board/<vendor>/<board>/<CONFIG_SYS_BOARD>.env -
构建系统(Makefile/Kbuild)会在编译时自动查找该路径下的
.env文件,并通过脚本(如tools/env2text.py)将其转换为 C 数组嵌入固件。所以这些版本的 U-Boot 编译会用到 Python。
.env 文件是一个纯文本文件,你可以在其中以 var=value 的形式编写环境变量。支持空行和多行变量。转换脚本会查找那些从第 1 列开始、紧随其后是一个字符串、且该字符串后立即跟一个等号(=)的行。等号前不允许有空格。建议对脚本内容进行缩进,使得只有形如 var= 的部分出现在行首。比如:
bash
mmcboot=
echo Booting from mmc ...;
run mmcargs;
if test ${sec_boot} = yes; then
if run true; then
run boot_os;
else
echo ERR: failed to authenticate;
fi;
若要向一个变量追加额外文本,可使用 var+=value 语法。该文本会在构建(make)过程中被合并到该变量中,并以单一值的形式提供给 U-Boot。
.env 文件支持 C 风格注释。支持空行和多行变量,并且还可以使用标准的 C 预处理器指令以及来自板级配置的 CONFIG_ 宏定义。
例如,对于 snapper9260 开发板,你需要创建一个名为 board/bluewater/snapper9260.env 的文本文件,其中包含环境变量内容。
bash
stdout=serial
#ifdef CONFIG_VIDEO
stdout+=,vidconsole
#endif
bootcmd=
/* U-Boot script for booting */
if [ -z ${tftpserverip} ]; then
echo "Use 'setenv tftpserverip a.b.c.d' to set IP address."
fi
usb start; setenv autoload n; bootp;
tftpboot ${tftpserverip}:
bootm
failed=
/* Print a message when boot fails */
echo CONFIG_SYS_BOARD boot failed - please check your image
echo Load address is CONFIG_SYS_LOAD_ADDR
对于一组开发板共用的配置,可以使用 #include 指令引入位于 include/env 目录下的公共文件,该文件包含环境变量设置。例如:
c
#include <env/ti/mmc.env>
U-Boot 不会自动去除引号 !!!环境变量值本身不需引号,U-Boot 内部按字符串处理。
比如在 .config 中定义了配置选项:
bash
CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-pcduino3"
则:
bash
fdtfile=CONFIG_DEFAULT_DEVICE_TREE.dtb
会被拼接为:
bash
fdtfile="sun7i-a20-pcduino3.dtb"
因为有引号,U-Boot 在加载设备树时会因找不到带引号的文件名而失败!
目前没有通用的方法可以去除引号。
旧式基于 C 语言定义环境变量
传统上,默认环境变量在 include/env_default.h 中创建,并可通过各种 CONFIG 宏定义进行扩展。
-
U-Boot 早期将默认环境变量硬编码为一个 C 字符串数组,位于
include/env_default.h。例如:c#define DEFAULT_ENVIRONMENT \ "bootdelay=2\0" \ "baudrate=115200\0" \ CONFIG_EXTRA_ENV_SETTINGS\ "\0"
特别地,你可以在板级文件中定义 CONFIG_EXTRA_ENV_SETTINGS 来添加环境变量。
-
CONFIG_EXTRA_ENV_SETTINGS是一个 宏拼接点,通常在板级头文件(如include/configs/myboard.h)中定义:c#define CONFIG_EXTRA_ENV_SETTINGS\ "fdtfile=myboard.dtb\0" \ "bootcmd=run mmcboot\0"
鼓励板级维护者迁移到基于文本的环境变量方式,因其更易于维护。旧式基于 C 语言缺点是:
- 配置与代码耦合
- 字符串拼接易出错(漏 \0、引号不匹配等)。
- 无法使用注释、条件编译复杂逻辑受限。
"distro-board" 脚本目前仍依赖旧式环境变量,因此请改用 "Standard Boot" 方案。
- "distro-board" 脚本:指 U-Boot 的
tools/distro_bootcmd.h机制,用于实现类似 Linux 发行版的通用启动流程(自动探测 SD/eMMC/USB/NFS 等)。该机制内部依赖CONFIG_EXTRA_ENV_SETTINGS注入distro_bootcmd变量。(目前已淘汰) - "Standard Boot":指开发者自行定义
bootcmd等变量(通常通过.env文件),而非依赖发行版兼容模式。
如果同时定义 了基于文本的环境变量文件和旧式 C 语言环境变量,则旧式 C 环境中的变量将覆盖文本文件中设置的同名变量。
环境变量列举
某些设备 配置选项 可通过 环境变量 进行设置。在许多情况下,默认环境中的变量值来源于某个 CONFIG 宏定义------详情请参见 include/env_default.h。
autostart:加载镜像后自动启动
若其值为真,通过 xxx-boot 命令加载的镜像将自动启动。
-
若
autostart是以1、y、Y、t或T开头的字符串,比如 "y"、"yes"、"t"、"true",则为真,否则为假。 -
如果变量不存在,返回 -1。注意,-1 在 C 中表示真,也就是说:如果不定义这个变量,则默认为真 。
cint env_get_yesno(const char *var) { char *s = env_get(var); if (s == NULL) return -1; return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ? 1 : 0; } -
xxx-boot是一系列加载镜像并具备启动意图 的命令,它们是:bootelf------ 从内存中的 ELF 镜像启动bootp------ 通过 BOOTP/TFTP 协议从网络启动镜像dhcp------ 通过 DHCP/TFTP 协议从网络启动镜像diskboot------ 从 IDE 设备启动nboot------ 从 NAND 设备加载镜像nfs------ 通过 NFS 协议从网络启动镜像rarpboot------ 通过 RARP/TFTP 协议从网络启动镜像scsiboot------ 从 SCSI 设备启动tftpboot------ 通过 TFTP 协议从网络启动镜像usbboot------ 从 USB 设备启动
注意:
loadb、loadx、loady等纯加载命令 不受autostart影响,因为它们仅用于传输数据,无启动语义。 -
技术原理:在
xxx-boot命令内部,U-Boot 首先下载镜像到指定位置,然后检查autostart,若为真,则立即执行bootm ${addr}
baudrate:波特率
用于设置 UART 的波特率------其默认值为 CONFIG_BAUDRATE(该宏默认为 115200)。
bootdelay:启动延时
c
#ifndef CONFIG_BOOTDELAY
#define CONFIG_BOOTDELAY 1 // mx6_common.h
#endif
"bootdelay=" __stringify(CONFIG_BOOTDELAY) // env_default.h
在自动执行 bootcmd 之前等待的延时(单位:秒)。在此期间,用户可选择进入命令行 shell(若启用了 CONFIG_AUTOBOOT_MENU_SHOW=y,则显示启动菜单):
- 设为 0:无延时自动启动镜像,但可通过按键中断;
- 设为 -1:完全禁用自动启动镜像,会进入 U-Boot 的 Shell,常用于测试;
- 设为 -2:无延时自动启动镜像,且不检测任何中断请求。
默认值由 CONFIG_BOOTDELAY 定义。若启用了 CONFIG_OF_CONTROL=y,则设备树中 /config/bootdelay 节点的值会覆盖此环境变量。
bootcmd:启动命令
若用户在 启动延时 期间未进入 shell,则执行此命令。通常是一条或多条命令组成的脚本,是 整个启动链的"最后一公里",连接 bootloader 与操作系统。例如:
-
使用使用文本文件定义环境变量
bash// 定义在 .env 文件中 mmcboot= mmc dev 0; fatload mmc 0:1 ${kernel_addr_r} Image; fatload mmc 0:1 ${fdt_addr_r} myboard.dtb; booti ${kernel_addr_r} - ${fdt_addr_r} bootcmd=run mmcboot -
使用旧式 C 语言定义环境变量
c"bootcmd=" CONFIG_BOOTCOMMAND // env_default.h #define CONFIG_BOOTCOMMAND \ // mx6ullevk.h "run findfdt;" \ "mmc dev ${mmcdev};" \ "mmc dev ${mmcdev}; if mmc rescan; then " \ "if run loadbootscript; then " \ "run bootscript; " \ "else " \ "if run loadimage; then " \ "run mmcboot; " \ "else run netboot; " \ "fi; " \ "fi; " \ "else run netboot; fi"
bootargs:传递给操作系统的命令行参数
c
"bootargs=" CONFIG_BOOTARGS // mx6ullevk.h
对 Linux 而言,bootargs 就是 内核命令行(kernel cmdline),决定根文件系统、控制台、内存布局等。例如:
bash
bootargs=console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rw
- U-Boot 在调用
bootz/bootm时,将 bootargs 写入设备树的chosen节点或 ATAGS(旧版方法) - 必须包含 console=:否则内核可能无串口输出。
- 使用 rootwait:确保 MMC/USB 设备初始化完成后再挂载 rootfs。
bootfile:镜像文件名
通过 TFTP 加载的镜像文件名。
- 当执行
tftpboot ${addr}(无文件名)时,U-Boot 会自动使用bootfile的值作为默认文件名。 - 默认值通常为 "uImage" 或 "Image",取决于板级配置。
bootm_low:限制 bootm 命令可以访问的内存范围
该变量以十六进制数形式给出,定义了 bootm 命令允许使用的最低地址。
bootm_low所定义的地址同时也是 Linux 内核初始内存映射的基地址- 与
bootm_size(最大可用内存大小)共同定义了一个 安全内存窗口,防止bootm使用保留区域
bootsize:限制 bootm 命令可以访问的内存范围
该变量以十六进制数形式给出,定义了 bootm 命令允许使用的内存区域大小。
bootretry 和 bootstopkeysha256、 bootdelaykey、 bootstopkey:增强的自动启动配置
基础的自动启动映象相关配置包括:
bootdelay:设置倒计时秒数bootcmd:倒计时结束后要执行的命令
这些基础功能的流程是:
- 倒计时内按任意键 → 自动启动停止 → 进入 U-Boot 命令行
- 这适合开发,但不适合产品环境,这时因为:
- 串口噪声:意外的产生了一个中断信号,设备进入 U-Boot
- 按键干扰:用户不懂系统,随便按了一个键,设备进入 U-Boot
- 配置中断:远程使用 U-Boot 配置设备,但期间断网了,一直停留在 U-Boot
所以需要让自动启动更加安全,可控,而不是被任何字符中断。U-Boot 提供了一些增强功能。
重新开始自动启动流程(bootretry 环境变量)
当自动启动被打断进入 U-Boot 命令行后,如果用户 长时间不输入命令 ,U-Boot 会 重新开始自动启动流程。
bash
bootretry=CONFIG_BOOT_RETRY_TIME // socfpga_secu.env
CONFIG_BOOT_RETRY_TIME:启动重新自动启动的超时时间,单位:秒- 只要用户执行一个命令 → 超时计时器重置
CONFIG_BOOT_RETRY_MIN:定义最小超时时间,不允许被设置得太低
在配置了 CONFIG_BOOT_RETRY_TIME 的前提下,如果使能配置项 CONFIG_RESET_TO_RETRY,则:
bootretry超时后,将直接 重启板子
使用特定字符串才能阻止自动启动(bootdelaykey 和 bootstopkey 环境)
- bootdelaykey:输入指定字符串(宏
CONFIG_AUTOBOOT_DELAY_STR指定)进入 U-Boot 命令行,如果设置了"重新开始自动启动流程",则超时时间达到后,会再次自动启动 - bootstopkey:输入指定字符串(宏
CONFIG_AUTOBOOT_STOP_STR指定)进入 U-Boot 命令行,不会有超时。
无论哪种模式,都需要:
- 配置宏:
CONFIG_AUTOBOOT_KEYED=y - 配置提示字符串:
CONFIG_AUTOBOOT_PROMPT="Press xxx to abort autoboot in %d seconds\n"
测试,以 U-Boot 2016 为例 (硬件为 i.mx6ull)
-
在
configs/mx6ull_alientek_emmc_defconfig中添加:cCONFIG_AUTOBOOT_KEYED=y CONFIG_AUTOBOOT_STOP_STR="k" CONFIG_AUTOBOOT_PROMPT="Press k to abort autoboot in %d seconds\n" -
重新编译:
bashmake mx6ull_alientek_emmc_defconfig ARCH=arm CROSS_COMPILE=/usr/local/bin/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf- make -j12 -
将编译后的文件拷贝到 TFTP 共享文件目录:
bashsudo cp u-boot.imx ~/linux/tftpboot/ -
通过 tftp 更新 U-Boot:
bashtftp 80800000 u-boot.imx mmc dev 1 0 mmc write 80800000 2 2c6 mmc partconf 1 1 0 0注:我编译后的 u-boot.imx 大小 363520 字节,363520/512 = 710 = 0x2c6
加密(哈希)保护的 stop key(bootstopkeysha256)
功能和 bootstopkey 相同,只不过阻止自动启动的字符串不会明文放在环境变量,而是存储 sha256 哈希值。当用户输入字符串后,U-Boot 会做 sha256,然后跟 bootstopkeysha256 做比较,相同则进入U-Boot 命令行,不会有超时。
button_cmd_0, button_cmd_0_name, ..., button_cmd_N, button_cmd_N_name
用于在启动过程中检测到某个按钮被按下时,映射并执行对应的命令。详见 CONFIG_BUTTON_CMD。例如:
bash
button_cmd_0_name=recovery
button_cmd_0=run recovery_cmd
button_cmd_1_name=update
button_cmd_1=run update_cmd
若启动时检测到"recovery 按钮"被按下,则执行 recovery_cmd ,如路由器"复位键进入恢复模式"。
updatefile:自动软件更新机制
TFTP 服务器上软件更新文件的位置,由自动软件更新功能使用。详情请参阅 doc/README.update 文档。
以下给出这个文档中的描述解析:
1. 这个功能是什么?
U-Boot 提供一个自动软件更新(Auto-update)机制:
每次开机时,U-Boot 会尝试从 TFTP 服务器下载一个文件(文件名由环境变量 updatefile 指定)。
下载成功后:解析该文件(它是一个 FIT 文件),校验每个更新内容的 SHA-1 校验值,并根据 FIT 中描述的地址信息,将更新内容自动写入 NOR Flash
一句话总结:只要服务器上放好更新文件,设备开机时就能自动升级固件。
2. 这个功能依赖什么?
要启用自动更新,需要:
c
#define CONFIG_UPDATE_TFTP 1
另外必须启用:
- NOR Flash 支持
- FIT 文件支持:CONFIG_FIT
- 设备树解析库:CONFIG_OF_LIBFDT
➡ 这些都是自动从 FIT 文件提取更新内容所必需的。
3. 自动更新涉及哪些关键配置?
(1) CONFIG_UPDATE_LOAD_ADDR
- TFTP 下载的默认地址是环境变量
loadaddr - 若
loadaddr没有设置,则使用CONFIG_UPDATE_LOAD_ADDR - 默认值:0x100000
也就是说 updatefile 会临时下载到这个区域。
(2) TFTP 链接超时配置:CONFIG_UPDATE_TFTP_CNT_MAX 和 CONFIG_UPDATE_TFTP_MSEC_MAX
因为设备每次启动都会尝试连接 TFTP,所以不能等太久:
CONFIG_UPDATE_TFTP_MSEC_MAX:每次连接等待多少毫秒(默认:100ms)CONFIG_UPDATE_TFTP_CNT_MAX:最多尝试连接多少次(默认:0次,即基本不重试)
➡ 防止没有服务器时导致开机慢。
4. updatefile 是如何制作的?(FIT 格式)
updatefile 必须是 FIT 文件 (.itb)
FIT 文件可包含多个更新,例如:
- U-Boot
- Kernel
- Ramdisk
- DTB
制作 FIT 文件需要:
- 一个 .its 描述文件
- 支持 binary include 的 dtc 版本
制作命令:
bash
mkimage -f update_uboot.its update_uboot.itb
5. 示例:使用 updatefile 自动更新 U-Boot
如果你有:
bash
u-boot.bin
update_uboot.its
运行:
bash
mkimage -f update_uboot.its update_uboot.itb
把 update_uboot.itb放到 TFTP 服务器:
例如:/tftpboot/update_uboot.itb
然后在 U-Boot 中设置:
bash
setenv updatefile /tftpboot/update_uboot.itb
saveenv
之后,一旦开机且 serverip 指向的服务器可用,设备会自动:
- 下载 updatefile
- 校验 SHA-1
- 替换闪存中的 U-Boot
注意风险:
- 必须确保 u-boot.bin 是可用的
- 必须确保闪存写入地址正确
- 否则可能会使设备无法开机
6. 多文件更新示例(update3.its)
这个例子展示如何同时更新:
- kernel
- ramdisk
- dtb
制作流程与上面相同,只是 .its 内容更复杂。
7. 使用 DFU + TFTP 的另一种更新方式
文档最后提到:
- 也可以用 DFU(USB 方式)结合 TFTP 来更新固件
- 详细见 doc/README.dfutftp
这是另外一种更新手段,与 updatefile 是并行的功能。
autoload:自动加载镜像(bootp 和 dhcp 命令)
若设为 "no"(即任何以 'n' 开头的字符串),"bootp" 和 "dhcp" 命令将仅从 BOOTP 服务器查询配置信息,而不会尝试加载任何镜像。
默认情况下,dhcp 命令会:
- 获取 IP、网关、TFTP 服务器地址;
- 自动下载 bootfile 指定的文件。
设置 autoload=no 后,仅执行第 1 步,常用于:
- 获取网络参数后手动下载不同镜像;
注意:tftpboot、nfs 等命令不受 autoload 影响,它只作用于 bootp/dhcp。
fdt_high:FDT加载地址的上限约束
若设置此变量,将限制设备树(FDT)在启动时被复制到的最高地址。例如,若你的系统在物理地址 0x10000000 处有 1GB 内存,但 Linux 内核仅将前 704MB 视为"低端内存"(low memory),你可能需要将 fdt_high 设为 0x3C000000 (0x100000000 - 0x3C000000,共 704MB),使设备树 blob 被复制到这 704MB 低端内存的最高地址,以便 Linux 内核在启动过程中能够访问它。
若将其设为特殊值 0xffffffff(32 位机器)或 0xffffffffffffffff(64 位机器),则启动时完全不复制设备树。要使此方式生效,设备树必须位于可写内存中,其末尾需有足够填充空间供 U-Boot 添加所需信息,且该内存必须能被内核访问。然而,强烈不建议使用此方式,因为它会阻止 U-Boot 确保设备树起始地址正确对齐,而未对齐的设备树将导致操作系统启动失败。
fdtcontroladdr:控制设备树的地址
若设置此变量,它表示当启用了 CONFIG_OF_CONTROL 时,U-Boot 所使用的控制设备树(control FDT)的地址。
ONFIG_OF_CONTROL表示 U-Boot 从设备树获取自身配置(而非从CONFIG_宏)。fdtcontroladdr指向这个"控制设备树"的内存地址(通常由 BootROM 或前一级 bootloader 加载)
initrd_high:限制 initrd 镜像的放置位置
initrd 就是一个存放在内存中的临时小型根文件系统,辅助内核加载真正的根文件系统。
若未设置此变量,initrd 镜像将被复制到 RAM 中尽可能高的地址;这通常是期望的行为,因为它允许 initrd 使用最大可能的内存大小。
如果出于某些原因,你需要确保 initrd 镜像加载在 CFG_SYS_BOOTMAPSZ 限制之下,可将此变量设为 "no"、"off" 或 "0"。或者,你也可以将其设为一个最大上限地址(U-Boot 仍会检查该地址不会覆盖 U-Boot 自身的栈和数据区)。
例如,当你的系统有 16MB RAM,并希望为 Linux 保留 4MB 不使用,可通过在 bootargs 中添加 mem=12M 实现。但此时你必须确保 initrd 镜像也放置在前 12MB 内------可通过以下命令实现:
bash
setenv initrd_high 00c00000 # 0x00C00000 = 12MB
若将 initrd_high 设为 0xffffffff(32 位机器)或 0xffffffffffffffff(64 位机器),这表示告知 U-Boot:所有地址对 Linux 内核都是合法的,包括 flash 内存中的地址。此时 U-Boot 完全不会复制 ramdisk。这可用于减少系统启动时间,但要求你的 Linux 内核支持此特性。然而,这种用法要求用户确保 initrd 与镜像其他部分(如 Linux 内核的 BSS 段)无重叠。不应默认启用,仅应在部署优化阶段谨慎使用。
在一些嵌入式应用中,内核和根文件系统都在 Flash 上,所有驱动都编译进内核,这时是不需要 initrd 的。
ipaddr:设备 IP 地址
设备的本机 IP 地址,用于 TFTP/NFS 等网络操作(tftpboot 命令)。若未设置,dhcp 或 bootp 命令会自动获取并设置它。
serverip:TFTP 服务器 IP 地址
用于 tftpboot 命令。
loadaddr:默认加载地址
"bootp"、"rarpboot"、"tftpboot"、"loadb" 或 "diskboot" 等命令的默认加载地址。注意,最优默认值因架构而异。例如,在 32 位 ARM 上,通常使用内存起始地址的一个偏移量,因为 Linux 内核 zImage 自带解压器,我们最好避开其工作区域。
-
ARM Linux 内核(zImage 格式)不是直接执行,它先会在内存里自己解压成一个更大的 Image,然后再跳到解压后的内核执行。
-
这个解压动作会使用内存的一部分区域。
-
如果你把 zImage 加载得太靠近内存起始(比如 i.mx6ull 的内存起始地址 0x80000000),很有可能解压出来的 Image 会覆盖 zImage 自身或覆盖其他数据,导致系统无法启动。
-
所以 U-Boot 为 zImage 选择的加载地址(loadaddr)必须往后挪一点,比如 i.mx6ull 会设置:
bash#define CONFIG_LOADADDR 0x80800000 // mx6common.h,留出 8MB "loadaddr=" __stringify(CONFIG_LOADADDR) // env_default.h
loads_echo:回显接收数据
loads 命令通过串口 XMODEM 协议接收二进制文件。
bash
"loads_echo=" __stringify(CONFIG_LOADS_ECHO) // env_default.h
若启用 CONFIG_LOADS_ECHO,U-Boot 会在接收时回显字符(用于调试)。
ethprime:设置默认首选网络接口
控制哪个网络接口被优先使用(即作为默认首选接口,启动默认值)。
如果你的板子有多个网卡,且希望确保 TFTP/NFS 从特定接口加载内核,请务必设置 ethprime=FEC。
ethact:设置当前活动的网络接口
ethact 控制当前处于活动状态的网络接口。例如,你可以执行以下操作:
bash
=> setenv ethact FEC
=> ping 192.168.0.1 # 流量通过 FEC 接口发送
=> setenv ethact SCC
=> ping 10.0.0.1 # 流量通过 SCC 接口发送
ethact 是运行时变量,允许用户在 U-Boot 命令行中手动切换当前使用的网络接口,而无需重启。与之对应的是 ethprime,是"启动默认值";
ethrotate:路由网络接口
当设为 "no" 时,U-Boot 不会遍历所有可用的网络接口,而仅使用当前选定的接口。当该变量未设置,或设置为除 "no" 以外的任何值时,U-Boot 会依次尝试所有可用的网络接口。
netretry:重试网络接口策略
- 当设为 "no" 时,每次网络操作要么成功,要么立即失败,不进行重试。
- 当设为 "once" 时,网络操作会在所有可用网络接口各尝试一次后,若仍无成功,则宣告失败。
httpdstp:设置 http 端口号
如果设置了该变量,其值将被用作 HTTP 请求的 TCP 目标端口,取代默认的 80 端口。
U-Boot 支持通过 httpget 命令从 Web 服务器下载文件(如内核镜像)。默认使用标准 HTTP 端口 80,但很多嵌入式部署使用非标端口(如 8080、8000)。
仅影响 HTTP:该变量不影响 TFTP、NFS、DHCP 等其他协议。
phy_aneg_timeout:设置 PHY 自动协商超时时间
如果设置了该变量,其指定的值将覆盖 CONFIG_PHY_ANEG_TIMEOUT 配置项。该变量的数值格式和单位与 CONFIG_PHY_ANEG_TIMEOUT 相同,分别为"十进制"和"毫秒"。
CONFIG_PHY_ANEG_TIMEOUT 的默认值对大多数应用场景已足够,但某些对端设备(link-partner)由于其所使用的以太网 PHY 芯片特性,可能需要更长的超时时间。当然,如果应用场景有特殊需求,也可以将该超时时间缩短。
- U-Boot 中 CONFIG_PHY_ANEG_TIMEOUT 通常设为 5000 ms(5 秒)
- aneg:自动协商(Auto-Negotiation)
rng_seed_size
指定添加到设备树节点 /chosen/rng-seed 中的随机值的字节长度。该变量以十进制数字形式给出。若未设置,则默认使用 64 字节。
- 现代 Linux 内核(尤其是启用
CONFIG_RANDOM_TRUST_BOOTLOADER时)会从设备树的/chosen/rng-seed获取初始熵(entropy),用于初始化内核的随机数生成器(CRNG)。 - 若 U-Boot 有硬件 RNG(如 SoC 内置 TRNG),可生成真随机数填充此字段,提升系统安全性。
silent_linux:控制 Linux 是否静默启动(不输出信息)
如果设置了该变量,则通过在 Linux 内核命令行中添加 console= 来指示 Linux 以静默方式启动。
- 若其值为 "yes",则 Linux 将被设为静默启动;
- 若为 "no",则不会设为静默;
- 若未设置,则当 U-Boot 控制台本身处于静默状态时,Linux 也会被设为静默启动。
U-Boot 的 silent 环境变量控制自身是否输出日志。silent_linux 决定是否将这种"静默"传递给 Linux。
console= 的作用:清空内核的控制台设备列表,使 printk 输出不显示在串口/VGA 上(但仍可通过 dmesg 查看)。
开发阶段应设为 "no",否则无法看到内核 panic 或驱动错误信息。
产品发布推荐启用:设为 "yes" 可隐藏技术细节,呈现干净启动画面。
若你的 bootargs 中已包含 console=ttyS0,...,则 silent_linux=yes 会覆盖它(因 console= 清空了列表)。需注意顺序或手动拼接。
tftpsrcp:固定 TFTP 源端口号
如果设置了该变量,其值将被用作 TFTP 通信的 UDP 源端口。
- 标准 TFTP(RFC 1350)使用 UDP。客户端向服务器的 69 号端口发送请求,但服务器会从一个临时高端口回传数据,客户端也需用一个临时端口接收。
- 默认情况下,U-Boot 让操作系统(或网络栈)自动分配源端口(ephemeral port)。
- 设置 tftpsrcp 可固定源端口,便于防火墙策略配置或网络调试。
tftpdstp:固定 TFTP 目标端口号
如果设置了该变量,其值将被用作 TFTP 的 UDP 目标端口,取代默认的 69 号端口。
tftpblocksize:设置 TFTP 数据块大小
指定 TFTP 传输使用的数据块大小;若未设置,则使用 TFTP 服务器的默认块大小。
tftptimeout:设置 TFTP 超时时间
TFTP 数据包的重传超时时间(单位:毫秒,最小值为 1000,即 1 秒)。该值定义了在多长时间内未收到响应即视为丢包,从而触发重传。默认值为 5000(5 秒)。在网络丢包率较高或 TFTP 服务器不可靠的情况下,降低此值可使下载更快成功。
tftptimeoutcountmax:设置 TFTP 最大超时重传次数
单次文件传输过程中允许的最大超时次数(无单位,最小值为 0)。该值定义了在放弃传输前最多可发生多少次超时。默认值为 10,而 0 表示"不允许任何超时"(即首次超时即失败)。在高丢包率网络、不可靠 TFTP 服务器或客户端硬件不稳定的场景下,增大此值有助于下载最终成功。
tftpwindowsize:设置 TFTP 窗口大小
如果设置了该变量,其值将被用作 TFTP 的窗口大小,遵循 RFC 7440 规范。这意味着在向服务器发送确认(ACK)之前,我们可以连续接收的数据块数量。
- 传统 TFTP:1 块 → ACK → 1 块(停等),带宽利用率极低。
- RFC 7440(Windowed TFTP):允许"滑动窗口"机制。例如 tftpwindowsize=4 表示:
客户端可连续接收 Block1~4,然后一次性发 ACK(4),服务器接着发 Block 5~8......
bootpretryperiod:设置 BOOTP/DHCP 重试周期时间
BOOTP/DHCP 协议发送重试请求的时间窗口(单位:毫秒,无符号整数)。若未设置,该周期将采用默认值(28000 毫秒,即 28 秒),或若定义了 CONFIG_NET_RETRY_COUNT,则基于该配置计算得出。此环境变量的值优先级高于基于 CONFIG_NET_RETRY_COUNT 计算出的值。
镜像位置相关变量
注意:这些变量并非所有开发板都必须定义 。某些开发板目前为相同用途使用了其他变量名,而另一些开发板则可能将这些变量名用于其他目的。这些变量中的大多数仅是一组被广泛采用的变量名 ,它们出现在其他变量的定义中(如 bootcmd),但在 U-Boot 源代码中并未被硬编码引用。
也就是说,以下介绍的环境变量是厂商广泛使用,但是 U-Boot 并不使用。
- 指定 TFTP 服务器上该镜像文件的文件名
- bootfile:Linux 内核文件名
- fdtfile:设备树二进制文件名
- ramdiskfile:ramdisk 文件名
- 镜像的加载地址(RAM 中)
- kernel_addr_r:Linux 内核
- fdt_addr_r:设备树
- ramdisk_addr_r:ramdisk
- 镜像的存储物理地址或偏移量
- kernel_addr:Linux 内核
- fdt_addr:设备树
- ramdisk_addr:ramdisk
在设置 kernel_addr_r、fdt_addr_r 和 ramdisk_addr_r 的 RAM 加载地址时,需考虑多种约束条件:
- 负载(payload)自身的要求:例如,设备树(Device Tree)必须加载到 8 字节对齐的地址,这是其规范所强制规定的。类似地,操作系统也可能对镜像在内存中的位置施加限制------Linux 在《Booting ARM Linux》和《Booting AArch64 Linux》等文档中对此有明确说明。
- 实践性约束:我们无法预知用户使用的各镜像的具体大小,但必须确保它们互不重叠,否则会相互覆盖导致损坏。此外,若某个镜像被加载到操作系统 BSS 段(未初始化数据区)所在区域,同样可能引发冲突。
因此,我们必须确保默认地址值:
- 极低概率导致启动失败;
- 附带充分说明,以便用户可根据实际需求优化启动速度,或适配小内存系统。
不同架构具有不同的约束条件。为确保向前兼容性,我们必须严格遵循已公开的官方文档要求。以下通过具体示例,说明如何为不同平台设定合理的默认值。
TI OMAP2PLUS(ARMv7)示例:
bash
loadaddr=0x82000000
kernel_addr_r=${loadaddr}
fdt_addr_r=0x88000000
ramdisk_addr_r=0x88080000
bootm_size=0x10000000 # 256 MiB
首先要记住的是:DRAM 起始地址为 0x80000000。我们将默认加载地址设为从内存起始处偏移 32 MiB 的位置(即 0x82000000),并将 kernel_addr_r 指向该地址。这样做的原因是:Linux 的 zImage 自解压程序通常可以因此避免执行额外的重定位(relocation)操作。此外,该地址必须位于内存前 128 MiB 范围内。
接下来,我们将 fdt_addr_r 设为从内存起始处偏移 128 MiB 的位置(即 0x88000000)。这一位置由 Linux 内核文档所建议,并且由于其他架构限制,内核本身极不可能覆盖该区域。
然后,我们为设备树预留最多 512 KiB 的空间,之后才放置 initramfs(ramdisk)。
最后,我们规定所有镜像都应位于内存前 256 MiB 范围内,以便 U-Boot 在必要时可对它们进行重定位,确保满足对齐等要求。之所以选择 256 MiB 这一数值,是因为我们知道该系列平台中极少有内存小于 256 MiB 的型号。理论上,该上限甚至可设为 768 MiB 而仍能保证内核可见所有数据,但我们依然选择了我们认为最安全的假设。
特殊环境变量
这些变量只能设置一次(通常在电路板制造阶段完成)。一旦设定,U-Boot 拒绝删除或覆盖这些变量,除非在板级配置中启用了 CONFIG_ENV_OVERWRITE。
serial#
包含硬件标识信息,例如设备类型字符串和/或序列号。
ethaddr
以太网 MAC 地址。若启用了 CONFIG_REGEX=y,则还支持 eth*addr(其中 * 为整数,如 eth0addr, eth1addr)。
外部环境变量文件
配置选项 CONFIG_ENV_USE_DEFAULT_ENV_TEXT_FILE 提供了一种绕过 U-Boot 内部环境生成机制的方法。若启用该选项,则 CONFIG_ENV_DEFAULT_ENV_TEXT_FILE 指定一个文件名,该文件的内容将被转换为 U-Boot 的默认环境变量,从而完全取代 env_default.h 中定义的标准默认环境。
文件格式与 mkenvimage 工具所接受的格式相同:每行包含 key=value 形式的键值对。空行以及以 # 开头的注释行将被忽略。
未来的工作可能会将此功能与基于文本的环境变量机制统一,甚至可能将 env_default.h 的内容迁移至一个文本文件中。