分区表设计原则:分区表的作用与划分逻辑

分区表这东西,说白了就是一张「地图」。它告诉 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)的整数倍。否则擦除操作会越界,覆盖相邻分区。

分区设计的关键原则

我总结了几条铁律,你设计分区表时最好一条条对照:

  1. 对齐原则:分区起始地址和大小,必须对齐 Flash 的擦除块大小。
  2. 冗余原则:关键分区(Bootloader、Kernel)预留 20%~30% 的余量,防止后续版本膨胀。
  3. 隔离原则:只读分区(Rootfs)和可写分区(Userdata)必须分开,避免误写导致系统崩溃。
  4. 升级友好原则:如果支持 OTA,建议为 Kernel 和 Rootfs 准备 A/B 分区,实现无缝升级。

我曾经犯过的错:有一款产品,我把 Rootfs 和 Userdata 放在同一个分区,结果 OTA 升级时不小心格式化了整个分区,用户数据全没了。从那以后,我再也不敢把系统文件和用户数据混在一起。

分区与 OTA 升级的关系

你想想看,OTA 升级的本质是什么?就是擦除旧分区、写入新数据。如果分区表设计不合理,升级过程很容易出问题。

举个例子:

  • 如果 Kernel 分区太小,新版本内核放不下,升级直接失败。
  • 如果 Rootfs 和 Userdata 没有隔离,升级时可能误删用户数据。
  • 如果没有预留 A/B 分区,升级过程中断电,设备就变砖了。

所以,分区表设计一定要站在 OTA 的角度去思考。我建议你在设计阶段就画出分区布局图,标注清楚每个分区的用途、大小、读写属性,以及升级时的操作策略。

SVG:分区表与启动流程关系图

下面这张图,展示了分区表如何串联起整个启动和升级流程:

分区表与启动/升级流程关系图 Bootloader 分区 Kernel 分区 DTB 分区 Rootfs 分区 Userdata 分区 加载 加载 加载 挂载 Bootloader 执行 Kernel 启动 设备树解析 Rootfs 初始化 用户空间运行 OTA 下载新固件 校验分区表 擦除 & 写入分区 切换启动分区 说明:分区表是 Bootloader 和 OTA 升级的「桥梁」 左侧分区定义存储位置,右侧启动和升级流程按分区表操作

小结

分区表设计,看似简单,实则处处是坑。我给你的建议是:

  • 先画图,再写代码。
  • 留足余量,别抠门。
  • 考虑 OTA 升级场景,提前规划 A/B 分区。
  • 对齐、对齐、再对齐——偏移量不对,一切白费。

嗯,分区表这块就聊到这儿。记住,一张好的分区表,能让你的 OTA 升级事半功倍;一张烂的分区表,能让你加班到怀疑人生。