imx6ull uboot 使用*
- Uboot 学习笔记
Uboot 学习笔记
linux系统的组成部分

前面我们学习的是裸机开发,主要使用寄存器操作,实现对外设的驱动,掌握的外设的底层原理。之后就可以把重心放到linux驱动框架上。
在移植linux系统之前,需要
- 移植bootloader(用于启动linux内核, bootloader有很多种,常见的是uboot)
- 再移植linux内核
- 再移植根文件系统rootfs(这个里面包含了最常用的命令和文件)
这三个一起构成了完整的linux系统。
注:大部分移植的工作,芯片原厂(NXP)已经做好了,我们所做的移植,其实就是让他在特定的开发板上跑起来。
uboot 介绍
芯片上电以后,先运行一段bootloader程序,bootloader内部会初始化ddr等外设(RAM)(实际工作复杂的多),然后将Linux 内核从 flash(ROM)(NAND,NOR FLASH,SD,MMC 等)拷贝到 DDR(RAM) 中,最后启动 Linux 内核
有很多现成的 bootloader 软件可以使用,比如 U-Boot、vivi、RedBoot 等
uboot 的全称是 Universal Boot Loader,是一个遵循 GPL 协议的开源软件,是一个裸机代码,可以看作是一个裸机综合例程。
现在的 uboot 已经支持液晶屏、网络、USB 等高级功能。
可以从uboot官网找到uboot的源码,但是这个源码一般是给芯片原厂用的,用来给自家的芯片移植uboot,他们会维护自己的uboot版本。所以我们自己用肯定只能到NXP的官网去下载定制的uboot代码, 但是这个定制uboot都是针对原厂(NXP)的评估板的,如果是我们自己的板子,还需要二次修改NXP官方的uboot,使其适配我们自己的开发板。
你也可以在购买了第三方开发板以后使用半导体厂商提供的 uboot,只不过有些外设驱动可能不支持,需要自己移植,这个就是我们常说的 uboot 移植。
uboot 编译
我的imx的开发板是512G ddr, 8G emmc, 1G sd卡
|

