嵌入式 Linux 开发 5:u-boot 引导加载程序
简介 u-boot
启动 Linux 是一部三幕剧:bootloader-->kernel-->init@rootfs 如下图所示
而 u-boot 是使用最广泛的 bootloader 软件,它负责初始化硬件为 kernel 构建合适的运行环境。
花时间掌握 u-boot 的编译,烧录,使用是很值得的,不但提高开发效率,还能实现一些高级功能。
u-boot 镜像格式
为了识别 Linux kernel 镜像的属性 u-boot 在镜像文件的前面添加一个较小的头部。
如下图所示 u-boot 提供了一个名为 mkimage 的工具,用于生成这个镜像头部。
uImage
+--------+
| u-boot |
| header |
+--------+ u-boot +--------+
| zImage |<-----------| zImage |
+--------+ mkimage +--------+
导入 Linux 内核
假设按嵌入式 Linux 开发 3:搭建开发环境搭建了 TFTP 服务器。
在 u-boot 命令行设置如下环境变量
setenv ipaddr 192.168.1.103
# 配置目标板 IP
setenv serverip 192.168.1.101
# 配置服务器 IP
setenv tftp tftpboot 7fc0 980uimage
# 通过 TFTP 从服务器下载 kernel 文件 980uimage 到 0x7fc0@SDRAM
setenv boot bootm 7fc0
# 从 0x7fc0@SDRAM 启动 kernel
运行 saveenv
保存环境变量
现在可以体验快速测试 kernel 的流程
- 在开发主机 配置/编译 kernel 并将镜像文件复制到 TFTP 共享目录
- 重启目标板,进入 u-boot 执行
$tftp
和$boot
导入并运行 kernel
传递 rootfs 参数
bootargs=noinitrd root=/dev/nfs rw nfsroot=192.168.1.101:/nfsroot/nuc980_rootfs/rootfs,v3 ip=192.168.1.103:192.168.1.101:192.168.1.1:255.255.255.0 console=ttyS0,115200n8 rdinit=/sbin/init mem=64M
设备树 DTB
为了将底层硬件信息从 u-boot 传递给 Linux kernel 引入了设备树机制。
设备树 DTB(Device Tree Blob)是一个数据库,它代表了一个给定嵌入式 Linux 的硬件元件。
DTB 由设备节点组成,通常描述一个设备或总线,每个节点包含一组描述它的属性。
设备树编译器(dtc)将开发人员可读的设备树源码转换成机器可读的二进制文件,而 u-boot 和 kernel 都能理解这个二进制文件。
一般在 kernel 源码根目录下执行如下命令即可编译 DTB
make ARCH=arm board.dtb
Linux 启动过程
理解下图 Linux 启动全过程很重要,无论是构建相应的组件(u-boot-->kernel-->rootfs),还是解决 bug 或提升性能。
编译与部署 fw_printenv
背景
U-Boot 提供 fw_printenv(fw_setenv)程序,这允许 Linux 在用户空间查看和修改 U-Boot 环境变量。
升级 Linux 镜像经常要用到这个实用程序,下面描述编译和测试的流程。
查找环境变量数值
find $PRJROOT/bootldr -name *.h -print | xargs grep "CONFIG_ENV_" | grep -i <target_name>
#define CONFIG_ENV_OFFSET 0x80000 --> 环境变量在 MTD 偏移量
#define CONFIG_ENV_SIZE 0x20000 --> 环境变量大小
#define CONFIG_ENV_SECT_SIZE 0x20000 --> 环境变量块大小
修改 fw_env.config
cd $(find $PRJROOT/bootldr -name *.h -print | xargs grep "fw_printenv" -l | xargs dirname)
# 进入 env 目录
tar zcvf ./fw_env.config.tar.gz ./fw_env.config
# 备份配置文件
vi ./fw_env.config
# 按环境变量数值修改配置文件
# MTD SPI-dataflash example
# MTD device name Device offset Env. size Flash sector size Number of sectors
/dev/mtd0 0x80000 0x20000
编译
make CROSS_COMPILE=${CROSS}- env -C ../..
编译 env 得在 U-Boot 根目录下执行,编译成功后会生成 fw_printenv 可执行文件。
复制文件到 rootfs
sudo cp -vf ./fw_env.config <target_rootfs_dir>/etc/
sudo cp -vf ./fw_printenv <target_rootfs_dir>/usr/bin/
cd <target_rootfs_dir>/usr/bin/
sudo ln -s ./fw_printenv ./fw_setenv
# 二者是同一个执行文件
建立 lock 目录(仅运行 1 个实体)
cd <target_rootfs_dir>/var/
sudo ln -s ../tmp ./lock
# 建立软链接目录 /var/lock->/tmp
升级板子 rootfs 并测试
fw_printenv
--> 显示 U-Boot 环境变量
fw_setenv ethaddr 00:11:22:33:44:55
--> 配置 MAC 地址
fw_printenv
--> 查看 MAC 地址