4. Bootloader原理与移植
Bootloader是嵌入式Linux系统上电后运行的第一段软件,它负责初始化关键硬件、建立运行环境,并最终把Linux内核加载到内存中启动。U-Boot(Universal Boot Loader)是嵌入式领域使用最广泛的开源Bootloader,支持ARM、MIPS、RISC-V、x86等多种架构,具备网络、存储、USB、文件系统等丰富驱动,是产品级方案的首选。
一、U-Boot的两阶段启动流程
U-Boot采用典型的SPL+U-Boot两阶段设计。第一阶段通常称为SPL(Secondary Program Loader)或MLO,运行在片内SRAM中,代码量小,主要完成时钟、DDR、串口等最基础初始化,然后把完整的U-Boot镜像搬运到DDR并跳转执行。第二阶段是完整的U-Boot,具备命令行、驱动模型、环境变量、网络协议栈等能力,最终引导内核。
从代码执行角度看,启动路径大致为:_start → lowlevel_init → _main → board_init_f → relocate_code → board_init_r → main_loop。其中board_init_f在重定位前完成内存布局规划,board_init_r在重定位后完成外设、环境变量、控制台等初始化,最后进入命令行循环。
二、常用命令与环境变量
U-Boot命令行是调试阶段最直接的工具。常用命令包括:printenv查看环境变量,setenv设置变量,saveenv保存到存储介质,mmc操作SD/eMMC,fatload/ext4load加载文件,tftp通过网络下载,bootz/bootm启动内核,md/mw读写内存,ping测试网络。
# 查看与设置环境变量
printenv bootcmd
setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rw'
saveenv
# 从 eMMC 加载内核与设备树
fatload mmc 0:1 0x80800000 zImage
fatload mmc 0:1 0x83000000 imx6ull.dtb
bootz 0x80800000 - 0x83000000
# 网络下载并启动
tftp 0x80800000 zImage
tftp 0x83000000 imx6ull.dtb
bootz 0x80800000 - 0x83000000
环境变量中最重要的两个是bootcmd和bootargs。bootcmd定义自动启动时执行的命令序列,bootargs是传递给内核的启动参数,决定控制台、根文件系统、内存大小等关键配置。生产环境通常把bootcmd设置为从eMMC加载,调试阶段则常改为TFTP网络启动,提高迭代效率。
三、板级移植的关键步骤
U-Boot移植的核心是“以相近参考板为起点,逐步适配自己的硬件”。以NXP i.MX6ULL为例,通常选择mx6ull_14x14_evk作为参考板,复制其板级目录与配置文件,然后修改DDR参数、引脚复用、时钟树、存储设备、网络PHY等。
| 移植项 | 关键文件/配置 | 常见问题 |
|---|---|---|
| 板级目录 | board/freescale/mx6ull_xxx/ | Kconfig、Makefile未同步 |
| 配置文件 | configs/mx6ull_xxx_defconfig | DDR型号、容量不匹配 |
| 设备树 | arch/arm/dts/mx6ull_xxx.dts | 引脚复用、PHY地址错误 |
| DDR初始化 | spl.c / ddr.c | 时序参数错误导致SPL挂死 |
| 环境变量存储 | CONFIG_ENV_IS_IN_MMC | 偏移地址与分区冲突 |
四、编译与烧写方法
U-Boot编译通常分两步:先配置,再编译。以ARM平台为例:
# 清理并配置
make distclean
make mx6ull_xxx_defconfig
# 编译(指定交叉编译器)
make CROSS_COMPILE=arm-linux-gnueabihf- -j8
# 生成物
# u-boot.bin 完整镜像
# SPL 第一阶段镜像
# u-boot.imx 带IVT头的可烧写镜像
烧写方式取决于存储介质。SD卡可用dd命令写入:
sudo dd if=u-boot.imx of=/dev/sdb bs=1k seek=1 conv=fsync
eMMC量产时通常通过USB下载模式(如i.MX的MFG Tool)或已有U-Boot中的mmc write命令更新。更新时务必确认偏移地址,避免覆盖分区表或内核分区。
dd写错盘会直接破坏主机数据。建议先用lsblk确认设备名,并在量产脚本中加入设备序列号校验。五、常见误区与复盘
- 只改设备树不改配置:U-Boot的设备树与内核设备树是两套,引脚、时钟、DDR参数需在U-Boot侧单独确认。
- 环境变量保存位置冲突:环境变量偏移与分区表重叠,会导致保存后无法启动,需核对
CONFIG_ENV_OFFSET。 - 忽略SPL日志:SPL阶段无输出往往意味着DDR或时钟初始化失败,应优先用示波器确认晶振与电源。
- bootargs与内核配置不匹配:控制台设备名、根文件系统类型写错,内核会panic,需与内核config逐项对照。
掌握U-Boot的启动流程、命令体系、环境变量机制和板级移植方法,是嵌入式Linux系统构建的基础能力。实际项目中,建议把可用的环境变量、烧写脚本和调试命令整理成板级文档,形成可复用的工程资产。