注:uboot只是引导程序,是一个综合裸机例程,也可以引导其他系统,也可以支持其他架构,也可以拓展其他外设。
所以在编译 uboot 之前,一定要根据自己的需求配置 uboot。mx6ull_14x14_ddr512_emmc_defconfig就是正点原子针对 I.MX6U-ALPHA 的 EMMC 核心板编写的配置文件。
这个配置文件的目录在uboot/configs中,通过make xxx_defconfig来配置 uboot,xxx_defconfig就是不同板子的配置文件
最终会编译出uboot.bin, uboot.imx这些用于烧录的镜像(和之前的裸机程序一样的镜像文件)
uboot 烧录
直接把编译出来的u-boot.bin当成裸机例程烧录到SD卡即可
uboot 网络(驱动开发调试用)
ping底层网络联通(2层,3层)
ping成功仅验证了开发板与主机的底层网络互通(无需 DHCP 参与,依赖静态配置或已有临时 IP)
dhcp
dhcp命令本质是通过 BOOTP(DHCP 的前身)/DHCP 协议向网络请求 IP 地址、网关、启动文件地址等配置,所以需要你的网络中有一台机器运行 DHCP 服务器(Ubuntu主机,用来给设备分配ip)
Ubuntu 默认无 DHCP 服务:与普通 Windows 系统类似,Ubuntu 桌面版(如你的系统)默认未安装和启用 DHCP 服务器(仅包含 DHCP 客户端),开发板发送的广播请求无法被 Ubuntu 响应,因此仍会出现超时,另外Ubuntu 防火墙可能拦截 DHCP 协议的 UDP 67/68 端口,即使后续安装了 DHCP 服务器,也可能因端口被拦截导致交互失败。
Ubuntu主机 安装dhcp服务器
# 更新软件源 |
配置dhcp服务器内容
sudo vim /etc/dhcp/dhcpd.conf |
指定dhcp服务器使用的网卡
sudo vim /etc/default/isc-dhcp-server |
启动Ubuntu主机dhcp服务器
# 启动DHCP服务 |
关闭防火墙,防止阻挡dhcp服务
# 放行UDP 67/68端口 |
nfs服务(尝试失败,一直超时)
NFS 仅用于文件共享(后续开发板挂载根文件系统等场景),为后续dhcp下载linux内核镜像提供文件下载方法
sudo apt-get install nfs-kernel-server rpcbind |
tftp服务(尝试成功)
nfs,tftp都是传输文件的协议,uboot会在建立好和ubuntu主机的网络通信之后,就开始用文件传输(底层走的是网络tcp,udp)来下载主机上的zImage(内核镜像)。
我们在uboot里面执行dhcp后,会让ubuntu主机给我们分配一个ip,然后默认开始tftp拉取主机的共享文件。但是文档里面让我自己走nfs拉取,我自己尝试了之后,发现非常难用,也无法保证主机的nfs正确建立。
通过设置主机tftp服务后:
# 安装TFTP服务端(Ubuntu/Debian) |
ubuntu主机本地验证,发现确实可以正常拉取文件,这样至少能保证主机这边是正常的。
tftp 127.0.0.1 |
之后uboot端尝试以下拉取,发现直接很快就拉下来了。
# 1. TFTP加载内核到指定地址 |
将 tftpboot 文件夹里面的 zImage 文件下载到开发板 DRAM 的 0X80800000 地址处
uboot RAM 操作
裸机都是对整个设备的寻址空间进行了存储空间映射,所以0x8080 0000, 表示的是RAM的其实地址(SRAM = DDR)
md.(b/w/l) addr(H) count(H) |
uboot ROM 操作
ROM,磁盘,uboot会读取所有mmc设备(SD卡, EMMC, NAND)
mmc info |
可以使用命令mmc write来升级 uboot,也就是在 uboot 中更新 uboot。
- 注:在运行的uboot中,拉取新的uboot.imx镜像到RAM中,然后写入SD卡(我们启动的地址)(为什么要隔两个块?因为前2个block,保存的是分区表),之后重启即可。


uboot 文件操作(不再是磁盘字节操作了)
ROM中格式分布:
正常我们在EMMC里面安装了linux系统,那么他会有3个分区:
- part 0(无格式): uboot (前面会留出2个块存放分区表,不要随便擦除)
- part 1(fat): kernel(zImage) + device tree(dtb)
- part 2(ext): rootfs
fat文件系统格式
# info 查询指定 MMC 设备分区的文件系统信息 |
ext文件系统格式
# EMMC 的分区 2 就是 ext4格式的,使用 ext4ls 就可以查询 EMMC 的分区 2 中的文件和目录 |
mmc0,1分区内容
通过fstype, fatls, fatinfo, 可以查看出emmc(mmc 1), sd(mmc 0)里面的每个分区都是干什么的。
可以看到
sd(mmc 0)
part0: 无文件系统part1: fat- zImage, dtb
part2: fat- 空
emmc(mmc 1)
part0: 无文件系统part1: fat- zImage, dtb
part2: ext- rootfs
(emmc)(mmc 1:2)rootfs,根文件系统里面的内容是这样:
=> ext4ls mmc 1:2 |
(emmc)(mmc 1:1) 的linux内核镜像+设备树文件
=> fatls mmc 1:1 |
这样就可以通过uboot,来从远程下载zimage, dtb,rootfs来更新emmc,来实现在线升级。
分区 0 里面到底是什么?
=> mmc dev 0 |
严格来说,你执行 mmc part 看到的 Part 1 和 Part 2 是受 MBR(主引导记录) 管理的有格式分区。
而你所谓的“分区 0”(即扇区 0 到扇区 20479 之间的区域),在 i.MX 架构中存放的是最核心的启动镜像:
Sector 0 (扇区 0): 存放 MBR 分区表。(前两个块,1k字节)
Sector 2 (偏移 1KB 处): 存放
u-boot.imx。
i.MX6ULL 的 bootROM 固化了启动逻辑,它在加电后会固定去 MMC 设备(SD卡或 EMMC)的 1KB 偏移处 寻找启动头(IVT/DCD 等)。
剩余空闲空间: 用于存放环境变量(如果你配置 U-Boot 存放在 MMC 中)或者空闲。
属性, 分区 1 (FAT), 分区 2 (FAT/EXT) |
所以SD卡为例,我们1G的SD卡,分区0=10MB,分区1=128MB,分区2=822MB
(u-boot.imx = 363KB, zImage = 6MB)
所以绰绰有余
关于环境变量的保存,当你saveenv保存环境变量,你会看到保存到MMC0, sd卡中
=> printenv bootcmd |
实际环境变量:
对于正点原子的 i.MX6ULL 开发板,默认配置通常如下:
- U-Boot 程序: 存储在偏移 $1$ KB ($2$ 扇区) 处。
- 环境变量 (Env): 存储在偏移 $768$ KB (即 $0xC0000$ 字节) 处。
物理地址偏移, 内容, 说明 |
uboot boot操作
uboot 的本质工作是引导 Linux,所以 uboot 肯定有相关的 boot(引导)命令来启动 Linux
要启动 Linux,需要先将 Linux 镜像文件拷贝到 DRAM 中,有两种拷贝方式:
- 从 EMMC 或者 NAND 等ROM中将 Linux 镜像和设备树文
件拷贝到 DRAM - tftp 将 Linux 镜像文件和设备树文件下载到 DRAM 中
不管用那种方法,只要能将 Linux 镜像和设备树文件存到 DRAM 中就行, 然后使用 bootz 命令来启动,bootz 命令用于启动 zImage 镜像文件
bootz [addr [initrd[:size]] [fdt]] |
- addr 是 Linux 镜像文件在 DRAM 中的位置
- initrd 是 initrd 文件在DRAM 中的地址,如果不使用 initrd 的话使用‘-’代替即可
- fdt 就是设备树文件在 DRAM 中的地址
bootz 从远程拉取kernel + dtb到RAM 启动linux内核
因为我们没有根文件系统,所以内核启动后,只会到无法挂在rootfs,然后kernel panic
|

