uboot-命令和环境变量

1.1 help或者?#

image

1.1.1 help+具体命令#

? bootz 或 help bootz
image

1.2 信息查询#

1.2.1 bdinfo#

image

1.2.2 printenv#

image
image
前确保 uboot 中的环境变量 bootargs 内容如下:
console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw

1
2
3
4
5
cp arch/arm/boot/zImage /home/zuozhongkai/linux/tftpboot/ -f
cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /home/zuozhongkai/linux/tftpboot/ -f
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-evk.dtb
bootz 80800000 - 83000000

1.2.3 version#

image

1.3 环境变量#

1.3.1 setenv设定环境变量#

设置bootdelay时间为5s.

1
2
setenv bootdelay 5
saveenv

image

1
2
setenv author zuozhongkai
saveenv

新建环境变量也是用setenv。

1.3.2 saveenv保存环境变量#

1.3.3 setenv删除环境变量#

1
2
setenv author
saveenv

设置变量为空表示删除掉该环境变量,重启该环境变量就不会存在了。

1.3.4 环境变量原理#

include/env_default.h定义了很多环境变量,如bootargs,bootdelay,bootcmd等
image
由 于 没 有 定 义DEFAULT_ENV_INSTANCE_EMBEDDED和CONFIG_SYS_REDUNDAND_ENVIRONMENT,因此 uchar default_environment[]数组保存环境变量。

1.3.4.1 bootcmd展开#

CONFIG_BOOTCOMMAND等一系列宏都是定义在include/configs/mx6ull_alientek_emmc.h:
image
uboot 使用了类似 shell 脚本语言的方式来编写的,首先run findfdt, findfdt 是用来查找开发板对应的设备树文件(.dtb),IMX6ULL EVK 的设备树文件为imx6ull-14x14-evk.dtb,findfdt内容如下:

1
2
3
4
5
6
7
8
9
"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" \

那么run findfdt就等同于执行setenv fdt_file imx6ull-14x14-evk.dtb。设置fdt_file环境变量等于imx6ull-14x14-evk.dtb。
mmc dev ${mmcdev}用于切换 mmc 设备,mmcdev 为 1,因此这行代码就是:mmc dev 1,也就是切换到 EMMC 上。
先执行 mmc dev ${mmcdev}切换到 EMMC 上,然后使用命令 mmc rescan 扫描看有没有 SD 卡或者 EMMC 存在,如果没有的话就直接跳到else,执行 run netboot,netboot也是一个自定义的环境变量,这个变量是从网络启动 Linux 的。
扫描到EMMC后,run 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 这个文件。再展开bootscript:

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

由于boot.src 文件不存在,所以 bootscript 也就不会运行。就运行环境变量 loadimage:
loadimage=fatload mmc ${mmcdev}:${mmcpart} ${loadaddr} ${image}
loadimage展开:
loadimage=fatload mmc 1:1 0x80800000 zImage
fatload就是从 mmc1 的分区中读取 zImage 到内存的 0X80800000 处,而 mmc1的分区 1 中存在 zImage。
loadimage执行完,执行mmcboot环境变量,run mmcboot:
image
①打印Booting from mmc …
②运行环境变量 mmcargs,mmcargs 用来设置 bootargs,后面分析 bootargs 的时候在学习。
③判断boot_fdt是否为yes或者try,根据uboot输出的环境变量信息可知boot_fdt=try。因此执行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处。
⑤loadfdt加载dtb成功后,调用命令 bootz 启动 linux:
bootz ${loadaddr} - ${fdt_addr};
展开:
bootz 0x80800000 - 0x83000000 (注意‘-’前后要有空格)

总结一下bootcmd展开:

1
2
3
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

我们可以将bootcmd环境变量进行简化:

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

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

1.3.4.2 bootargs展开#

bootargs 保存着 uboot 传递给 Linux 内核的参数。从emmc启动时,bootargs 环境变量是由 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
console=ttymxc0,115200 综合起来就是设置 ttymxc0(也就是串口 1)作为 Linux 的终端,并且串口波特率设置为 115200。
root=/dev/mmcblk1p2 用于指明根文件系统存放在mmcblk1 设备的分区 2 中。在 I.MX6U-ALPHA 开发板中/dev/mmcblk1 表示 EMMC,而/dev/mmcblk1p2 表示EMMC 的分区 2。
③root 后面有rootwait rw,rootwait 表示等待 mmc 设备初始化完成以后再挂载,否则的话mmc 设备还没初始化完成就挂载根文件系统会出错的。rw 表示根文件系统是可以读写的,不加rw 的话可能无法在根文件系统中进行写操作,只能进行读操作。

