2、分区表基础概念:什么是分区表、为什么需要分区表、分区表与文件系统的关系
各位同学,咱们今天聊点实在的。分区表这东西,说白了就是一张“地图”。你想想看,一块Flash芯片,少则几十兆,多则几个G。如果没有分区表,U-Boot怎么知道哪里放内核、哪里放设备树、哪里放根文件系统?
我刚开始做嵌入式那会儿,也犯过糊涂。觉得分区表不就是几个地址范围嘛,随便写写就行。结果有一次,分区大小算错了,内核镜像写到一半把设备树给覆盖了。板子死活起不来,查了三天才找到原因。嗯,从那以后,我对分区表就再也不敢马虎了。
什么是分区表?
分区表,本质上是一组描述存储介质布局的数据结构。它告诉系统:
- 这块存储芯片被分成了几块区域
- 每块区域的起始地址和大小是多少
- 每块区域叫什么名字、干什么用的
在U-Boot里,分区表通常以两种形式存在:
- 硬编码在源码中:直接在
include/configs/目录下的头文件里定义宏 - 存储在设备树中:通过
partitions节点描述,U-Boot动态解析
我个人更推荐第二种方式。为什么?因为改分区不用重新编译U-Boot,改个设备树文件就行。这在项目迭代阶段特别方便。
核心要点:分区表就是存储介质的“目录索引”。没有它,系统不知道数据该往哪放、从哪读。
为什么需要分区表?
这个问题我问过不少刚入行的朋友。他们的第一反应是:“为了管理存储空间呗。” 对,但不全对。
我总结了几点核心原因:
- 隔离不同功能模块:Bootloader、内核、根文件系统、用户数据,各自有独立空间,互不干扰
- 支持系统升级:比如A/B分区方案,升级失败还能回滚。我在一个车机项目里就吃过这个甜头
- 简化地址管理:不用每次烧写都去查芯片手册算地址,直接说“烧到kernel分区”就行
- 便于维护和调试:出问题了,直接看分区表就知道哪个区域可能被破坏了
举个例子。你想想看,如果没有分区表,你要升级内核。你得先知道内核当前在哪个地址,新内核要写到哪个地址,还得保证不覆盖别的数据。多麻烦?有了分区表,一句 update kernel 就搞定了。
我的经验:分区表设计得越清晰,后期维护成本越低。我曾经接手过一个项目,分区表乱七八糟,连注释都没有。改一个分区大小,要翻遍整个代码库。那感觉,真叫一个酸爽。
分区表与文件系统的关系
这个问题,很多初学者容易搞混。我直接说结论:分区表和文件系统是两个不同层次的概念,但它们配合使用。
分区表负责“划地盘”,文件系统负责“管地盘”。
打个比方:
- 分区表就像城市规划图,告诉你哪块是住宅区、哪块是商业区、哪块是工业区
- 文件系统就像每个区里的管理制度,比如住宅区怎么编号、商业区怎么招商
在嵌入式系统里,常见的情况是:
| 分区 | 用途 | 文件系统 |
|---|---|---|
| bootloader | 存放U-Boot镜像 | 裸数据(无文件系统) |
| kernel | 存放Linux内核 | 裸数据或FIT镜像 |
| dtb | 存放设备树 | 裸数据 |
| rootfs | 存放根文件系统 | ext4、squashfs、ubifs等 |
| data | 用户数据 | ext4、fat32等 |
看到没?有些分区不需要文件系统,比如bootloader和kernel分区,U-Boot直接按偏移地址读写。而rootfs和data分区,则需要文件系统来管理文件和目录结构。
注意:分区大小和文件系统类型要匹配。比如你用ubifs文件系统,分区大小必须是LEB(逻辑擦除块)的整数倍。我曾经因为没算好这个,导致文件系统挂载失败,折腾了一整天。
分区表的核心逻辑
为了让你更直观地理解,我画了一张图。这张图展示了分区表在整个系统启动流程中的位置和作用。
这张图想表达什么?说白了就是:U-Boot启动后,第一件事就是去读分区表。读懂了分区表,它才知道接下来该去哪找内核、去哪找设备树。没有分区表,U-Boot就是个瞎子。
实际项目中的分区表设计
我在一个物联网网关项目里,遇到过这么个情况。产品经理说:“我们要支持远程升级,还要保证升级失败能回滚。” 好,那就得设计A/B分区方案。
分区表大概长这样:
// 伪代码示例
partition(bootloader, 0x000000, 0x100000) // 1MB
partition(env, 0x100000, 0x020000) // 128KB
partition(kernel_a, 0x120000, 0x400000) // 4MB
partition(kernel_b, 0x520000, 0x400000) // 4MB
partition(dtb_a, 0x920000, 0x080000) // 512KB
partition(dtb_b, 0x9A0000, 0x080000) // 512KB
partition(rootfs_a, 0xA20000, 0x2000000) // 32MB
partition(rootfs_b, 0x2A20000, 0x2000000)// 32MB
partition(data, 0x4A20000, 0x2000000)// 32MB
你看,kernel和rootfs都有A/B两份。升级时写B分区,如果启动失败,U-Boot自动切回A分区。这个方案我用了好几年,稳得很。
关键点:分区表设计要预留足够的空间给未来升级。我见过太多项目,一开始分区卡得死死的,后来想加个功能都没地方放。记住,存储空间是硬约束,但分区规划是软约束。宁可多留点余量,也别抠抠搜搜的。
总结一下
分区表不是什么高深的东西。它就是一张表,告诉系统存储芯片怎么用。但就是这么一张表,设计得好,能省你无数麻烦;设计得烂,能让你加班到怀疑人生。
我个人的习惯是:在项目启动阶段,花半天时间把分区表设计好,然后写到文档里。后续谁都不许随便改。真要改,必须走评审流程。这样能避免很多后期的问题。
好了,关于分区表的基础概念,咱们就聊到这儿。下一节我会讲分区表的具体格式和实现方式,到时候咱们再深入聊。
小提示:如果你刚开始接触分区表,建议先从简单的单分区方案入手。等熟悉了U-Boot的启动流程,再尝试A/B分区、多分区等复杂方案。一步一步来,别着急。