第4章:固件文件结构解析

做量产测试这么多年,我见过太多工程师拿到一个RK固件包就懵了。一个.img文件或者.update文件,里面到底装了啥?为什么有时候刷机失败,换个固件包就好了?今天我就带你把这层窗户纸捅破。

4.1 RK固件包的整体结构

说白了,RK的固件包就是一个大容器。它把多个独立的分区镜像打包在一起,再加上一些元数据信息。我个人习惯把固件包想象成一个「快递箱」——外面是包装(文件头),里面是各种零件(分区镜像)。

常见的固件包有两种格式:

  • .img格式:早期RK芯片用的多,比如RK3128、RK3229。结构相对简单。
  • .update格式:新平台主流格式,比如RK3568、RK3588。带签名校验,安全性更高。

不管哪种格式,核心内容都差不多。我给大家拆开看看:

固件组成部分 说明 是否必须
固件头部 包含魔数、版本号、分区数量等信息
分区表(Parameter) 定义每个分区的起始地址、大小、名称
分区镜像数据 bootloader、uboot、kernel、system等实际数据
校验信息 CRC32或SHA256校验值 新平台必须

核心要点:固件包的本质就是「分区表 + 分区数据」的集合。你理解了分区表,就理解了固件包的灵魂。

4.2 分区表(Parameter)深度解析

分区表,在RK平台里通常叫parameter.txt或者parameter。它是一段纯文本,但格式非常严格。我刚开始做RK开发时,就因为少写了一个逗号,导致整个固件刷进去起不来。嗯,这种坑踩过一次就记住了。

来看一个典型的Parameter文件内容:

FIRMWARE_VER: 8.1
MACHINE_MODEL: RK3568_EVB
MACHINE_ID: 007
MANUFACTURER: Rockchip
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: 0xffffffff
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
CMDLINE: mtdparts=rk29xxnand:0x00002000@0x00004000(uboot),0x00002000@0x00006000(trust),0x00002000@0x00008000(misc),0x00020000@0x0000a000(boot),0x00020000@0x0002a000(recovery),0x00040000@0x0004a000(backup),0x00080000@0x0008a000(cache),0x00400000@0x0010a000(system),0x00008000@0x0050a000(metadata),0x00080000@0x00512000(vendor),0x00080000@0x00592000(oem),-@0x00612000(userdata)

这里最核心的就是CMDLINE这一行。它定义了每个分区的布局。我来拆解一下格式:

0x00002000@0x00004000(uboot)

  • 0x00002000:分区大小,单位是扇区(512字节)。这里就是4MB。
  • @0x00004000:分区起始地址,也是扇区单位。从8MB位置开始。
  • (uboot):分区名称,烧录工具和系统都靠这个名字识别。

我的小技巧:在量产测试脚本里,我经常用rkdeveloptool read-partition命令来验证分区表是否被正确烧录。如果读出来的分区大小和parameter里对不上,那基本就是烧录出问题了。

4.3 各分区的作用详解

每个分区都有自己的使命。我按启动顺序给大家捋一遍:

4.3.1 Bootloader分区

这是芯片上电后第一个执行的代码。它负责初始化DDR、时钟、存储控制器等基础硬件。说白了,就是给后续的代码搭好舞台。

我曾经遇到过一个项目,换了DDR颗粒后频繁启动失败。查了两天才发现,是bootloader里的DDR初始化参数没更新。从那以后,我每次换物料都会先确认bootloader版本对不对。

4.3.2 Uboot分区

Uboot是真正的引导加载程序。它比bootloader复杂得多,支持文件系统、网络、USB等。它的核心工作是加载kernel到内存,然后跳转过去。

在量产测试中,uboot还有一个重要角色——它支持fastbootrockusb协议。我们量产烧录工具就是通过uboot来和PC通信的。

4.3.3 Trust分区

这个分区存放ARM TrustZone的安全固件。如果你的产品不需要安全启动,这个分区可以很小甚至为空。但如果你要做支付类、版权保护类的产品,这个分区就至关重要了。

4.3.4 Misc分区

一个很小的分区,用来存放系统启动模式。比如正常启动、恢复模式、量产模式等。我经常在量产脚本里通过写misc分区来让设备进入烧录模式。

4.3.5 Boot分区

存放Linux内核(kernel)和设备树(dtb)。这是系统启动的核心。kernel负责驱动硬件、管理内存和进程。设备树告诉kernel硬件是怎么连接的。

4.3.6 System分区

这是Android系统的主要分区,存放/system目录下的所有文件。包括框架层代码、系统应用、库文件等。在Linux系统中,这个分区通常对应根文件系统。

这个分区是固件包里最大的,动辄几百MB甚至上GB。量产烧录时,大部分时间都花在写这个分区上。

4.3.7 其他常见分区

分区名 作用 量产测试关注点
recovery 恢复系统,用于OTA升级失败后的救砖 确认recovery能正常启动
cache 系统缓存,OTA升级包临时存放 大小要够用,否则OTA会失败
userdata 用户数据分区,相当于手机的内部存储 量产测试后要清空
vendor 厂商定制分区,存放硬件相关的库和配置 驱动相关的文件都在这里

避坑指南:我曾经在量产时发现,同一批固件烧到不同批次的主板上,有的能启动有的不能。最后定位到是parameter里分区大小定义和实际NAND Flash的坏块管理策略不匹配。记住:分区大小一定要考虑坏块预留空间,尤其是NAND Flash方案。

4.4 固件打包与解包实战

在量产测试中,我们经常需要解包固件来替换某个分区,或者重新打包。RK官方提供了rkImageMakerafptool这两个工具。

解包一个.update固件:

# 解包update固件
afptool -unpack update.img output_dir

# 查看解包后的文件结构
ls output_dir/
# 你会看到类似这样的输出:
# Image.cfg  parameter.txt  uboot.img  trust.img  boot.img  system.img  ...

重新打包:

# 修改完分区镜像后重新打包
afptool -pack output_dir new_update.img

我个人习惯在量产测试脚本里加一个固件校验步骤:解包后检查每个分区镜像的MD5值,确保固件包没有被损坏。这个习惯帮我避免过好几次因为固件传输错误导致的批量刷机失败。

4.5 总结

固件文件结构,说白了就是一张「地图」加上一堆「货物」。地图是分区表,货物是各个分区的镜像数据。你只要掌握了这张地图,就能在固件世界里来去自如。

下一章我会讲量产烧录的具体流程和常见问题。到时候我会分享一个我踩过的坑——因为固件包里的bootloader版本和硬件不匹配,导致3000台设备全部变砖。嗯,那真是刻骨铭心的一次经历。