1.3.4.3 bootdlelay#

uboot命令行倒计时

1.4 内存操作#

1.4.1 md#

md[.b, .w, .l] address [# of objects]

注意:uboot 命令中的数字都是十六进制的

  1. 命令中的[.b .w .l]对应 byte、word 和 long,也就是分别以 1 个字节、2 个字节、4 个字节来显示内存值.
  2. address 就是要查看的内存起始地址.
  3. [# of objects]表示要查看的数据长度:

这个数据长度单位不是字节,而是跟你所选择的显示格式有关。比如你设置要查看的内存长度为20(十六进制为 0x14),如果显示格式为.b 的话那就表示 20 个字节;如果显示格式为.w 的话就表示 20 个 word,也就是 20*2=40 个字节;如果显示格式为.l 的话就表示 20 个 long,也就是20*4=80 个字节

1
2
3
md.b 80000000 10 //读16字节
md.w 80000000 10 //读32字节
md.l 80000000 10 //读64字节

image

1.4.2 nm命令#

写内存,写成功后地址不会自增。

1
nm [.b, .w, .l] address

image
0500e031 表示地址 0x80000000 现在的数据,后面就可以输入要修改后的数据 0x12345678,输入完成以后按下回车,然后再输入‘q’即可退出。
退出后输入md.l查看。
image

1.4.3 mm命令#

写内存,写成功后地址会自增。
比如以.l 格式修改从地址 0x80000000 开始的连续 3 个内存块(3*4=12个字节)的数据为 0X05050505.
image
输入md命令查看一下:
image

1.4.4 mw命令#

写一段连续的内存。

1
mw [.b, .w, .l] address value [count]

比如使用.l 格式将以 0X80000000 为起始地址的 0x10 个内存块(0x10 * 4=64 字节)填充为 0X0A0A0A0A

1
mw.l 80000000 0A0A0A0A 10

image

1.4.5 cp命令#

数据拷贝命令,用于将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 Nor Flash 中的数据拷贝到 DRAM 中。

cp [.b, .w, .l] source target count

我们使用.l 格式将 0x80000000 处的地址拷贝到 0X80000100 处,长度为 0x10 个内存块(0x10 * 4=64 个字节).

cp.l 80000000 80000100 10

image

1.4.6 cmp命令#

比较两段内存的数据是否相等。

cmp [.b, .w, .l] addr1 addr2 count

比较 0x80000000 和 0X80000100 这两个地址数据是否相等,比较长度为 0x10 个内存块(16 * 4=64 个字节)

cmp.l 80000000 80000100 10

image
我们再随便挑两段内存比较一下,比如地址0x80002000 和 0x800003000,长度为 0X10.
image
可以看出,0x80002000 处的数据和 0x80003000 处的数据就不一样.

1.5 网络操作命令#

环境变量 描述
ipaddr 开发板 ip 地址,可以不设置,使用 dhcp 命令来从路由器获取 IP 地址
ethaddr 开发板的 MAC 地址,一定要设置
gatewayip 网关地址
netmask 子网掩码
serverip 服务器 IP 地址,也就是 Ubuntu 主机 IP 地址,用于调试代码

预先设置号网络相关环境变量:

setenv ipaddr 192.168.1.50
setenv ethaddr b8:ae:1d:01:00:00
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
setenv serverip 192.168.1.253
saveenv

1.5.1 ping命令#

ping 192.168.1.100

image

1.5.2 dhcp命令(自动ip获取)#

dhcp 用于从路由器获取 IP 地址,前提得开发板连接到路由器上的,如果开发板是和电脑
直连的,那么 dhcp 命令就会失效。直接输入 dhcp 命令即可通过路由器获取到 IP 地址。

image
DHCP 不单单是获取 IP 地址,其还会通过 TFTP 来启动 linux 内核,输入? dhcp
可查看 dhcp 命令详细的信息:
image

1.5.3 nfs命令#

nfs(Network File System)网络文件系统,通过网络将编译好的 linux 镜像和设备树文件下载
到 DRAM 中,然后就可以直接运行。
虚拟机Ubuntu先搭建好nfs服务,详见:nfs服务搭建 linux搭建nfs服务 | Hexo (fuzidage.github.io)

1
nfs [loadAddress] [[hostIPaddr:]bootfilename]

loadAddress 是要保存的 DRAM 地址,[[hostIPaddr:]bootfilename]是要下载的文件地址,
我们将正点原子官方编译出来的 Linux 镜像文件 zImage 下载到开发板 DRAM 的 0x80800000这个地址处。

1
nfs 80800000 192.168.1.253:/home/zuozhongkai/linux/nfs/zImage

下载过程如图下:
image

下载完成以后查看 0x80800000 地址处的数据,使用命令 md.b 来查看前 0x100 个字节的数据。
image
我们再用UE打开编译出的zImage,对比一下说明 nfs 命令下载到的zImage 是正确的。
image

1.5.4 tftp命令#

tftp 命令的作用和 nfs 命令一样,都是用于通过网络下载东西到 DRAM 中。tftp服务搭建参考:tftp服务搭建 linux搭建tftp和ftp服务 | Hexo (fuzidage.github.io)

tftpboot [loadAddress] [[hostIPaddr:]bootfilename]

loadAddress 是文 件在 DRAM 中的 存放 地址 ,
[[hostIPaddr:]bootfilename]是要从 Ubuntu 中下载的文件。但是和 nfs 命令的区别在于,tftp 命令不需要输入文件在 Ubuntu 中的完整路径,只需要输入文件名即可。比如我们现在将 tftpboot 文件夹里面的 zImage 文件下载到开发板 DRAM 的 0X80800000 地址处。

1
tftp 80800000 zImage

image

1.6 emmc和sd卡指令#

image

mmc相关命令:

命令 描述
mmc info 输出 MMC 设备信息
mmc read 读取 MMC 中的数据
mmc wirte 向 MMC 设备写入数据
mmc rescan 扫描 MMC 设备
mmc part 列出 MMC 设备的分区
mmc dev 切换 MMC 设备
mmc list 列出当前有效的所有 MMC 设备
mmc hwpartition 设置 MMC 设备的分区
mmc bootbus…… 设置指定 MMC 设备的 BOOT_BUS_WIDTH 域的值
mmc bootpart…… 设置指定 MMC 设备的 boot 和 RPMB 分区的大小
mmc partconf…… 设置指定 MMC 设备的 PARTITION_CONFG 域的值
mmc rst 复位 MMC 设备
mmc setdsr 设置 DSR 寄存器的值

1.6.1 mmc info#

image

当前选中的 MMC 设备是EMMC,版本为 5.0,容量为 7.1GiB(EMMC为 8GB),速度为 52000000Hz=52MHz,8 位宽的总线。还有一个与 mmc info 命令相同功能的命令:mmcinfo,“mmc”和“info”之间没有空格。

1.6.2 mmc rescan#

mmc rescan 命令用于扫描当前开发板上所有的 MMC 设备,包括 EMMC 和 SD 卡。

1.6.3 mmc list#

查看当前开发板一共有几个 MMC 设备.
image

可以看出当前开发板有两个 MMC 设备:FSL_SDHC:0 和 FSL_SDHC:1 (eMMC),这是因为我现在用的是 EMMC 版本的核心板,加上 SD 卡一共有两个 MMC 设备,FSL_SDHC:0 是 SD卡,FSL_SDHC:1(eMMC)是 EMMC。默认会将 EMMC 设置为当前 MMC 设备,这就是为什么输入mmc info查询到的是 EMMC 设备信息,而不是 SD 卡。要想查看 SD 卡信息,就要使用命令mmc dev来将 SD 卡设置为当前的 MMC 设备。

1.6.4 mmc dev#

选择切换当前emmc设备。

mmc dev [dev] [part]

[dev]用来设置要切换的 MMC 设备号,[part]是分区号。如果不写分区号的话默认为分区 0。

1
mmc dev 0 //切换到 SD 卡,0 为 SD 卡,1 为 eMMC

image
切换到sd这个mmc后,输入mmc info命令既可以查看sd信息:
image

可以看到当前 SD 卡为 3.0 版本的,容量为 14.8GiB(16GB 的 SD 卡),4 位宽的总线。

image

1.6.5 mmc part#

查看mmc分区

1
2
mmc dev 1 //切换到 EMMC
mmc part //查看 EMMC 分区

image

切到核心板的emmc后,mmc part显示分区信息,此时 EMMC 有两个分区,第一个分区起始扇区为 20480,长度为 262144 个扇区;第二个分区起始扇区为 282624,长度为 14594048 个扇区。
如果 EMMC 里面烧写了 Linux 系统的话,EMMC 是有 3 个分区的,第 0 个分区存放 uboot,第 1 个分区存放Linux 镜像文件和设备树,第 2 个分区存放根文件系统。但是在上图中只有两个分区,那是因为第 0 个分区没有格式化,所以识别不出来,实际上第 0 个分区是存在的。一个新的 SD卡默认只有一个分区,那就是分区 0,所以前面讲解的 uboot 烧写到 SD 卡,其实就是将 u-boot.bin烧写到了 SD 卡的分区 0 里面.

1
mmc dev 1 2 //将 EMMC 的分区 2 设置为当前 MMC 设备

image

1.6.6 mmc read#

1
mmc read addr blk# cnt

读mmc设备中的数据。addr 是数据读取到 DRAM 中的地址,blk 是要读取的块起始地址(十六进制),一个块是 512字节,这里的块和扇区是一个意思,在 MMC 设备中我们通常说扇区,cnt 是要读取的块数量(十六进制)。比如从 EMMC 的第 1536(0x600)个块开始,读取 16(0x10)个块的数据到 DRAM 的0X80800000 地址处

1
2
mmc dev 1 0 //切换到 MMC 分区 0
mmc read 80800000 600 10 //读取数据

image
这里我们还看不出来读取是否正确,通过 md.b 命令查看 0x80800000 处的数据就行了,查看 16*512=8192(0x2000)个字节的数据。
image

可以看到baudrate=115200.board_name=EVK.board_rev=14X14等字样,
这个就是 uboot 中的环境变量。EMMC 核心板 uboot 环境变量的存储起始地址就是1536*512=786432

1.6.7 mmc write#

1
mmc write addr blk# cnt

从DRAM写数据到mmc设备。
比如通过 nfs 或者 tftp 命令将新的 u-boot.bin 下载到开发板的 DRAM 中,然后再使用命令mmc write将其写入到 MMC设备中。

1
2
3
mmc dev 0 //切换到 SD 卡
version //查看uboot版本号
tftp 80800000 u-boot.imx

image
可以看出,u-boot.imx 大小为 379904 字节,379904/512=742,所以我们要向 SD 卡中写入742 个块,如果有小数的话就要加 1 个块。使用命令mmc write从 SD 卡分区 0 第 2 个块(扇区)开始烧写,一共烧写 742(0x2E6)个块

1
2
mmc dev 0 0
mmc write 80800000 2 2E6

image

烧写成功,重启开发板(从 SD 卡启动),重启以后再输入 version 来查看版本号:
image
这样就给mmc0也就是sd卡烧录了uboot, 同理要烧录emmc也是同理,切到mmc1即可:

1
2
3
4
mmc dev 1 0 //切换到 EMMC 分区 0
tftp 80800000 u-boot.imx //下载 u-boot.imx 到 DRAM
mmc write 80800000 2 32E //烧写 u-boot.imx 到 EMMC 中
mmc partconf 1 1 0 0 //分区配置,EMMC 需要这一步!

注意:千万不要写 SD 卡或者 EMMC 的前两个块(扇区),里面保存着分区表!

1.6.7 mmc erase#

1
mmc erase blk# cnt

擦除 MMC 设备的指定块, blk 为要擦除的起始块,cnt 是要擦除的数量。

1.7 文件操作命令(fat文件系统)#

1.7.1 fatinfo#

fatinfo <interface> [<dev[:part]>]

于查询指定 MMC 设备分区的文件系统信息,interface 表示接口,比如 mmc,dev 是查询的设备号,part 是要查询的分区。比如我们要查询 EMMC 分区 1 的文件系统信息:

1
fatinfo mmc 1:1

image
上图显示mmc1也就是emmc设备的分区1的文件系统为fat32格式。

1.7.1 fatls#

fatls <interface> [<dev[:part]>] [directory]

查询设备分区的目录和文件信息。interface 是要查询的接口,比如 mmc,dev 是要查询的设备号,part 是要查询的分区,directory是要查询的目录。

1
fatls mmc 1:1   //查询 mmc1设备(EMMC 设备)中分区 1 中的所有的目录和文件

image

1.7.3 fstype#

fstype <interface> <dev>:<part>

查看 MMC 设备某个分区的文件系统格式.正点原子 EMMC 核心板上的 EMMC 默认有 3 个分区, 分区 0 格式未知,因为分区 0 存放的 uboot,并且分区 0 没有格式化,所以文件系统格式未知。分区 1 的格式为 fat,分区 1 用于存放 linux 镜像和设备树。分区 2 的格式为 ext4,用于存放 Linux 的根文件系统(rootfs)。

1
2
3
fstype mmc 1:0
fstype mmc 1:1
fstype mmc 1:2

image

1.7.4 fatload#

fatload <interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]]

