3、GPT与MBR分区表:分区表结构详解,为什么GPT更适合多分区协同启动
说到分区表,很多做嵌入式的朋友第一反应就是“这玩意儿跟启动有啥关系?”
关系大了去了。我当年调试一块ARM开发板,死活起不来系统,折腾了两天,最后发现是分区表类型选错了。嗯,从那以后我再也不敢小看分区表了。
3.1 MBR分区表:老将的局限
MBR(主引导记录)诞生于1983年,跟IBM PC/AT一个年代。你想想看,那时候的硬盘才多大?10MB就算海量了。
MBR的结构其实很简单:
- 引导代码区:446字节,存放第一阶段引导程序
- 分区表:64字节,最多4个主分区
- 结束标志:0x55AA,2字节
每个分区表项只有16字节,结构如下:
typedef struct {
uint8_t status; // 0x80表示可引导
uint8_t start_head; // 起始磁头号
uint16_t start_sector; // 起始扇区(低6位)+ 起始柱面(高10位)
uint8_t type; // 分区类型(0x83=Linux, 0x0C=FAT32等)
uint8_t end_head; // 结束磁头号
uint16_t end_sector; // 结束扇区+柱面
uint32_t lba_start; // 起始LBA地址
uint32_t sector_count; // 扇区总数
} mbr_partition_t;
看到问题了吗?LBA地址只有32位。这意味着最大只能寻址2^32个扇区,每个扇区512字节的话,就是2TB。
注意:MBR的2TB限制是硬伤。我有个客户买了块4TB的硬盘,用MBR分区,结果只认出一半空间。最后只能重新格成GPT。
还有一个更坑的地方——MBR只允许4个主分区。想多分区?得用扩展分区和逻辑分区。这玩意儿在嵌入式多系统启动时简直就是噩梦。
3.2 GPT分区表:新时代的解决方案
GPT(GUID分区表)是UEFI规范的一部分。它解决了MBR几乎所有的痛点。
先看GPT的整体布局:
+------------------+
| 保护MBR | // 兼容性用的,防止老工具误操作
+------------------+
| GPT头部 | // 主分区表头
+------------------+
| 分区表项数组 | // 默认128个表项,每个128字节
+------------------+
| 用户数据区域 |
+------------------+
| 分区表项备份 | // 备份在磁盘末尾
+------------------+
| GPT头部备份 |
+------------------+
GPT头部结构长这样:
typedef struct {
uint64_t signature; // "EFI PART"
uint32_t revision; // 版本号
uint32_t header_size; // 头部大小(通常92字节)
uint32_t header_crc32; // 头部校验和
uint32_t reserved;
uint64_t my_lba; // 本头部所在LBA
uint64_t alternate_lba; // 备份头部所在LBA
uint64_t first_usable_lba; // 第一个可用LBA
uint64_t last_usable_lba; // 最后一个可用LBA
uint8_t disk_guid[16]; // 磁盘唯一GUID
uint64_t partition_entry_lba;// 分区表项起始LBA
uint32_t num_partitions; // 分区表项数量
uint32_t entry_size; // 每个表项大小(128字节)
uint32_t partitions_crc32; // 分区表项校验和
} gpt_header_t;
每个分区表项128字节:
typedef struct {
uint8_t type_guid[16]; // 分区类型GUID
uint8_t unique_guid[16]; // 分区唯一GUID
uint64_t starting_lba; // 起始LBA(64位!)
uint64_t ending_lba; // 结束LBA(64位!)
uint64_t attributes; // 属性标志
uint16_t name[36]; // 分区名称(UTF-16LE)
} gpt_partition_t;
核心优势:GPT使用64位LBA地址,理论上支持最大8ZB(泽字节)的磁盘。你想想看,这够用几百年了。
3.3 为什么GPT更适合多分区协同启动?
我个人习惯在嵌入式多系统项目中优先使用GPT,原因有四点:
- 分区数量无限制:默认128个分区表项,不够还能扩展。MBR那4个主分区,在多系统启动时根本不够分。
- 备份机制可靠:GPT在磁盘头和尾各存一份分区表。我曾经遇到过磁盘前几个扇区损坏的情况,MBR直接废了,GPT还能从备份恢复。
- GUID标识唯一:每个分区都有唯一的GUID,不会像MBR那样靠分区编号来识别。这在多系统协同启动时特别重要——不会搞混分区。
- 校验和保障:GPT头部和分区表都有CRC32校验。数据损坏能及时发现,而不是等到启动失败才抓瞎。
实战建议:在做多分区协同启动时,我建议把每个系统的分区都加上有意义的名称(比如"kernel_a"、"rootfs_b")。这样在启动管理器里一眼就能认出来,不用去记分区编号。
3.4 一个实际的多分区布局案例
这是我之前做的一个车载信息娱乐系统的分区方案:
| 分区编号 | 名称 | 大小 | 用途 |
|---|---|---|---|
| 1 | bootloader | 2MB | U-Boot引导程序 |
| 2 | kernel_a | 16MB | 主系统内核 |
| 3 | kernel_b | 16MB | 备用系统内核 |
| 4 | rootfs_a | 512MB | 主系统根文件系统 |
| 5 | rootfs_b | 512MB | 备用系统根文件系统 |
| 6 | config | 8MB | 系统配置参数 |
| 7 | data | 剩余空间 | 用户数据 |
你看,7个分区,MBR根本搞不定。用GPT就轻松多了。而且每个分区都有明确的名字和GUID,启动管理器通过GUID就能找到对应的分区,不会因为分区编号变化而出错。
3.5 分区表结构对比图
下面这张图能帮你直观理解MBR和GPT的差异:
3.6 避坑指南
最后分享几个我踩过的坑:
- 兼容性问题:有些老旧的U-Boot版本不支持GPT。我在一个项目里就吃过这个亏,U-Boot死活读不了GPT分区。解决办法是升级U-Boot或者用混合MBR方案。
- 备份分区表损坏:虽然GPT有备份,但如果磁盘末尾扇区坏了,备份也就废了。我建议定期用
gdisk -l /dev/sdX检查分区表完整性。 - 分区对齐:SSD和eMMC都有擦除块大小(通常是4KB或1MB)。分区不对齐会导致性能下降。用
parted时记得加align-check参数。
小技巧:创建GPT分区时,我习惯用
sgdisk工具。它支持脚本化操作,批量部署时特别方便。比如:sgdisk -n 1:2048:+16M -t 1:8300 /dev/sda 创建一个16MB的Linux分区。
说白了,GPT就是为现代多系统环境量身定做的。如果你还在用MBR做多分区协同启动,我建议你趁早换过来。别等到分区不够用或者数据损坏了才后悔。