一、Uboot
1.1 Uboot简介
Linux 系统要启动就必须需要一个 bootloader 程序,也就说芯片上电以后先运行一段bootloader程序。这段bootloader程序会先初始化DDR等硬件外设,然后将Linux内核flash(NAND,NOR FLASH, SD, MMC 等)拷贝到 DDR 中,最后启动 Linux 内核。它最主要的工作就是启动 Linux 内核, bootloader 和 Linux 内核的关系就跟 PC 上的 BIOS 和 Windows 的关系一样, bootloader 就相当于 BIOS。
Uboot ( Universal Boot Loader)是其中一种bootloader软件,遵循 GPL 协议的开源软件,Uboot官方代码地址。
1.2 Uboot代码类型
uboot 官方的 uboot 源码是给半导体厂商准备的,半导体厂商会下载 uboot 官方的 uboot 源码,然后将自家相应的芯片移植进去。也就是说半导体厂商会自己维护一个版本的 uboot,这个版本的 uboot 相当于是他们定制的。既然是定制的,那么肯定对自家的芯片支持会很全,虽然 uboot 官网的源码中一般也会支持他们的芯片,但是绝对是没有半导体厂商自己维护的 uboot 全面。如果是我们自己做的板子就需会修改半导厂商官方的 uboot,以适应自己的开发板。
种类 | 描述 |
---|---|
uboot 官方的 uboot 代码 | 由 uboot 官方维护开发的 uboot 版本,版本更新快,基本包含所有常用的芯片。 |
半导体厂商的 uboot 代码 | 半导体厂商维护的一个 uboot,专门针对自家的芯片,在对自家芯片支持上要比 uboot 官方的好。 |
开发板厂商的 uboot 代码 | 开发板厂商在半导体厂商提供的 uboot 基础上加入了对自家开发板的支持 |
二、Uboot常用命令
uboot 是可配置的,需要什么命令就使能什么命令。进入 uboot 的命令行模式以后输入“help”或者“?”,然后按下回车即可查看当前 uboot 所支持的命令, 如图:
如果对其中的哪个命令不明白或者使用方法不清楚的可以使用 ( ?+命令 )或 ( help + 命令),如下
2.1 常用命令表
分类 | 命令 | 功能 | 描述 |
---|---|---|---|
信息查询命令 | bdinfo | 查看板子信息 | 可以得出 DRAM 的起始地址和大小、启动参数保存起始地址、波特率、sp(堆栈指针)起始地址等信息 |
printenv | 用于输出环境变量信息 | uboot 也支持 TAB 键自动补全功能,输入“print”然后按下 TAB 键就会自动补全命令,直接输入“print”也可以。 | |
printenv + 环境变量 | 打印出指定的变量信息 | ||
version | 查看 uboot 的版本号 | 打印出uboot 版本号,编译时间,编译器 等信息 | |
环境变量操作命令 | setenv + 变量 + 值 | 设置或者修改环境变量的值 | setenv 修改的是 DRAM中的环境变量值,修改以后要使用 saveenv 命令将修改后的环境变量保存到 flash 中,否则的话uboot 下一次重启会继续使用以前的环境变量值。如要将环境变量 bootdelay 改为 5,就可以使用命令:setenv bootdelay 5 |
setenv + 变量 + ‘值 1 值 2 值 3’ | 设置或者修有多个值的环境变量 | 有时候我们修改的环境变量值可能会有空格,这个时候环境变量值就得用单引号括起来,比如下面修改环境变量 bootcmd 的值:setenv bootcmd 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw | |
setenv + 变量 | 删除一个变量 | 删除一个环境变量只要给这个环境变量赋空值即可 | |
saveenv | 保存修改后的环境变量 | 一般环境变量是存放在外部 flash 中的,uboot 启动的时候会将环境变量从 flash 读取到 DRAM 中 | |
内存 (RAM) 操作命令 | md[.b, .w, .l] + address + [# of objects] | 用于显示内存值 | [.b .w .l]对应 byte、 word 和 long,也就是分别以 1 个字节、 2 个字节、 4 个字节来显示内存值。 address 就是要查看的内存起始地址, [# of objects]表示要查看的数据长度,这个数据长度单位不是字节,而是跟你所选择的显示格式有关。如你设置要查看的内存长度为20(十六进制为 0x14),如果显示格式为.b 的话那就表示 20 个字节;如果显示格式为.w 的话就表示 20 个 word,也就是 202=40 个字节;如果显示格式为.l 的话就表示 20 个 long,也就是204=80 个字节。uboot 命令中的数字都是十六进制的!不是十进制的! 如想查看以 0X80000000 开始的 20 个字节的内存值,显示格式为.b ,应该使用命令:md.b 80000000 14 |
nm [.b, .w, .l] + address | 修改指定地址的内存值 | ?后面就可以输入要修改后的数据 ,输入完成以后按下回车,然后再输入‘q’即可退出 。如以.l 格式修改 0x80000000 地址的数据为 0x12345678。输入命令:nm.l 80000000 | |
mm [.b, .w, .l] + address | 修改指定地址的内存值 | mm与nm不同,address为起始地址,使用 mm 修改内存值的时候地址会自增,可以连续地修改一段地址。 | |
mw [.b, .w, .l] + address + value + [count] | 使用一个指定的数据填充一段内存 | 以.b、 .w 和.l 来指定操作格式, address 表示要填充的内存起始地址, value为要填充的数据, count 是填充的长度。如使用.l 格式将以 0X80000000 为起始地址的 0x10 个内存块(0x10 * 4=64 字节)填充为 0X0A0A0A0A,命令:mw.l 80000000 0A0A0A0A 10 | |
cp [.b, .w, .l] + source + target + count | 数据拷贝命令 | 将 DRAM 中的数据从一段内存拷贝到另一段内存中,或者把 NorFlash 中的数据拷贝到 DRAM 中。使用.l 格式将 0x80000000 处的地址拷贝到 0X80000100 处,长度为 0x10 个内存块(0x10 * 4=64 个字节),命令为:cp.l 80000000 80000100 10 | |
cmp [.b, .w, .l] + addr1 + addr2 + count | 用于比较两段内存的数据是否相等 | 以.b、 .w 和.l 来指定操作格式, addr1 为第一段内存首地址, addr2 为第二段内存首地址, count 为要比较的长度。如以…l格式比较 0x80000000 和 0X80000100 这两个地址数据是否相等,比较长度为 0x10 个内存块(16 * 4=64 个字节),命令为:cmp.l 80000000 80000100 10 | |
网络操作命令 | ping + IP地址 | 检测网络是否连通 | 开发板的网络能否使用,是否可以和服务器(Ubuntu 主机)进行通信,通过 ping 命令就可以验证。注意!只能在 uboot 中 ping 其他的机器,其他机器不能 ping uboot,因为 uboot 没有对 ping命令做处理,如果用其他的机器 ping uboot 的话会失败! 如我的服务器 IP 地址为 192.168.1.250,命令:ping 192.168.1.250 。 |
dhcp | 通过路由器获取到 IP 地址 | dhcp 用于从路由器获取 IP 地址,前提得Uboot设备是连接到路由器上的,如果设备是和电脑直连的,那么 dhcp 命令就会失效。DHCP 不单单是获取 IP 地址,其还会通过 TFTP 来启动 linux 内核 | |
nfs + [loadAddress] +[[hostIPaddr:] bootfilename] | 使用nfs(Network File System)网络文件系统,在两机器时分资源 | loadAddress 是要保存的 DRAM 地址,[[hostIPaddr:]bootfilename]是要下载的文件地址。如下载镜像到80800000,命令为 :nfs 80800000 192.168.1.250:/home/zuozhongkai/linux/nfs/zImage | |
tftp [loadAddress] +[[hostIPaddr:] bootfilename ] | 通过tftp协议下载文件到DRAM | loadAddress 是文件在 DRAM 中的存放地址,[[hostIPaddr:]bootfilename]是要从 Ubuntu 中下载的文件。但是和 nfs 命令的区别在于,tftp 命令不需要输入文件在 Ubuntu 中的完整路径,只需要输入文件名即可。比如我们现在将 tftpboot 文件夹里面的 zImage 文件下载到开发板 DRAM 的 0X80800000 地址处,命令:tftp 80800000 zImage | |
EMMC 和 SD 卡操作命令 | mmc info | 输出当前选中的 mmc设备的信息 | 还有一个与 mmc info 命令相同功能的命令: mmcinfo,“mmc”和“info”之间没有空格。 |
mmc rescan | 扫描当前设备上所有的 MMC 设备 | 包括 EMMC 和 SD 卡,一般认为 EMMC和 SD 卡是同一个东西 | |
mmc list | 查看当前设备一共有几个 MMC 设备 | ||
mmc dev [dev] [part] | 切换当前 MMC 设备 | [dev]用来设置要切换的 MMC 设备号, [part]是分区号。如果不写分区号的话默认为分区 0。使用如下命令切换到 SD卡( 0 ): mmc dev 0 将 EMMC (1)的分区 2 设置为当前 MMC 设置,可以使用如下命令:mmc dev 1 2 | |
mmc part | 查看当前MMC设备的分区情况 | ||
mmc read addr blk# cnt | 读取 mmc 设备的数据 | addr 是数据读取到 DRAM 中的地址, blk 是要读取的块起始地址(十六进制),一个块是 512字节,这里的块和扇区是一个意思,在 MMC 设备中通常说扇区, cnt 是要读取的块数量(十六进制)。如从 EMMC 的第 1536(0x600)个块开始,读取 16(0x10)个块的数据到 DRAM 的0X80800000 地址处,命令:mmc read 80800000 600 10 | |
mmc write addr blk# cnt | 将数据写到当前 MMC 设备里面 | addr 是要写入 MMC 中的数据在 DRAM 中的起始地址, blk 是要写入 MMC 的块起始地址(十六进制), cnt 是要写入的块大小,一个块为 512 字节。我们可以使用命令“mmc write”来升级 uboot,也就是在 uboot 中更新 uboot。这里要用到 nfs 或者 tftp 命令,通过 nfs 或者 tftp 命令将新的 u-boot.bin 下载到开发板的 DRAM 中,然后再将其写入到 MMC设备中。千万不要写 SD 卡或者 EMMC 的前两个块(扇区),里面保存着分区表! | |
mmc erase blk# cnt | 擦除当前 MMC 设备的指定块 | blk 为要擦除的起始块, cnt 是要擦除的数量。没事不要用 mmc erase 来擦除 MMC 设备!!! | |
FAT 格式文件系统操作命令 | fatinfo < interface> [<dev[:part]>] | 查询指定 MMC 设置指定分区的文件系统信息 | interface 表示接口,比如 mmc, dev 是查询的设备号, part 是要查询的分区。比如我们要查询 EMMC 分区 1 的文件系统信息,命令:fatinfo mmc 1:1 |
fatls < interface> [<dev[:part]>] [directory] | 查询 FAT 格式设备的目录和文件信息 | interface 是要查询的接口,比如 mmc, dev 是要查询的设备号, part 是要查询的分区, directory是要查询的目录。如查询 EMMC 分区 1 中的所有的目录和文件,命令:fatls mmc 1:1 | |
fstype < interface>< dev>:< part> | 查看 MMC 设备某个分区的文件系统格式 | 如查看mmc(1)1分区的的文件系统格式,命令: fstype mmc 1:1 | |
fatload < interface> [<dev[:part]> [< addr> [< filename> [bytes [pos]]]]] | 将指定的文件读取到 DRAM 中 | interface 为接口,比如 mmc, dev 是设备号, part 是分区, addr 是保存在 DRAM 中的起始地址, filename 是要读取的文件名字。 bytes 表示读取多少字节的数据,如果 bytes 为 0 或者省略的话表示读取整个文件。pos 是要读的文件相对于文件首地址的偏移,如果为 0 或者省略的话表示从文件首地址开始读取。将 EMMC 分区 1 中的 zImage 文件读取到 DRAM 中的0X80800000 地址处,命令:fatload mmc 1:1 80800000 zImage | |
fatwrite < interface> <dev[:part]> < addr> < filename> < bytes> | 将 DRAM 中的数据写入到 MMC 设备中 | uboot 默认没有使能 fatwrite 命令,需要修改板子配置头文件。 interface 为接口,比如 mmc, dev 是设备号, part 是分区, addr 是要写入的数据在 DRAM中的起始地址, filename 是写入的数据文件名字, bytes 表示要写入多少字节的数据。可以通过 fatwrite 命令在 uboot 中更新 linux 镜像文件和设备树。如更新 linux 镜像文件 zImage命令为:fatwrite mmc 1:1 80800000 zImage 0x5c2720 | |
EXT 格式文件系统操作命令 | ext2load、 ext2ls、 ext4load、 ext4ls 和 ext4write | 这些命令与FAT 格式文件系统操作命令的含义及使用相同,可参考上面FAT 格式文件系统操作命令使用 | |
NAND操作命令 | nand info | 打印 NAND Flash 信息 | 给出了 NAND 的页大小、 OOB 域大小,擦除大小等信息 |
nand device | 切换当前 NAND Flash | 如果板子支持多片 NAND 就可以使用此命令来设置当前所使用的 NAND。这个需要你的 CPU 有两个 NAND 控制器,并且两个 NAND 控制器各接一片 NAND Flash。不过一般情况下 CPU 只有一个 NAND 接口,而且在使用中只接一片 NAND | |
nand erase[.spread] [clean] off size | 擦除 NAND Flash, 从指定地址开始(off)开始,擦除指定大小(size)的区域。 | NAND Flash 的特性决定了在向 NAND Flash 写数据之前一定要先对要写入的区域进行擦除。如从地址 0 开始擦除 1MB 的空间:nand erase 0x0 0x100000 | |
nand erase.part [clean] partition | 擦除指定的分区 | ||
nand erase.chip [clean] | 全篇擦除 | ||
nand write addr off size | 向 NAND 指定地址写入指定的数据 | addr 是要写入的数据首地址, off 是 NAND 中的目的地址, size 是要写入的数据大小。将0x87800000处开始的1M数写到 NAND 中 :nand write 0x87800000 0x0 0x100000 | |
nand read addr off size | 从 NAND 中的指定地址读取指定大小的数据到 DRAM 中 | addr 是目的地址, off 是要读取的 NAND 中的数据源地址, size 是要读取的数据大小。比如我们读取0x6000000处开始的0x19000字节数据到 0x83000000 地址处:nand read 0x83000000 0x6000000 0x19000 | |
BOOT操作命令 | bootz [addr [initrd[:size]] [fdt]] | 从内存启动zImage文件 | addr 是 Linux 镜像文件在 DRAM 中的位置, initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用‘-’代替即可, fdt 就是设备树文件在 DRAM 中的地址。如zImage放在0x80800000开始处,设备树放在0x83000000处,则启动使用:bootz 80800000 – 83000000 |
bootm [addr [initrd[:size]] [fdt]] | 用于启动 uImage 镜像文件 | addr 是 uImage镜像文件在 DRAM 中的位置, initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用‘-’代替即可, fdt 就是设备树文件在 DRAM 中的地址。使用方法与bootz相同,不同是bootm用于启动uImage | |
boot | 用来启动 Linux 系统 | boot 需要读取环境变量 bootcmd 来启动 Linux 系统, bootcmd 是一个很重要的环境变量!其名字分为“boot”和“cmd”,也就是“引导”和“命令”,说明这个环境变量保存着引导命令,其实就是启动的命令集合,具体的引导命令内容是可以修改的。如想使用 tftp 命令从网络启动 Linux 那么就可以设置 bootcmd 为tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000,然后使用 saveenv 将 bootcmd 保存起来。然后直接输入 boot 命令即可从网络启动 Linux 系统 | |
其他命令 | reset | 复位重启 | |
go addr [arg …] | 跳到指定的地址处执行应用 | addr 是应用在 DRAM 中的首地址,arg是执行应用的参数。如使用 tftp 命令将 应用程序xxx.bin文件下载到开发板 DRAM 的 0X87800000 地址处,因为裸机例程的链接首地址就是 0X87800000,最后使用 go 命令启动xxx.bin 这个应用,命令如下:1. tftp 87800000 xxx.bin 2. go 87800000 | |
run + 环境变量 | 运行环境变量中定义的命令 | 在调试 Linux 系统的时候常常要在网络启动和 EMMC/NAND 启动之间来回切换,这里我们就可以通过自定义环境变量来实现不同的启动方式,比如定义环境变量 mybootemmc 表示从 emmc 启动,运行run mybootemmc 即可从emmc启动。 | |
mtest [start [end [pattern [iterations]]]] | 内存读写测试命令 | 可以用来测试自己开发板上的 DDR,start是要测试的DRAM 开始地址, end 是结束地址。比如我们测试 0X80000000~0X80001000这段内存,输入mtest 80000000 80001000 |