将指定的文件读取到 DRAM.
interface 为接口,比如 mmc,dev 是设备号,part 是分区,addr 是保存在 DRAM 中的起始地址,filename 是要读取的文件名字。bytes 表示读取多少字节的数据,如果 bytes 为 0 或者省略的话表示读取整个文件。pos 是要读的文件相对于文件首地址的偏移,如果为 0 或者省略的话表示从文件首地址开始读取.

fatload mmc 1:1 80800000 zImage  //将 EMMC 分区 1 中的 zImage 文件读取到 DRAM 中的0X80800000 地址处

image

225ms 内读取了 6785272 个字节的数据,速度为 28.8MiB/s,速度是非常快的,因为这是从 EMMC 里面读取的,而 EMMC 是 8 位的,速度肯定会很快的。

1.7.5 fatwrite#

将 DRAM 中的数据写入到 MMC 设备。
uboot 默认没有使能 fatwrite 命令,需要修改板子配置头文件,比如 mx6ullevk.h、 mx6ull_alientek_emmc.h 等,需要开启宏:

1
#define CONFIG_FAT_WRITE /* 使能 fatwrite 命令 */

image

fatwrite <interface> <dev[:part]> <addr> <filename> <bytes>

interface 为接口,比如 mmc,dev 是设备号,part 是分区,addr 是要写入的数据在 DRAM中的起始地址,filename 是写入的数据文件名字,bytes 表示要写入多少字节的数据。