bootz 本地ROM启动
从 EMMC 中启动 Linux 系统的话只需要使用命令 fatload 将 zImage 和imx6ull-14x14-emmc-7-1024x600-c.dtb 从EMMC 的分区 1 中拷贝到 DRAM 中,然后使用命令 bootz 启动即可
bootm
bootm 和 bootz 功能类似,但是 bootm 用于启动 uImage 镜像文件
boot 自动化启动命令
boot 命令也是用来启动 Linux 系统的,只是 boot 会读取环境变量 bootcmd 来启动 Linux 系统, bootcmd这个环境变量保存着引导命令,其实就是启动的命令集合
远程拉取启动
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; |
前面说过 uboot 倒计时结束以后就会启动 Linux 系统,其实就是执行的 bootcmd 中的启动命令
默认就是远程网络启动
从EMMC中启动
修改bootcmd
setenv bootcmd 'fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-14x14- |
最终kernel开始启动,最终会卡在:
[ 3.784511] b310 4096 mmcblk1boot0 (driver?) |
没有找到根文件系统,这个很正常,因为没有设置 uboot 的
bootargs 环境变量,关于 bootargs 环境变量后面会讲解
其他命令
reset
reset //复位重启 |
go
用于跳转到RAM的地方来运行
注:我们从MMC中拷贝东西到RAM中,都是到80800000, 而裸机程序本体的链接地址是因为裸机例程的链接首地址就是 0X87800000
tftp 87800000 printf.bin |
复习裸机烧录的镜像的地址结构
run
run 命令用于运行环境变量中定义的命令,
比如可以通过“run bootcmd”来运行 bootcmd 中的启动命令,这在后面调试linux驱动的时候,会频繁需要切换启动方式,用这个来执行环境变量脚本
setenv mybootemmc 'fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull- 14x14-emmc-7-1024x600-c.dtb;bootz 80800000 - 83000000' |
mtest
mtest 命令是一个简单的内存读写测试命令,可以用来测试自己开发板上的 DDR
mtest [start [end [pattern [iterations]]]] |