3. 分区表基础:MBR与GPT分区表的结构、原理与区别
做嵌入式Bootloader这些年,我调试过不少因为分区表搞错而启动失败的板子。说实话,分区表这东西,看着简单,但坑特别多。你想想看,CPU上电后第一件事就是找启动代码,而启动代码在哪,全靠分区表来指引。
这一章,我们就来把MBR和GPT这两种分区表彻底讲透。我会结合我实际项目中踩过的坑,帮你建立对分区表的直观理解。
3.1 为什么需要分区表?
一块硬盘或eMMC,说白了就是一个巨大的字节数组。如果没有分区表,操作系统根本不知道哪里是文件系统,哪里是Bootloader,哪里是用户数据。
分区表就是一张“地图”。它告诉系统:
- 存储设备的布局是怎样的
- 每个分区从哪里开始、到哪里结束
- 每个分区是什么类型(FAT32、EXT4、还是裸分区)
核心观点:分区表是存储设备的第一份元数据。它必须放在设备的固定位置,并且格式要严格遵循规范。否则,整个系统都无法启动。
3.2 MBR分区表:老将的坚守
MBR(Master Boot Record)诞生于1983年,随IBM PC DOS 2.0一起发布。嗯,比我的从业年龄还大。但直到今天,很多嵌入式设备仍然在用。
3.2.1 MBR的物理结构
MBR位于存储设备的第一个扇区(LBA 0),每个扇区512字节。它的布局非常紧凑:
| 偏移地址 | 长度 | 内容 |
|---|---|---|
| 0x000 - 0x1BD | 446字节 | 第一阶段Bootloader代码(引导代码) |
| 0x1BE - 0x1FD | 64字节 | 4个分区表项,每个16字节 |
| 0x1FE - 0x1FF | 2字节 | 魔数 0x55AA(有效标志) |
每个分区表项16字节,结构如下:
| 偏移 | 长度 | 含义 |
|---|---|---|
| 0 | 1字节 | 引导标志(0x80表示可引导) |
| 1-3 | 3字节 | CHS起始地址(已过时) |
| 4 | 1字节 | 分区类型(如0x83=Linux, 0x0C=FAT32) |
| 5-7 | 3字节 | CHS结束地址 |
| 8-11 | 4字节 | LBA起始扇区号 |
| 12-15 | 4字节 | 分区总扇区数 |
注意:MBR的分区表项只有4个。如果需要超过4个分区,必须使用扩展分区。扩展分区本身也是一个MBR分区类型,它内部再嵌套逻辑分区。我曾经在一个项目里遇到扩展分区嵌套超过3层的情况,结果某个Bootloader死活不认——因为它只支持一级扩展分区。
3.2.2 MBR的局限性
我在一个安防监控项目里,需要在一块2TB的硬盘上存储视频数据。MBR就出问题了:
- 最大寻址2TB:LBA地址用32位表示,最大2^32 * 512字节 = 2TB。超过2TB的硬盘,MBR无法完整管理。
- 主分区最多4个:扩展分区机制增加了复杂度,而且逻辑分区的引导兼容性很差。
- 没有备份:MBR只存在于LBA 0,一旦损坏,整个分区表丢失。我见过不少因为意外断电导致MBR损坏,数据全丢的案例。
- CHS寻址已过时:现代硬盘的物理结构早已不是CHS(柱面-磁头-扇区)模型,但MBR规范里还保留着这些字段,纯粹是历史包袱。
3.3 GPT分区表:现代的选择
GPT(GUID Partition Table)是UEFI规范的一部分,用来替代MBR。它解决了MBR几乎所有的痛点。
3.3.1 GPT的物理结构
GPT的布局比MBR复杂,但更健壮:
GPT头(位于LBA 1)的关键字段:
- 签名:"EFI PART"(45 46 49 20 50 41 52 54)
- 版本号:当前为1.0(修订版 00 00 01 00)
- 头大小:通常为92字节
- 头CRC32:对整个GPT头进行校验
- 分区表CRC32:对分区表项进行校验
- 分区表项起始LBA:通常为2
- 分区表项数量:通常为128
- 每个分区表项大小:128字节
- 备份GPT头LBA:指向磁盘末尾的备份
3.3.2 GPT分区表项结构
每个分区表项128字节,比MBR的16字节丰富得多:
| 偏移 | 长度 | 含义 |
|---|---|---|
| 0-15 | 16字节 | 分区类型GUID(如EFI系统分区为C12A7328-F81F-11D2-BA4B-00A0C93EC93B) |
| 16-31 | 16字节 | 唯一分区GUID(每个分区全球唯一) |
| 32-39 | 8字节 | 起始LBA(64位,支持超大容量) |
| 40-47 | 8字节 | 结束LBA(64位) |
| 48-55 | 8字节 | 属性标志位(如只读、隐藏、系统分区等) |
| 56-127 | 72字节 | 分区名称(UTF-16LE编码,最多36个字符) |
个人经验:我习惯在分区名称字段里写入有意义的名字,比如"bootloader"、"kernel_a"、"rootfs_b"。这样在调试时,用gdisk或parted一看就知道每个分区的用途,不用去查偏移表。这个习惯帮我省了不少排查时间。
3.4 MBR vs GPT:关键区别
直接上对比表,一目了然:
| 对比项 | MBR | GPT |
|---|---|---|
| 最大磁盘容量 | 2TB | 9.4ZB(2^64 * 512字节) |
| 最大分区数 | 4个主分区(+扩展分区内的逻辑分区) | 128个(默认,可扩展) |
| 分区表位置 | LBA 0(仅一份) | LBA 1 + 磁盘末尾备份 |
| 数据完整性 | 无校验 | CRC32校验头和分区表 |
| 引导方式 | BIOS模式(传统Legacy) | UEFI模式(也可通过CSM兼容BIOS) |
| 分区标识 | 1字节类型ID(如0x83) | 16字节GUID(全球唯一) |
| 分区名称 | 不支持 | 支持(UTF-16LE,最多36字符) |
| 兼容性 | 所有x86设备 | UEFI设备,部分老旧BIOS不支持 |
3.5 嵌入式场景下的选择建议
我在实际项目中,选择MBR还是GPT,主要看这几个因素:
- 存储容量:如果eMMC或NAND Flash小于2TB,MBR完全够用。但现在的嵌入式设备,比如视频监控NVR,动不动就挂4TB硬盘,那就必须上GPT。
- Bootloader支持:U-Boot对GPT的支持已经很成熟了。但如果你用的是某个厂商的闭源Bootloader,最好先确认它是否支持GPT。我曾经在一个项目里,Bootloader只认MBR,被迫把GPT转成MBR,结果损失了备份保护功能。
- 分区数量:A/B系统升级方案通常需要至少6个分区(boot_a、boot_b、system_a、system_b、data、misc)。MBR的4个主分区限制很尴尬,用扩展分区又增加复杂度。GPT的128个分区绰绰有余。
- 可靠性要求:如果设备运行在恶劣环境(频繁断电、振动),GPT的备份机制是救命稻草。我曾经在工业设备上遇到过主GPT头被损坏的情况,靠备份GPT恢复了所有分区数据。
避坑指南:我曾经在一个项目里,为了兼容老旧BIOS,选择了MBR。结果设备在现场运行半年后,MBR所在的扇区出现了坏块,整个分区表丢失。从那以后,只要硬件支持,我坚决用GPT。备份GPT在磁盘末尾,坏块概率远低于起始扇区。
3.6 混合MBR(Hybrid MBR)
还有一种特殊情况:混合MBR。它同时包含MBR和GPT分区表。MBR部分包含一个或多个GPT分区的“影子”条目,让不支持GPT的老旧操作系统(如Windows XP 32位)也能识别部分分区。
说实话,混合MBR是个妥协方案。我在实际项目中很少用,因为它容易造成两个分区表不一致。如果你不是必须兼容非常老的系统,建议直接纯GPT。
3.7 本章小结
分区表是存储设备的基石。MBR简单、兼容性好,但容量和分区数受限,且没有备份。GPT现代、健壮、支持大容量和大分区数,是当前的主流选择。
在嵌入式Bootloader开发中,我建议你默认使用GPT。除非你有明确的兼容性需求(比如必须支持Legacy BIOS启动),否则不要回头去用MBR。记住:分区表选错了,后面所有的工作都可能白费。