比如我们通过nfs or tftp命令下载镜像到DRAM后,通过fatwrite去烧写image:
image
zImage 大小为6785272(0X6788f8)个字节(注意,由于开发板系统在不断的更新中,因此zImage 大小不是固定的,一切以实际大小为准),接下来使用命令fatwrite将其写入到 EMMC 的分区 1 中,文件名字为 zImage:

fatwrite mmc 1:1 80800000 zImage 6788f8

image

完成以后使用fatls命令查看一下 EMMC 分区 1 里面的文件:
image

1.8 文件操作命令(ext文件系统)#

ext文件系统是linux常用的文件系统,一般rootfs就是典型的ext2文件系统。
ext2load、ext2ls、ext4load、ext4ls 和 ext4write。这些命令的含义和使用与 fatload、fatls 和 fatwrite一样,只是 ext2 和 ext4 都是针对 ext 文件系统的。

1
ext4ls mmc 1:2	//emmc设备分区2就是ext4文件系统,存放了rootfs

image

1.9 nandflash操作命令#

输入? nand即可查看NAND 相关命令:
image

1.9.1 nand info#

打印 NAND Flash 信息:
image

1.9.2 nand device#

用于切换 NAND Flash,如果你的板子支持多片 NAND 的话就可以使用此命令来设置当前所使用的 NAND。

