在嵌入式Linux开发中,U-Boot作为系统启动的关键环节,其正确烧写直接关系到设备能否正常启动。许多开发者在使用nand write命令更新U-Boot时,会遇到烧写后系统无法启动的问题。本文将深入剖析这一现象背后的技术原理,帮助开发者理解NAND Flash启动的特殊性,以及为何在I.MX6ULL平台上不能简单地使用nand write来更新U-Boot。
NAND Flash与NOR Flash在启动机制上存在本质差异。NOR Flash支持XIP(eXecute In Place),CPU可以直接从NOR Flash中读取并执行代码。而NAND Flash由于接口特性限制,无法直接执行代码,需要先将启动代码加载到RAM中执行。
在I.MX6ULL平台上,NAND Flash启动过程更为复杂。芯片内部ROM代码会从NAND Flash的特定位置读取Boot Control Block(BCB)和Discovery Bad Block Table(DBBT),这两个数据结构对启动过程至关重要:
提示:BCB和DBBT的作用类似于SD卡启动中的IVT(Image Vector Table)和DCD(Device Configuration Data),但实现机制不同。
BCB位于NAND Flash的特定位置(通常为第一个好块),其典型结构如下:
| 字段 | 大小 | 描述 |
|---|---|---|
| 魔数 | 4字节 | 固定值"STMP"标识BCB起始 |
| 版本 | 4字节 | BCB版本信息 |
| 启动搜索次数 | 4字节 | ROM尝试读取BCB的次数 |
| 启动配置 | 4字节 | 启动参数配置 |
| 固件1地址 | 4字节 | 主U-Boot镜像位置 |
| 固件2地址 | 4字节 | 备用U-Boot镜像位置 |
| 保留 | 44字节 | 保留字段 |
DBBT记录了NAND Flash中的坏块信息,确保启动过程中避开这些坏块。其关键特性包括:
在实际操作中,DBBT的生成需要考虑NAND Flash的以下特性:
NXP提供的mfgtool工具在烧写U-Boot时,会调用kobs-ng工具完成以下步骤:
bash复制# kobs-ng的典型使用示例
kobs-ng init -x u-boot.imx --search_exponent=1
直接使用nand write命令烧写U-Boot时,会缺失以下关键步骤:
这导致烧写的U-Boot虽然存在于NAND Flash中,但ROM代码无法正确识别和加载它。
针对I.MX6ULL平台,不同系统组件的更新策略应有所区别:
以下组件可以直接使用nand write命令更新:
更新内核的典型命令序列:
bash复制tftp 0x87800000 zImage
nand erase 0x4000000 0xA00000
nand write 0x87800000 0x4000000 0xA00000
以下组件需要使用专用工具(如mfgtool)更新:
快速验证内核更新:
bash复制# 下载、擦除、写入内核一步完成
tftp 0x87800000 zImage && nand erase 0x4000000 0xA00000 && nand write 0x87800000 0x4000000 0xA00000
设备树更新检查:
bash复制# 读取并验证设备树
nand read 0x83000000 0x6000000 0x19000
fdt addr 0x83000000
fdt print
NAND信息查看:
bash复制# 查看NAND详细信息
nand info
nand bad
现象:使用nand write更新U-Boot后,系统无法启动。
解决方案:
现象:系统有时能启动,有时不能。
可能原因:
排查步骤:
nand bad命令检查坏块分布合理设置BCB搜索参数:
bash复制# 调整search_exponent参数
kobs-ng init -x u-boot.imx --search_exponent=2
启用ECC校验:
分区优化:
在实际项目中,我曾遇到过因NAND Flash老化导致DBBT信息不完整的情况。通过分析发现,原始DBBT没有预留足够的空间记录新增坏块,导致系统随机启动失败。解决方案是重新调整分区布局,为DBBT预留更多空间,并使用更新的kobs-ng工具生成BCB/DBBT结构。