linux 系统移植(第六期)--Uboot移植(5)--bootcmd 和 bootargs 环境变量-- Ubuntu20.04

文章目录
前言

一、bootcmd和bootargs环境变量

[二、环境变量 bootcmd](#二、环境变量 bootcmd)

[三、环境变量 bootargs](#三、环境变量 bootargs)

总结


前言

上一期我们已经把uboot 的驱动部分就修改完成了,uboot 移植也完成了,uboot 的最终目的就是启动 Linux 内核,所以需要通过启动 Linux 内核来判断 uboot 移植是否成功。在启动 Linux 内核之前我们先来学习两个重要的环境变量 bootcmd 和 bootargs。


一、bootcmd和bootargs环境变量

uboot 中有两个非常重要的环境变量 bootcmd 和 bootargs,接下来看一下这两个环境变量。bootcmd 和 bootagrs 是采用类似 shell 脚本语言编写的,里面有很多的变量引用,这些变量其实 都是环境变量,有很多是 NXP 自 己 定 义 的 。 文 件 mx6ull_alientek_emmc.h 中的宏 CONFIG_EXTRA_ENV_SETTINGS 保存着这些环境变量的默认值,内容如下:

复制代码
#ifdef CONFIG_SYS_BOOTMENU
#define CONFIG_EXTRA_ENV_SETTINGS \
    CONFIG_MFG_ENV_SETTINGS \
    "fdt_addr=0x83000000\0" \
    "panel=ATK4384\0" \
    "fdt_high=0xffffffff\0" \
    "bootz ${loadaddr} - ${fdt_addr}\0"
#else
#define CONFIG_EXTRA_ENV_SETTINGS \
    CONFIG_MFG_ENV_SETTINGS \
    "image=Image\0" \
    "console=ttymxc0\0" \
    "fdt_high=0xffffffff\0" \
    "initrd_high=0xffffffff\0"

...

"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} = SDB && 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"

宏 CONFIG_EXTRA_ENV_SETTINGS 是个条件编译语句,使用 NAND 和 EMMC 的时候

宏 CONFIG_EXTRA_ENV_SETTINGS 的值是不同的。

二、环境变量****bootcmd

bootcmd 是U-Boot 启动 Linux 内核的核心命令载体,倒计时结束后自动执行。

支持手动修改,无存储值时会读取env_default.h中的默认配置(首次运行必用)。

核心功能是从存储介质读取内核 / 设备树文件到内存并启动 Linux。
打开文件 include/env_default.h ,在此文件中有如下所示内容:

复制代码
#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
env_t environment __PPCENV__ = {
	ENV_CRC,	/* CRC Sum */
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
	1,		/* Flags: valid */
#endif
	{
#elif defined(DEFAULT_ENV_INSTANCE_STATIC)
static char default_environment[] = {
#else
const uchar default_environment[] = {
#endif
#ifdef	CONFIG_ENV_CALLBACK_LIST_DEFAULT
	ENV_CALLBACK_VAR "=" CONFIG_ENV_CALLBACK_LIST_DEFAULT "\0"
#endif
#ifdef	CONFIG_ENV_FLAGS_LIST_DEFAULT
	ENV_FLAGS_VAR "=" CONFIG_ENV_FLAGS_LIST_DEFAULT "\0"
#endif
#ifdef	CONFIG_BOOTARGS
	"bootargs="	CONFIG_BOOTARGS			"\0"
#endif
#ifdef	CONFIG_BOOTCOMMAND
	"bootcmd="	CONFIG_BOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_RAMBOOTCOMMAND
	"ramboot="	CONFIG_RAMBOOTCOMMAND		"\0"
#endif
#ifdef	CONFIG_NFSBOOTCOMMAND
	"nfsboot="	CONFIG_NFSBOOTCOMMAND		"\0"
#endif
#if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
	"bootdelay="	__stringify(CONFIG_BOOTDELAY)	"\0"
#endif
#if defined(CONFIG_BAUDRATE) && (CONFIG_BAUDRATE >= 0)
	"baudrate="	__stringify(CONFIG_BAUDRATE)	"\0"
#endif
#ifdef	CONFIG_LOADS_ECHO
	"loads_echo="	__stringify(CONFIG_LOADS_ECHO)	"\0"
#endif
#ifdef	CONFIG_ETHPRIME
	"ethprime="	CONFIG_ETHPRIME			"\0"
#endif
#ifdef	CONFIG_IPADDR
	"ipaddr="	__stringify(CONFIG_IPADDR)	"\0"
#endif
#ifdef	CONFIG_SERVERIP
	"serverip="	__stringify(CONFIG_SERVERIP)	"\0"
#endif
#ifdef	CONFIG_SYS_AUTOLOAD
	"autoload="	CONFIG_SYS_AUTOLOAD		"\0"
#endif
#ifdef	CONFIG_PREBOOT
	"preboot="	CONFIG_PREBOOT			"\0"
#endif
#ifdef	CONFIG_ROOTPATH
	"rootpath="	CONFIG_ROOTPATH			"\0"
#endif
#ifdef	CONFIG_GATEWAYIP
	"gatewayip="	__stringify(CONFIG_GATEWAYIP)	"\0"
#endif
#ifdef	CONFIG_NETMASK
	"netmask="	__stringify(CONFIG_NETMASK)	"\0"
#endif
#ifdef	CONFIG_HOSTNAME
	"hostname="	__stringify(CONFIG_HOSTNAME)	"\0"
#endif
#ifdef	CONFIG_BOOTFILE
	"bootfile="	CONFIG_BOOTFILE			"\0"
#endif
#ifdef	CONFIG_LOADADDR
	"loadaddr="	__stringify(CONFIG_LOADADDR)	"\0"
#endif
#ifdef	CONFIG_CLOCKS_IN_MHZ
	"clocks_in_mhz=1\0"
#endif
#if defined(CONFIG_PCI_BOOTDELAY) && (CONFIG_PCI_BOOTDELAY > 0)
	"pcidelay="	__stringify(CONFIG_PCI_BOOTDELAY)"\0"
#endif
#ifdef	CONFIG_ENV_VARS_UBOOT_CONFIG
	"arch="		CONFIG_SYS_ARCH			"\0"
	"cpu="		CONFIG_SYS_CPU			"\0"
	"board="	CONFIG_SYS_BOARD		"\0"
	"board_name="	CONFIG_SYS_BOARD		"\0"
#ifdef CONFIG_SYS_VENDOR
	"vendor="	CONFIG_SYS_VENDOR		"\0"
#endif
#ifdef CONFIG_SYS_SOC
	"soc="		CONFIG_SYS_SOC			"\0"
#endif
#endif
#ifdef	CONFIG_EXTRA_ENV_SETTINGS
	CONFIG_EXTRA_ENV_SETTINGS
#endif
	"\0"
#ifdef DEFAULT_ENV_INSTANCE_EMBEDDED
	}
#endif
};

上段代码中指定了很多环境变量的默认值,比如 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 就是从 mmc1 的分区中读取 zImage 到内存的 0X80800000 处,而 mmc1 的分区 1 中存在zImage。

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

netboot 环境变量。
其实就是为了从 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;"

三、环境变量****bootargs

bootargs 保存着 uboot 传递给 Linux 内核的参数,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 启动后,IMX6ULL 的串口 1 在 Linux 中的设备文件就是 /dev/ttymxc0,在 Linux 中,一切皆文件。

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。
3、rootfstype

此选项一般配置 root 一起使用,rootfstype 用于指定根文件系统类型,如果根文件系统为ext 格式的话此选项无所谓。如果根文件系统是 yaffs、jffs 或 ubifs 的话就需要设置此选项,指定根文件系统的类型。


总结

学习两个重要的环境变量 bootcmd 和 bootargs。

相关推荐
温暖小土1 小时前
深度解析 Spring Boot 自动配置:从原理到实践
java·springboot
Marktowin1 小时前
Mybatis-Plus更新操作时的一个坑
java·后端
lili-felicity1 小时前
React Native for OpenHarmony 实战:Easing 动画完全指南
javascript·react native·react.js
R-sz1 小时前
如何将json行政区划导入数据库,中国行政区域数据(省市区县镇乡村五级联动)
java·数据库·json
m0_748254662 小时前
AJAX 基础实例
前端·ajax·okhttp
vmiao2 小时前
【前端入门】商品页放大镜效果(仅放大镜随鼠标移动效果)
前端
持续前行2 小时前
vscode 中找settings.json 配置
前端·javascript·vue.js
定仙游4532 小时前
Java StringBuilder 超详细讲解
java
Anita_Sun2 小时前
Lodash 源码解读与原理分析 - Lodash IIFE 与兼容性处理详解
前端