1.9.3 nand erase#

nand erase 命令用于擦除 NAND Flash,NAND Flash 的特性(位翻转,只能由1变成0,而不能由0变成1)决定了在向 NAND Flash 写数据之前一定要先对要写入的区域进行擦除.

1
2
3
nand erase[.spread] [clean] off size //从指定地址开始(off)开始,擦除指定大小(size)的区域。
nand erase.part [clean] partition //擦除指定的分区
nand erase.chip [clean] //全篇擦除

1.9.3 nand write#

nand write addr off size

addr 是要写入的数据首地址,off 是 NAND 中的目的地址,size 是要写入的数据大小。

编译出来 NAND版本的 kernel 和 dtb 文件,在烧写之前要先对 NAND 进行分区,也就是规划好 uboot、linux kernel、设备树和根文件系统的存储区域,I.MX6U-ALPHA 开发板出厂系统 NAND 分区如下:

1
2
3
4
5
6
0x000000000000-0x0000003FFFFF : "boot"
0x000000400000-0x00000041FFFF : "env"
0x000000420000-0x00000051FFFF : "logo"
0x000000520000-0x00000061FFFF : "dtb"
0x000000620000-0x000000E1FFFF : "kernel"
0x000000E20000-0x000020000000 : "rootfs"

一共有六个分区,第一个分区存放 uboot,地址范围为 0x0~0x3FFFFF(共 4MB);第二个分区存放 env(环境变量),地址范围为 0x400000~0x420000(共 128KB);第三个分区存放 logo(启动图标),地址范围为 0x420000~0x51FFFF(共 1MB);第四个分区存放 dtb(设备树),地址范围为0x520000~0x61FFFF(共 1MB);第五个分区存放 kernel(也就是 linux kernel),地址范围为0x620000~0xE1FFFF(共 8MB);剩下的所有存储空间全部作为最后一个分区,存放 rootfs(根文件系统)。

