文章目录
链接: C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂
1. bootcmd 和 bootargs 环境变量
1.1 环境变量 bootcmd
bootcmd 保存着 uboot 默认命令, uboot 倒计时结束以后就会执行 bootcmd 中的命令。这些命令一般都是用来启动 Linux 内核的,比如读取 EMMC 或者 NAND Flash 中的 Linux 内核镜像文件和设备树文件到 DRAM 中,然后启动 Linux 内核。
如果 EMMC 或者 NAND 中没有保存 bootcmd 的值,那么 uboot 就会使用默认的值,板子第一次运行 uboot 的时候都会使用默认值来设置 bootcmd 环境变量。
打开文件 include/env_default.h,在此文件中有如下所示内容:
指定了很多环境变量的默认值,比如 bootcmd
的默认值就是CONFIG_BOOTCOMMAND
, bootargs 的默认值就是 CONFIG_BOOTARGS
。
CONFIG_BOOTCOMMAND
值如下:
#define CONFIG_BOOTCOMMAND \
"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"
#endif
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;'
1.2 环境变量 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启动以后 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=0n,y=1n)表示 mmc 设备x 的分区 y。在 I.MX6U-ALPHA 开发板中/dev/mmcblk1 表示 EMMC,而/dev/mmcblk1p2 表示EMMC 的分区 2。
root 后面有“rootwait rw”, rootwait 表示等待 mmc 设备初始化完成以后再挂载,否则的话mmc 设备还没初始化完成就挂载根文件系统会出错的。 rw 表示根文件系统是可以读写的,不加rw 的话可能无法在根文件系统中进行写操作,只能进行读操作。
2. uboot 启动 Linux 测试
启动 Linux 内核。测试两种启动 Linux 内核的方法,一种是直接从 EMMC 启动,一种是从网络启动。
2.1 从 EMMC 启动 Linux 系统
从 EMMC 启动也就是将编译出来的 Linux 镜像文件 zImage 和设备树文件保存在 EMMC中, uboot 从 EMMC 中读取这两个文件并启动。先检查一下 EMMC 的分区 1 中有没有zImage 文件和设备树文件,输入命令“ls mmc 1:1”
=> mmc list
FSL_SDHC: 0
FSL_SDHC: 1 (eMMC)
=> ls mmc 1:1
6785480 zimage
39459 imx6ull-14x14-emmc-4.3-480x272-c.dtb
39459 imx6ull-14x14-emmc-4.3-800x480-c.dtb
39459 imx6ull-14x14-emmc-7-800x480-c.dtb
39459 imx6ull-14x14-emmc-7-1024x600-c.dtb
39459 imx6ull-14x14-emmc-10.1-1280x800-c.dtb
40295 imx6ull-14x14-emmc-hdmi.dtb
40203 imx6ull-14x14-emmc-vga.dtb
8 file(s), 0 dir(s)
此时 EMMC 分区 1 中存在 zimage 和 imx6ull-alientek-emmc.dtb这两个文件,可以测试新移植的 uboot 能不能启动 linux 内核。设置 bootargs 和 bootcmd这两个环境变量,设置如下:
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 - 83000000;'
saveenv
设置好以后直接输入 boot,或者 run bootcmd 即可启动 Linux 内核,如果 Linux 内核启动成功的话就会输出如图
U-Boot 2016.03-g0ae7e33 (Aug 14 2022 - 19:42:45 +0800)
CPU: Freescale i.MX6ULL rev1.1 792 MHz (running at 396 MHz)
CPU: Industrial temperature grade (-40C to 105C) at 43C
Reset cause: POR
Board: I.MX6U ALPHA|MINI
I2C: ready
DRAM: 512 MiB
MMC: FSL_SDHC: 0, FSL_SDHC: 1
In: serial
Out: serial
Err: serial
switch to partitions #0, OK
mmc1(part 0) is current device
Net: FEC1
Error: FEC1 address not set.
Normal Boot
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc1(part 0) is current device
reading zImage
6785480 bytes read in 222 ms (29.1 MiB/s)
reading imx6ull-14x14-emmc-7-1024x600-c.dtb
39459 bytes read in 23 ms (1.6 MiB/s)
Kernel image @ 0x80800000 [ 0x000000 - 0x6789c8 ]
## Flattened Device Tree blob at 83000000
Booting using the fdt blob at 0x83000000
Using Device Tree in place at 83000000, end 8300ca22
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.1.15-g3dc0a4b (alientek@ubuntu) (gcc version 5.3.0 (GCC) ) #1 SMP PREEMPT Thu Aug 18 09:27:40 CST 2022
[ 0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=10c53c7d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] Machine model: Freescale i.MX6 ULL 14x14 EVK Board
[ 0.000000] Reserved memory: created CMA memory pool at 0x98000000, size 128 MiB
[ 0.000000] Reserved memory: initialized node linux,cma, compatible id shared-dma-pool
2.2 从网络启动 Linux 系统
从网络启动 linux 系统的唯一目的就是为了调试!设置 linux 从网络启动,也就是将 linux 镜像文件和根文件系统都放到 Ubuntu 下某个指定的文件夹中,这样每次重新编译 linux 内核或者某个 linux 驱动以后只需要使用 cp 命令将其拷贝到这个指定的文件夹中即可,这样就不用需要频繁的烧写 EMMC,这样就加快了开发速度。
通过 nfs 或者 tftp 从 Ubuntu 中下载 zImage 和设备树文件,根文件系统的话也可以通过 nfs 挂载。使用 tftp 从 Ubuntu 中下载 zImage 和设备树文件。
设置 bootargs 和 bootcmd 这两个环境变量,设置如下:
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz
80800000 - 83000000'
saveenv
一开始是通过tftp下载zImage和imx6ull-alientek-emmc.dtb这两个文件,下载完成以后就是启动 Linux 内核
3. 总结
uboot 移植到此结束,简单总结一下 uboot 移植的过程:
①、不管是购买的开发板还是自己做的开发板,基本都是参考半导体厂商的 dmeo 板,而半导体厂商会在他们自己的开发板上移植好 uboot、 linux kernel 和 rootfs 等,最终制作好 BSP包提供给用户。我们可以在官方提供的 BSP 包的基础上添加我们的板子,也就是俗称的移植。
②、购买的开发板或者自己做的板子一般都不会原封不动的照抄半导体厂商的 dem板,都会根据实际的情况来做修改,既然有修改就必然涉及到 uboot 下驱动的移植。
③、一般 uboot 中需要解决串口、 NAND、 EMMC 或 SD 卡、网络和 LCD 驱动,因为 uboot的主要目的就是启动 Linux 内核,所以不需要考虑太多的外设驱动。
④、在 uboot 中添加自己的板子信息,根据自己板子的实际情况来修改 uboot 中的驱动。