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 0:保护MBR(0x55AA + 单个0xEE分区) LBA 1:GPT头(签名、分区表位置、CRC32校验) LBA 2 ~ LBA 33:分区表项(128个,每个128字节) 用户数据区(分区1、分区2、...、分区N) 文件系统、Bootloader、应用程序等 磁盘末尾:备份GPT头 + 备份分区表项 备份GPT在磁盘末尾 主GPT损坏时可恢复

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,主要看这几个因素:

  1. 存储容量:如果eMMC或NAND Flash小于2TB,MBR完全够用。但现在的嵌入式设备,比如视频监控NVR,动不动就挂4TB硬盘,那就必须上GPT。
  2. Bootloader支持:U-Boot对GPT的支持已经很成熟了。但如果你用的是某个厂商的闭源Bootloader,最好先确认它是否支持GPT。我曾经在一个项目里,Bootloader只认MBR,被迫把GPT转成MBR,结果损失了备份保护功能。
  3. 分区数量:A/B系统升级方案通常需要至少6个分区(boot_a、boot_b、system_a、system_b、data、misc)。MBR的4个主分区限制很尴尬,用扩展分区又增加复杂度。GPT的128个分区绰绰有余。
  4. 可靠性要求:如果设备运行在恶劣环境(频繁断电、振动),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。记住:分区表选错了,后面所有的工作都可能白费。