4. U-Boot入门
U-Boot(Das U-Boot)是嵌入式领域最主流的引导加载程序之一,在 RISC-V 平台上承担着初始化 DDR、加载内核、传递设备树与启动参数等关键职责。理解 U-Boot 的项目结构、源码获取方式、配置编译流程以及常用调试手段,是后续完成 RISC-V Linux 启动链路分析的基础。本节从工程视角出发,把 U-Boot 当作一个可配置、可裁剪、可调试的软件项目来认识。
一、U-Boot 项目结构:从顶层目录看职责划分
U-Boot 源码采用典型的“顶层分类 + 板级目录”组织方式。顶层目录按功能划分,板级与架构相关代码则集中在 arch/、board/、configs/ 中。理解这些目录的职责,能帮助我们在移植和排障时快速定位文件。
arch/riscv/:RISC-V 架构相关代码,包括启动汇编、异常向量、MMU/页表初始化、CPU 与 SoC 支持。board/:具体开发板的板级初始化代码,如 DDR 参数、引脚复用、板级外设。configs/:板级默认配置片段(defconfig),是编译配置的起点。drivers/:驱动模型(DM)下的各类外设驱动,如串口、MMC、网络、GPIO、时钟。common/:通用命令与启动流程实现,如cmd/下的命令、board_r.c等。include/:公共头文件与配置宏定义,configs/生成的.config会映射到include/generated/。dts/与arch/riscv/dts/:设备树源文件,用于描述板级硬件。tools/:构建工具,如mkimage、dtc等。
arch/riscv/ 与 board/<vendor>/<board>/ 是最常修改的两处;前者决定 CPU 启动方式,后者决定板级硬件初始化顺序。二、源码获取:官方仓库与厂商分支
U-Boot 官方源码托管在 denx 的 Git 仓库,RISC-V 相关支持持续合入主线。实际项目中,芯片厂商通常维护自己的分支,包含尚未上游化的 DDR 初始化、时钟树与安全启动代码。
# 获取官方主线源码
git clone https://source.denx.de/u-boot/u-boot.git
cd u-boot
git checkout v2024.01 # 选择稳定版本标签
# 查看当前支持的 RISC-V 板级配置
ls configs/ | grep -i riscv
# 若使用厂商分支(示例)
git remote add vendor https://github.com/vendor/u-boot.git
git fetch vendor
git checkout -b vendor-dev vendor/vendor-2024.01
选择版本时需注意:主线版本通用性好、便于学习;厂商分支与具体 SoC 匹配度高,但可能存在大量私有补丁。学习阶段建议以主线稳定版为主,遇到硬件无法启动时再对照厂商分支。
三、配置与编译流程:从 defconfig 到可烧录镜像
U-Boot 使用 Kconfig 配置系统,流程可概括为“选择 defconfig → 生成 .config → 编译 → 生成镜像”。下图展示了这一数据流与关键产物之间的关系。
典型编译命令如下,注意 RISC-V 交叉工具链前缀通常为 riscv64-linux-gnu- 或 riscv64-unknown-elf-:
# 1. 选择板级配置
make qemu-riscv64_defconfig
# 2. 可选:图形化裁剪
make menuconfig
# 3. 编译
make CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)
# 4. 查看生成产物
ls -lh u-boot u-boot.bin u-boot.map System.map
四、常用命令与调试方法
U-Boot 启动后会进入命令行,常用命令覆盖内存、存储、网络、启动与信息查看。掌握这些命令,可以在不重新烧录的情况下验证硬件与镜像。
| 命令 | 作用 | 典型用法 |
|---|---|---|
bdinfo | 查看板级信息与内存布局 | bdinfo |
printenv | 打印环境变量 | printenv bootargs |
setenv / saveenv | 设置并保存环境变量 | setenv ipaddr 192.168.1.10; saveenv |
md / mw | 读/写内存 | md 0x80000000 0x20 |
mmc / sf | 访问 MMC 或 SPI Flash | mmc dev 0; mmc info |
fatls / ext4ls | 列出文件系统内容 | fatls mmc 0:1 |
tftpboot | 通过网络加载镜像 | tftpboot 0x80200000 Image |
booti / bootm | 启动内核镜像 | booti 0x80200000 - 0x83000000 |
go | 跳转执行裸机程序 | go 0x80000000 |
调试时,串口日志是第一手资料。若 U-Boot 无输出,应优先检查串口引脚、波特率(通常 115200)与时钟配置;若卡在 DDR 初始化,需核对 DDR 参数与电源时序。使用 CONFIG_LOGLEVEL 与 debug() 宏可提升日志详细程度。
u-boot.bin 直接烧到错误偏移,导致 ROM 无法识别;或忽略 u-boot.dtb 与镜像的拼接关系,使 U-Boot 找不到设备树。烧录前务必确认分区表与加载地址。五、案例与复盘:一次 RISC-V 板卡启动失败排查
某 RISC-V 开发板在替换 U-Boot 后无任何串口输出。排查步骤:先用 bdinfo 无法进入,说明未到命令行;检查烧录偏移,发现 u-boot.bin 被写到 0x0 而非厂商规定的 0x20000;重新烧录后串口出现 U-Boot 2024.01 横幅,但卡在 Loading Environment。进一步用 printenv 发现环境变量区地址与 Flash 实际布局不符,修改 CONFIG_ENV_OFFSET 后正常启动。复盘结论:U-Boot 的配置项与硬件分区强相关,任何偏移、地址、时钟参数都必须与板级手册一致。
掌握项目结构、源码获取、配置编译与调试命令后,就可以把 U-Boot 作为可控的启动阶段来观察和修改,为后续分析 RISC-V Linux 启动链路打下工程基础。