分区表基础:分区表的概念、分区类型与格式
做 Bootloader 开发,绕不开分区表。说白了,分区表就是一张地图,告诉芯片「哪块存代码、哪块存数据、哪块是配置」。我刚开始接触这块时,觉得它就是个表格,后来踩了坑才明白——分区表要是乱了,整个系统都起不来。
分区表到底是什么?
分区表是存储设备(比如 eMMC、NAND Flash、SD 卡)最开头的一段数据。它记录了整个存储空间怎么划分。每个分区有起始地址、大小、类型、属性等信息。
你可以把它想象成一本房产证。房产证上写着「A 户 100 平米,B 户 80 平米」,分区表就是存储设备的房产证。Bootloader 启动时,第一件事就是读这张表,找到内核分区在哪,然后跳过去加载。
核心要点:分区表是 Bootloader 与存储设备之间的契约。双方都按这张表来解读数据,任何一方理解错了,系统就崩了。
分区类型:主分区、扩展分区、逻辑分区
这里有个历史遗留问题。早期的 MBR 分区表只能记录 4 个分区。为什么是 4 个?因为 MBR 的分区条目只有 64 字节,每个条目 16 字节,算下来就是 4 个。我当年做第一块开发板时,就因为这个限制折腾了好几天。
为了解决这个限制,工程师们想了个办法——扩展分区和逻辑分区。
| 分区类型 | 说明 | 数量限制 | 典型用途 |
|---|---|---|---|
| 主分区 | 直接记录在 MBR 中的分区,可引导系统 | 最多 4 个 | Bootloader、内核、根文件系统 |
| 扩展分区 | 一种特殊的主分区,作为容器存放逻辑分区 | 最多 1 个 | 容纳多个逻辑分区 |
| 逻辑分区 | 嵌套在扩展分区内部,通过 EBR 链式索引 | 理论上无上限 | 数据分区、用户存储 |
为什么会搞出扩展分区?说白了就是「打补丁」。MBR 设计时没想到存储会这么大、分区会这么多。扩展分区本身也是一个主分区,但它里面可以再套一层逻辑分区。逻辑分区通过扩展引导记录(EBR)链式连接,一个指向下一个。
个人经验:在嵌入式系统中,我建议尽量用主分区。逻辑分区虽然能突破 4 个的限制,但链式查找效率低,而且一旦中间某个 EBR 损坏,后面的分区全丢。我在一个工业项目中遇到过这种情况,最后不得不改用 GPT。
分区表格式:MBR vs GPT
现在主流的就两种格式:MBR 和 GPT。MBR 是古董,GPT 是新生代。但古董不代表没用,很多嵌入式芯片还在用 MBR。
MBR(主引导记录)
MBR 位于存储设备的第一个扇区(LBA 0),大小 512 字节。结构如下:
- 引导代码(446 字节):存放 Bootloader 的第一阶段代码
- 分区表(64 字节):4 个条目,每个 16 字节
- 签名(2 字节):固定为 0x55AA,用于校验
MBR 的局限很明显:
- 最大支持 2TB 磁盘(因为用 32 位 LBA)
- 最多 4 个主分区
- 没有备份,坏了就全完
避坑指南:我曾经在一个项目里,MBR 的 0x55AA 签名被意外覆盖了。原因是 Bootloader 写入时扇区偏移算错了。结果芯片启动时直接卡死,连串口都打不开。后来我养成了一个习惯——每次烧录完,先读回 MBR 校验签名。
GPT(GUID 分区表)
GPT 是 UEFI 时代的产物,解决了 MBR 的几乎所有痛点。结构如下:
- 保护 MBR(LBA 0):兼容旧工具,防止误识别
- GPT 头(LBA 1):记录分区表位置、大小、CRC 校验
- 分区条目(LBA 2~33):默认 128 个条目,每个 128 字节
- 备份 GPT:磁盘末尾有完整备份
| 对比项 | MBR | GPT |
|---|---|---|
| 最大容量 | 2TB | 9.4ZB(理论) |
| 分区数量 | 4 个主分区 | 128 个(默认) |
| 备份机制 | 无 | 头尾双备份 |
| 校验机制 | 仅 0x55AA 签名 | CRC32 校验 |
| 引导方式 | BIOS 传统模式 | UEFI |
| 嵌入式适用性 | 广泛(芯片原生支持) | 逐渐普及 |
嗯,这里要注意。GPT 虽然好,但不是所有嵌入式芯片都支持。有些老旧的 ARM 芯片,BootROM 只认 MBR。你强行用 GPT,芯片连启动都做不到。
MBR 与 GPT 在 Bootloader 中的实际选择
我个人习惯这样选:
- 存储小于 2TB、芯片较老:用 MBR,简单可靠
- 存储大于 2TB、需要多分区:用 GPT,灵活安全
- 需要 A/B 系统升级:强烈建议 GPT,因为可以轻松分出十几个分区
关键判断:如果你的 Bootloader 是自己写的,MBR 实现起来更简单,代码量少。如果用的是 U-Boot 这类成熟方案,GPT 支持已经很完善了,直接上 GPT 更省心。
分区表结构图
下面这张图展示了 MBR 和 GPT 在磁盘上的布局差异。你可以直观看到为什么 GPT 更安全——它有备份。
Bootloader 如何读取分区表
Bootloader 启动时,分区表读取流程大致如下:
- 读取 LBA 0:检查最后两个字节是否为 0x55AA
- 判断格式:如果 LBA 0 是保护 MBR(分区类型为 0xEE),则按 GPT 解析;否则按 MBR 解析
- 解析分区条目:遍历分区表,找到类型匹配的分区(如内核分区类型为 0x83 或特定 GUID)
- 加载数据:根据分区起始地址和大小,读取数据到内存
小技巧:在 U-Boot 中,你可以用 part list 命令查看当前存储设备的分区表。我调试时经常先用这个命令确认分区布局是否正确,再往下走加载流程。
常见分区表错误与排查
做 Bootloader 这些年,我遇到过不少分区表相关的问题。这里列几个典型的:
| 错误现象 | 可能原因 | 排查方法 |
|---|---|---|
| 启动卡在「Loading kernel...」 | 分区表偏移错误,读到了错误地址 | 用 hexdump 查看分区表内容,核对起始 LBA |
| 系统只能启动一次 | MBR 被写入操作覆盖 | 检查写入流程是否保护了 LBA 0 |
| GPT 分区无法识别 | 备份 GPT 损坏,主 GPT 也异常 | 用 gdisk 修复,或从备份恢复 |
| 分区大小显示为 0 | 分区条目 CRC 校验失败 | 重新写入分区表,确保 CRC 正确 |
曾经踩过的坑:有一次我在量产时发现,同一批芯片有的能启动有的不能。排查了两天才发现——烧录工具在写入固件时,把 MBR 的 0x55AA 签名覆盖成了 0x55AB。原因是工具代码里有个字节序转换的 bug。从那以后,我要求所有烧录脚本在写入后必须回读校验。
总结
分区表是 Bootloader 的基石。MBR 简单但脆弱,GPT 强大但需要芯片支持。选哪个,取决于你的硬件平台和项目需求。但不管选哪个,记住三点:
- 分区表必须有校验机制
- 写入操作必须保护分区表区域
- 量产前必须做分区表回读验证
嗯,这些经验都是用故障换来的。希望你能少走些弯路。