1
2
3
tftp 0x87800000 zImage //下载 zImage 到 DRAM 中
nand erase 0x620000 0x800000 //从地址 0x620000 开始擦除 8MB 的空间
nand write 0x87800000 0x620000 0x800000 //将接收到的 zImage 写到 NAND 中

这里我们擦除了 8MB 的空间,因为一般 zImage 就是 6,7MB 左右,8MB 肯定够了,如果不够的话就再多擦除一点就行了。同理烧录dtb:

1
2
3
tftp 0x87800000 imx6ull-14x14-emmc-7-1024x600-c.dtb //下载 dtb 到 DRAM 中
nand erase 0x520000 0x100000 //从地址 0x520000 开始擦除 1MB 的空间
nand write 0x87800000 0x520000 0x100000 //将接收到的 dtb 写到 NAND 中

1.9.4 nand read#

nand read addr off size

从 NAND 中的指定地址读取指定大小的数据到 DRAM.
addr 是目的地址,off 是要读取的 NAND 中的数据源地址,size 是要读取的数据大小。

1
nand read 0x83000000 0x520000 0x19000  //读取设备树(dtb)文件到 0x83000000 地址处

image

1.10 设备树相关#

1.10.1 fdt addr#

设置设备树起始地址:

1
2
nand read 0x83000000 0x520000 0x19000 //比如把nand中dtb分区数据读到dram
fdt addr 83000000 //设置好设备树起始地址

1.10.2 fdt header#

查看设备树头部信息:

fdt header

image

1.10.3 fdt print#

解析出dts内容:
image

1.11 启动相关#

1.11.1 bootz (启动zImage)#

bootz [addr [initrd[:size]] [fdt]]

addr 是 Linux 镜像文件在 DRAM 中的位置,initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用‘-’代替即可,fdt 就是设备树文件在 DRAM 中的地址.

1
2
3
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb
bootz 80800000 - 83000000

image
换一张启动方式:从mmc1也就是emmc启动:

1
2
3
fatload mmc 1:1 80800000 zImage
fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb
bootz 80800000 - 83000000

image

1.11.1 bootm (启动uImage)#

bootm [addr [initrd[:size]] [fdt]]

bootm 命令和 bootz 类似,它是启动 uImage 镜像。uImage是U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的“头”,说明这个映像文件的类型、加载位置、生成时间、大小等信息。
bootm如果不需要启动设备树:

bootm addr

1.11.3 boot#

boot 会读取环境变量 bootcmd 来启动 Linux 系统:
比如设置bootcmd如下,从网络启动linux:

1
2
3
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 - 83000000'
saveenv
boot

image

同理,如果想从emmc启动linux,设置bootcmd如下:

1
2
3
setenv bootcmd 'fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 - 83000000'
savenev
boot

image

1.11.4 go命令#

go addr

跳到指定的地址处执行, addr表示DRAM地址

1
2
tftp 87800000 printf.bin	//一个裸机程序,打印输入的按键,将两个整数相加
go 87800000

image

1.11.5 run#

run 命令用于运行环境变量中定义的命令,比如可以通过run bootcmd来运行 bootcmd 中的启动命令:

1
2
3
4
5
setenv mybootemmc 'fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb;bootz 80800000 - 83000000'
setenv mybootnand 'nand read 80800000 4000000 800000;nand read 83000000 6000000 100000;bootz 80800000 - 83000000'
setenv mybootnet 'tftp 80800000 zImage; tftp 83000000imx6ull-14x14-emmc-7-1024x600-c.dtb;
bootz 80800000 - 83000000'
saveenv

设置了3个环境变量,可以run mybootemmc或者run mybootnand或者run mybootnet来分别从emmc启动,从nand启动,从网络启动。

1.12 内存测试mtest#

mtest [start [end [pattern [iterations]]]]

start 是要测试的 DRAM 开始地址,end 是结束地址,比如我们测试 0X80000000~0X80001000这段内存,输入mtest 80000000 80001000
image
可以看出,测试范围为 0X80000000~0X80001000,已经测试了 486 次,如果要结束测试就按下键盘上的“Ctrl+C”键。