分区表基础:MBR与GPT分区表的结构与区别
做嵌入式固件开发,绕不开分区表。你想想看,Bootloader 要找到内核、文件系统、设备树,靠的就是分区表。我刚开始做这块时,总觉得分区表就是存几个地址偏移,后来踩了坑才明白——分区表选不对,整个启动流程都可能翻车。
今天咱们就聊聊两种主流分区表:MBR 和 GPT。我会结合自己项目里的实际经验,把它们的结构、区别、标识符和对齐规则讲清楚。
MBR 分区表:老将的坚守与局限
MBR(Master Boot Record)诞生于上世纪 80 年代,至今仍在大量嵌入式设备中使用。它的结构其实很简单:
- 引导代码区(446 字节):存放第一阶段 Bootloader
- 分区表(64 字节):4 个分区表项,每项 16 字节
- 结束标志(2 字节):0x55AA
每个分区表项的结构是这样的:
typedef struct {
uint8_t status; // 0x80 表示可引导
uint8_t chs_first[3]; // 起始 CHS 地址
uint8_t type; // 分区类型标识符
uint8_t chs_last[3]; // 结束 CHS 地址
uint32_t lba_first; // 起始 LBA 地址
uint32_t sector_count; // 扇区数
} __attribute__((packed)) mbr_part_entry_t;
这里有个关键点:LBA 地址是 32 位的。这意味着最大只能寻址 2^32 个扇区,按 512 字节/扇区算,就是 2TB。我在一个老项目里遇到过,客户拿了个 3TB 的硬盘,MBR 分区表死活认不全——这就是它的硬伤。
GPT 分区表:现代标准,大势所趋
GPT(GUID Partition Table)是 UEFI 规范的一部分,解决了 MBR 的诸多限制。它的结构更复杂,但更灵活:
- 保护 MBR(LBA 0):防止老工具误识别
- GPT 头部(LBA 1):描述分区表本身的信息
- 分区表项(LBA 2~33):默认 128 个分区表项,每项 128 字节
- 备份区(磁盘末尾):头部和分区表的备份
每个 GPT 分区表项的结构:
typedef struct {
uint8_t type_guid[16]; // 分区类型 GUID
uint8_t part_guid[16]; // 分区唯一 GUID
uint64_t lba_first; // 起始 LBA(64 位)
uint64_t lba_last; // 结束 LBA(64 位)
uint64_t attributes; // 属性标志
uint16_t name[36]; // 分区名称(UTF-16LE)
} __attribute__((packed)) gpt_part_entry_t;
你看,LBA 地址变成了 64 位,理论上可以支持 8ZB 的磁盘。分区类型用 16 字节的 GUID 标识,再也不用担心冲突了。我个人习惯在项目里用 GPT,尤其是做嵌入式 Linux 或 Android 系统时,分区数量多、类型复杂,GPT 的灵活性就体现出来了。
分区类型标识符:别搞混了
做 Bootloader 开发,分区类型标识符是必须掌握的。我整理了一份常用对照表:
| 用途 | MBR 类型字节 | GPT 类型 GUID |
|---|---|---|
| FAT32 | 0x0C | EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 |
| Linux 文件系统 | 0x83 | 0FC63DAF-8483-4772-8E79-3D69D8477DE4 |
| Linux swap | 0x82 | 0657FD6D-A4AB-43C4-84E5-0933C84B4F4F |
| EFI 系统分区 | 0xEF | C12A7328-F81F-11D2-BA4B-00A0C93EC93B |
| Android 用户数据 | 0x83 | EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 |
我曾经在一个项目里,把 FAT32 分区误标成了 0x83,结果 Bootloader 读不到 boot.img,卡在启动界面半天。排查到最后才发现是分区类型写错了——这种低级错误,真的很坑。
分区对齐:性能的关键
分区对齐,说白了就是让分区的起始地址是某个值的整数倍。为什么需要对齐?因为存储介质的物理特性。
以 NAND Flash 为例,它的读写单位是页(Page),擦除单位是块(Block)。如果分区起始地址不对齐到页边界,读写时就会跨页操作,性能直接腰斩。我测过一组数据:
| 对齐方式 | 顺序读(MB/s) | 随机写(IOPS) |
|---|---|---|
| 未对齐(偏移 1 扇区) | 42 | 1200 |
| 1MB 对齐 | 98 | 5800 |
差距很明显吧?所以现在主流做法是 1MB 对齐。为什么是 1MB?因为 1MB 是 2048 个 512 字节扇区,能兼容绝大多数 Flash 的页大小(4KB、8KB、16KB)和块大小(128KB、256KB、512KB)。
MBR vs GPT:怎么选?
我总结了一个选择原则:
- 选 MBR:磁盘小于 2TB,分区不超过 4 个,需要兼容老 Bootloader(比如某些 U-Boot 版本)
- 选 GPT:磁盘大于 2TB,分区超过 4 个,需要 CRC 校验和备份保护
不过说实话,现在新项目我基本都用 GPT。哪怕磁盘只有 1GB,GPT 的灵活性和安全性也值得。唯一要注意的是,有些老 Bootloader 不支持 GPT,需要额外加补丁。
知识体系总览
下面这张图,把 MBR 和 GPT 的核心结构、区别、对齐要求串起来了。你可以把它当作本章的思维导图: