2、分区表基础概念:什么是分区表、为什么需要分区表、分区表与文件系统的关系

各位同学,咱们今天聊点实在的。分区表这东西,说白了就是一张“地图”。你想想看,一块Flash芯片,少则几十兆,多则几个G。如果没有分区表,U-Boot怎么知道哪里放内核、哪里放设备树、哪里放根文件系统?

我刚开始做嵌入式那会儿,也犯过糊涂。觉得分区表不就是几个地址范围嘛,随便写写就行。结果有一次,分区大小算错了,内核镜像写到一半把设备树给覆盖了。板子死活起不来,查了三天才找到原因。嗯,从那以后,我对分区表就再也不敢马虎了。

什么是分区表?

分区表,本质上是一组描述存储介质布局的数据结构。它告诉系统:

  • 这块存储芯片被分成了几块区域
  • 每块区域的起始地址和大小是多少
  • 每块区域叫什么名字、干什么用的

在U-Boot里,分区表通常以两种形式存在:

  1. 硬编码在源码中:直接在 include/configs/ 目录下的头文件里定义宏
  2. 存储在设备树中:通过 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(逻辑擦除块)的整数倍。我曾经因为没算好这个,导致文件系统挂载失败,折腾了一整天。

分区表的核心逻辑

为了让你更直观地理解,我画了一张图。这张图展示了分区表在整个系统启动流程中的位置和作用。

分区表在系统启动中的角色 Flash 存储芯片(NAND / eMMC / SPI NOR) U-Boot 解析分区表(从设备树或头文件) 分区表内容(示例) bootloader kernel dtb rootfs data

这张图想表达什么?说白了就是: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分区、多分区等复杂方案。一步一步来,别着急。

可可精品资料库