1. RK3506卡片电脑U-Boot加载DTB故障深度解析
最近在调试万象奥科RK3506卡片电脑时,遇到了一个典型问题:U-Boot启动时无法加载设备树DTB文件,导致系统启动失败。这个看似简单的故障背后,其实涉及到Rockchip平台特有的启动流程设计。作为嵌入式开发者,这类问题在实际项目中经常遇到,今天我就结合自己的调试经验,带大家彻底搞懂这个问题的来龙去脉。
先看故障现象:系统启动时串口输出卡在以下错误信息:
code复制Failed to load DTB, ret=-19
No valid DTB, ret=-22
Failed to get kernel dtb, ret=-22
Net: No ethernet found.
表面上看是网络初始化失败,但实际根源在于DTB加载异常。这个问题会导致系统无法识别硬件配置,进而影响后续所有驱动初始化。
2. Rockchip平台启动机制剖析
2.1 RK3506的两种boot.img格式
RK3506 SDK支持两种boot镜像格式,这对理解问题至关重要:
FIT Image格式:
- 使用U-Boot特有的FIT(Flattened Image Tree)格式
- 通过ITS文件(zboot.its/thunderboot.its)描述镜像结构
- 特点是将kernel、dtb、resource等打包成单一镜像
- 支持完整性校验和签名验证
Android Bootimg格式:
- 传统Android boot镜像格式
- 使用mkbootimg工具生成
- 结构简单,但扩展性较差
- 在Rockchip平台上通常需要配合resource分区使用
2.2 U-Boot的DTB加载流程
RK3506的U-Boot在启动时会执行以下关键步骤:
- 从存储介质读取boot.img
- 解析镜像头部信息
- 根据配置查找DTB位置
- 加载并验证DTB
- 应用设备树配置
问题就出在第3步:U-Boot的resource_setup_blk_list()函数期望从特定位置获取DTB,但实际存储位置与预期不符。
3. 问题根源深度分析
3.1 ITS文件配置差异
通过对比SDK中的两个ITS模板文件,发现了关键差异:
thunderboot.its(问题配置):
dts复制/dts-v1/;
/ {
images {
fdt {
data = /incbin/("@KERNEL_DTB@");
type = "flat_dt";
};
kernel {
data = /incbin/("@KERNEL_IMG@");
type = "kernel";
};
// 缺少resource节点
};
configurations {
conf {
fdt = "fdt";
kernel = "kernel";
// 缺少multi="resource"引用
};
};
};
zboot.its(正确配置):
dts复制/dts-v1/;
/ {
images {
fdt {
data = /incbin/("@KERNEL_DTB@");
type = "flat_dt";
};
kernel {
data = /incbin/("@KERNEL_IMG@");
type = "kernel";
};
resource {
data = /incbin/("@RESOURCE_IMG@");
type = "multi";
arch = "arm";
compression = "none";
hash {
algo = "sha256";
};
};
};
configurations {
conf {
fdt = "fdt";
kernel = "kernel";
multi = "resource"; // 关键配置
};
};
};
3.2 根本原因总结
- 配置缺失:thunderboot.its缺少resource节点和multi引用
- 加载机制不匹配:U-Boot期望从resource区域加载DTB,但实际DTB被放在其他位置
- 校验失败:由于加载位置错误,导致哈希校验无法通过
4. 解决方案实现与验证
4.1 方案一:切换至zboot.its配置(推荐)
实施步骤:
- 修改板级配置文件:
bash复制vim rk3506_linux6.1_sdk/device/rockchip/rk3506/rockchip_rk3506_g_mini_defconfig
找到并修改以下配置:
code复制# 修改前
RK_BOOT_FIT_ITS_NAME="thunderboot.its"
# 修改后
RK_BOOT_FIT_ITS_NAME="zboot.its"
- 重新编译内核:
bash复制cd rk3506_linux6.1_sdk
./build.sh kernel
- 烧录验证:
bash复制cd rockdev
sudo upgrade_tool di -p parameter.txt
sudo upgrade_tool di -s MiniLoaderAll.bin
sudo upgrade_tool di -b boot.img
sudo upgrade_tool di -rootfs rootfs.img
sudo upgrade_tool di -oem oem.img
sudo upgrade_tool di -userdata userdata.img
sudo upgrade_tool RD
技术细节:
- 该方案利用SDK已有的正确配置
- 通过FIT机制确保DTB被正确打包和定位
- 不需要修改分区表,风险最小
4.2 方案二:添加独立resource分区
分区表修改:
修改parameter-128M.txt文件:
code复制# 修改前
CMDLINE:mtdparts=:0x00002000@0x00002000(uboot),0x00000800@0x00004000(misc),\
0x00000200@0x00004800(vnvm),0x00007000@0x00004a00(recovery),\
0x00005000@0x0000ba00(boot),0x00020000@0x00010a00(rootfs),\
0x00008000@0x00030a00(oem),-@0x00038a00(userdata:grow)
# 修改后
CMDLINE:mtdparts=:0x00002000@0x00002000(uboot),0x00000800@0x00004000(misc),\
0x00000200@0x00004800(vnvm),0x00007000@0x00004a00(recovery),\
0x00001000@0x0000ba00(resource),0x00004000@0x0000ca00(boot),\
0x00020000@0x00010a00(rootfs),0x00008000@0x00030a00(oem),\
-@0x00038a00(userdata:grow)
烧录步骤:
bash复制sudo upgrade_tool di -p parameter.txt
sudo upgrade_tool di -s MiniLoaderAll.bin
sudo upgrade_tool di -u uboot.img
sudo upgrade_tool di -resource resource.img
sudo upgrade_tool di -b boot.img
sudo upgrade_tool di -rootfs rootfs.img
sudo upgrade_tool di -oem oem.img
sudo upgrade_tool di -userdata userdata.img
sudo upgrade_tool RD
适用场景:
- 需要保持Android标准bootimg格式的项目
- 系统已经使用独立resource分区的设计
- 对启动流程有特殊定制需求的情况
5. 调试技巧与经验分享
5.1 验证方法
成功修复后,串口输出应包含以下关键信息:
code复制RESC: 'boot', blk@0x0000d85f
resource: sha256+
FIT: no signed, no conf required
DTB: rk-kernel.dtb
HASH(c): OK
Model: Rockchip RK3506 EVB1 V10 Board
5.2 常见问题排查
-
烧录后仍报错:
- 检查是否选对了方案对应的烧录命令
- 确认parameter.txt是否同步更新
- 验证boot.img的生成时间是否为新版本
-
DTB校验失败:
- 检查zboot.its中的hash配置
- 确认resource.img是否包含有效DTB
- 尝试关闭安全启动进行测试
-
分区表修改导致的问题:
- 确保分区大小和偏移计算正确
- 保留足够的对齐空间(通常0x1000)
- 避免分区重叠
5.3 性能优化建议
-
启动时间优化:
- 将DTB放在存储介质连续区域
- 适当增加DTB加载缓存
- 考虑使用压缩DTB
-
存储空间优化:
- 精简DTB内容,移除未使用的节点
- 合理分配分区大小,避免浪费
- 考虑使用UBIFS等高效文件系统
6. 方案对比与选型建议
| 评估维度 | 方案一(zboot.its) | 方案二(resource分区) |
|---|---|---|
| 修改复杂度 | 低(改1行配置) | 中(改分区表+烧录) |
| 编译影响 | 需重编kernel | 无需重编 |
| 烧录便利性 | 标准流程 | 需额外烧录resource |
| 分区灵活性 | 依赖FIT机制 | 可自由调整 |
| 兼容性 | 需U-Boot支持FIT | 兼容性更好 |
| 推荐指数 | ★★★★★ | ★★★★☆ |
对于大多数项目,我推荐优先考虑方案一,因为:
- Rockchip SDK默认支持该方案
- 维护成本低,后续升级方便
- 充分利用U-Boot的高级特性
- 减少分区管理复杂度
方案二更适合以下场景:
- 需要与Android生态保持兼容
- 系统已有成熟的分区方案
- 需要灵活更新DTB而不重新编译内核
7. 关键文件路径参考
SDK中的重要文件位置:
code复制# 配置文件
device/rockchip/rk3506/rockchip_rk3506_g_mini_defconfig
device/rockchip/rk3506/parameter-128M.txt
# ITS模板
device/rockchip/.chips/rk3506/zboot.its
device/rockchip/.chips/rk3506/thunderboot.its
# 工具链
tools/linux/Linux_Upgrade_Tool/upgrade_tool
在实际调试中,我习惯先备份原始文件再修改,同时使用git管理配置变更。这个习惯多次帮我快速回退错误的修改,建议各位开发者也都建立自己的版本管理流程。