分区表设计原则:分区表的作用与划分逻辑
分区表这东西,说白了就是一张「地图」。它告诉 Bootloader:你的内核在哪儿、DTB 在哪儿、根文件系统又在哪儿。没有这张地图,芯片上电后就是两眼一抹黑,根本不知道该从哪里启动。
我在项目中遇到过好几次,因为分区表设计不合理,导致 OTA 升级失败、回滚困难,甚至变砖。嗯,今天我们就来聊聊,怎么设计一张靠谱的分区表。
分区表的核心作用
分区表不仅仅是「划分空间」,它承担着三个关键职责:
- 启动引导:Bootloader 通过分区表找到 Kernel、DTB、Rootfs 的物理位置。
- 空间管理:防止不同固件模块互相覆盖,避免「写爆」某个区域。
- 升级与回滚:OTA 升级时,分区表决定了你能不能安全地切换系统版本。
一句话总结:分区表是嵌入式系统的「宪法」,所有启动和升级行为都得按它来。
五大核心分区的划分逻辑
一个典型的嵌入式 Linux 系统,至少包含以下 5 个分区。我按启动顺序一个个说。
1. Bootloader 分区
这是系统上电后第一个执行的代码。它负责初始化硬件、加载 Kernel 和 DTB。
- 大小建议:1MB ~ 4MB,具体看 Bootloader 的复杂度(U-Boot 一般 2MB 够用)。
- 位置:必须放在 Flash 的起始位置(偏移 0x0)。
- 注意事项:Bootloader 分区一般不做 OTA 升级,因为一旦写坏,设备就彻底变砖了。
我曾经踩过的坑:有一次为了省空间,把 Bootloader 分区压到 512KB,结果 U-Boot 加了几个驱动后放不下了。最后只能重新布局分区表,所有偏移量都得改,折腾了一整天。
2. Kernel 分区
存放 Linux 内核镜像(zImage 或 Image.gz)。
- 大小建议:4MB ~ 8MB。内核压缩后一般 3~5MB,留点余量。
- 位置:紧跟在 Bootloader 之后。
- 注意事项:如果启用了内核模块(.ko),需要额外考虑空间。
3. DTB 分区
设备树二进制文件,描述硬件信息。很多人容易忽略这个分区。
- 大小建议:64KB ~ 256KB。DTB 文件一般几十 KB。
- 位置:可以在 Kernel 之前或之后,但 Bootloader 必须知道它的确切地址。
- 注意事项:如果你的产品有多个硬件版本(比如不同屏幕、不同传感器),DTB 分区可能需要预留多个版本的空间。
我的习惯:把 DTB 单独分区,而不是打包进 Kernel。这样升级时,可以只更新 DTB 而不动内核,灵活性更高。
4. Rootfs 分区
根文件系统,存放所有用户空间程序、库、配置文件。
- 大小建议:32MB ~ 256MB,取决于你的应用复杂度。
- 文件系统类型:常用 squashfs(只读,压缩率高)或 ext4(可读写)。
- 注意事项:OTA 升级时,Rootfs 是更新最频繁的分区。建议使用 squashfs + overlayfs 方案,保证基础系统只读,用户数据可写。
5. Userdata 分区
存放用户数据、日志、配置、下载文件等。
- 大小建议:剩余 Flash 空间全部给 Userdata。
- 文件系统类型:ext4 或 f2fs(针对 Flash 优化)。
- 注意事项:OTA 升级时,Userdata 分区一般不做擦除,否则用户数据会丢失。
分区布局示例
下面是一个典型的 128MB Flash 分区布局,我直接拿项目里的例子改的:
| 分区名称 | 起始偏移 | 大小 | 文件系统 | 说明 |
|---|---|---|---|---|
| Bootloader | 0x000000 | 2MB | 裸分区 | U-Boot 镜像 |
| Kernel | 0x200000 | 6MB | 裸分区 | zImage |
| DTB | 0x800000 | 256KB | 裸分区 | 设备树 |
| Rootfs | 0x840000 | 64MB | squashfs | 只读根文件系统 |
| Userdata | 0x4480000 | 剩余空间 | ext4 | 用户数据 |
注意:所有偏移量必须是 Flash 擦除块大小(通常 64KB 或 128KB)的整数倍。否则擦除操作会越界,覆盖相邻分区。
分区设计的关键原则
我总结了几条铁律,你设计分区表时最好一条条对照:
- 对齐原则:分区起始地址和大小,必须对齐 Flash 的擦除块大小。
- 冗余原则:关键分区(Bootloader、Kernel)预留 20%~30% 的余量,防止后续版本膨胀。
- 隔离原则:只读分区(Rootfs)和可写分区(Userdata)必须分开,避免误写导致系统崩溃。
- 升级友好原则:如果支持 OTA,建议为 Kernel 和 Rootfs 准备 A/B 分区,实现无缝升级。
我曾经犯过的错:有一款产品,我把 Rootfs 和 Userdata 放在同一个分区,结果 OTA 升级时不小心格式化了整个分区,用户数据全没了。从那以后,我再也不敢把系统文件和用户数据混在一起。
分区与 OTA 升级的关系
你想想看,OTA 升级的本质是什么?就是擦除旧分区、写入新数据。如果分区表设计不合理,升级过程很容易出问题。
举个例子:
- 如果 Kernel 分区太小,新版本内核放不下,升级直接失败。
- 如果 Rootfs 和 Userdata 没有隔离,升级时可能误删用户数据。
- 如果没有预留 A/B 分区,升级过程中断电,设备就变砖了。
所以,分区表设计一定要站在 OTA 的角度去思考。我建议你在设计阶段就画出分区布局图,标注清楚每个分区的用途、大小、读写属性,以及升级时的操作策略。
SVG:分区表与启动流程关系图
下面这张图,展示了分区表如何串联起整个启动和升级流程:
小结
分区表设计,看似简单,实则处处是坑。我给你的建议是:
- 先画图,再写代码。
- 留足余量,别抠门。
- 考虑 OTA 升级场景,提前规划 A/B 分区。
- 对齐、对齐、再对齐——偏移量不对,一切白费。
嗯,分区表这块就聊到这儿。记住,一张好的分区表,能让你的 OTA 升级事半功倍;一张烂的分区表,能让你加班到怀疑人生。