这一章我们主要介绍UEFI固件和GPT分区格式,通过上面文章我们也知道BIOS所存在的缺点,而UEFI就是为了解决这些问题。UEFI除了提供BIOS解决的问题外,它同时也提供了更加丰富的图形界面,对用户更加的友好,而且EFI程序支持C语言编写,提升了工作效率。但相对了,我们的工作都是在重复一个步骤,就是简单,发现简单无法解决更多的问题,而引入了复杂化,而UEFI就存在这个问题,UEFI的引入使得设计更加的复杂。也许,以后为了简单性,由出现了新的固件技术也说不定。 UFEI与GPT在这里我们不会介绍UEFI的历史,我们重点关注UEFI的角色,如何编写UEFI程序以及支持UEFI的计算机如何启动的。我们关于UEFI的文章主要围绕这些问题展开,首先我们需要了解UEFI,UEFI是为了解决BIOS所存在的问题而从新设计的一套固件系统,它不是BIOS,虽然UEFI也引入了兼容模式,兼容模式可以让我们像BIOS那样启动系统,但记住 UEFI不是BIOS。 在概述中,我们知道支持UEFI引导的计算机启动后交给UEFI固件,后续由UEFI进行后续的工作,在这里我们重点关注UEFI的引导功能,同时为了解决MBR分区格式无法支持更大的磁盘空间引入了GPT分区,GPT分区也是UEFI规范中的内容。UEFI 会根据设置的启动顺序,查找GPT分区表中 GUID 为 GPTGPT全称GUID Partition Table,它是为了替代MBR分区表,使得能够支持更大空间的磁盘而设计的分区方案。现代的操作系统基本上都支持GPT分区表。UEFI规范明确使用GPT分区表的EFI系统分区进行系统引导工作。我们先看一下GPT的全景图 GPT分区同样使用LBA寻址,正如在图上显示的磁盘中的第一个LBA0中保存的是保护性MBR(protective MBR ),这个扇区是磁盘的第一个扇区,早期为了向前兼容,通常保留不用,但现在也为了防止基于MBR的工具错误识别从而导致破坏GPT分区的作用,而且这个扇区的类型设置为 0xEE 来表示它是一个保护性的MBR。LBA1(第二个扇区)保存的是GPT分区头,这个分区中包含了有关GPT分区详细的特征数据。对于扇区大小为512字节的硬盘,从LBA2-LBA33保存的是分区表数据,一个分区项占用128个字节。而对于4096字节大小的扇区只需要4个扇区保留分区表就可以。磁盘的最后保存了分区表的一个备份,这个备份包含了全部的分区表和分区头信息。 对于LBA1的GPT头的详细数据如下
分区表项中的详细数据
这个表主要重点关注的是第一项和第二项,第一项由预定义的值,这些值表明不同的含义,比如 一个GPT的例子在这里我们使用的系统是使用efi方式安装的ubuntu虚拟机,首先我们先使用fdisk工具打印磁盘的一些信息 $ sudo fdisk -l /dev/sdaDisk /dev/sda: 50 GiB, 53687091200 bytes, 104857600 sectorsDisk model: VBOX HARDDISKUnits: sectors of 1 * 512 = 512 bytesSector size (logical/physical): 512 bytes / 512 bytesI/O size (minimum/optimal): 512 bytes / 512 bytesDisklabel type: gptDisk identifier: 2A7B0333-1C74-443D-8BA2-162A6F4733F7Device Start End Sectors Size Type/dev/sda1 2048 1050623 1048576 512M EFI System/dev/sda2 1050624 104855551 103804928 49.5G Linux filesystem 从这个信息中,我们知道这个虚拟机使用了两个分区,sda1是EFI系统分区的类型,sda2是Linux文件系统的分区。下面我们将使用gpt分析磁盘中的真实数据是否如fdisk中显示的一致。 和在MBR中一样我们使用的还是gpt工具,首先我们需要先获取第一个lba,即lba0
这个命令将会将sda设备中的第一个扇区读取出来并且保存到lba.0中,然后我们使用gpt工具进行 $ cat lba.0 | print_mbr<<< MBR >>>BootCode: 0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000UniqueMBRDiskSignature: 0x00000000Unknown: 0x0000PartitionRecord: 0x00000200eeffffff01000000ffff3f06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000Signature: 0xAA55<<< MBR Partition #0 >>>#0.BootIndicator: 0x0#0.Is Bootable? (syn): No#0.StartingCHS: 0, 0, 2#0.OSType: 0xEE#0.OSType (syn): GPT Protective#0.EndingCHS: 255, 255, 255#0.StartingLBA: 1#0.SizeInLBA: 104857599<<< MBR Partition #1 >>>#1.BootIndicator: 0x0#1.Is Bootable? (syn): No#1.StartingCHS: 0, 0, 0#1.OSType: 0x0#1.OSType (syn): Empty#1.EndingCHS: 0, 0, 0#1.StartingLBA: 0#1.SizeInLBA: 0<<< MBR Partition #2 >>>#2.BootIndicator: 0x0#2.Is Bootable? (syn): No#2.StartingCHS: 0, 0, 0#2.OSType: 0x0#2.OSType (syn): Empty#2.EndingCHS: 0, 0, 0#2.StartingLBA: 0#2.SizeInLBA: 0<<< MBR Partition #3 >>>#3.BootIndicator: 0x0#3.Is Bootable? (syn): No#3.StartingCHS: 0, 0, 0#3.OSType: 0x0#3.OSType (syn): Empty#3.EndingCHS: 0, 0, 0#3.StartingLBA: 0#3.SizeInLBA: 0 0xAA55 的签名显示这个一个有效的MBR,它的446个字节的引导代码都是0,并且类型显示是 0xEE 说明它是GPT的保护性MBR,GPT的实际分区以LBA1开始,下面打印lba1的数据
LBA1是GPT的头信息,这个头显示了一些详细的信息
然后,我们按照AlternateLBA找到对应的备份数据 $ cat lba.104857599 | print_gpt_headerWarning: Using only the first 92 bytes of input<<< GPT Header >>>Signature: 0x4546492050415254Revision: 0x00000100HeaderSize: 92HeaderCRC32: 0x4d7ce45aHeaderCRC32 (calculated): 0x4d7ce45aReserved: 0x00000000MyLBA: 104857599AlternateLBA: 1FirstUsableLBA: 34LastUsableLBA: 104857566PartitionEntryLBA: 104857567NumberOfPartitionEntries: 128SizeOfPartitionEntry: 128PartitionEntryArrayCRC32: 0x1bc39ab0 需要注意的是这里的AlternateLBA和MyLBA和主gpt头正好相反。GPT中提供了校验数据HeaderCRC32和PartitionEntryArrayCRC32用于计算分区表数据是否有错误。这个机制在MBR中是没有的。下面这个图来自UEFI规范 这个图非常详细展示了一个磁盘的空间布局,开始是一个保护MBR,后面跟着的是主分区表然后就是各个分区,最后保存了分区表的一个备份。 那么,分区表中是什么样的呢,我们还是使用GPT,GPT的分区表在512字节的扇区保存在LBA2到LBA33中。找到对应的分区表数据
这里显示了2个有效的分区数据,其中第一分区
第二个分区
这两个分区显示的和fdisk显示的是一致的。需要注意的是数据分区开始于2048,而不是34,这说明中间还有一块没有使用的间隙。在GPT规范中有一段描述说明了这个原因:'avoid the need to determine the physical block size and the optimal transfer length granularity, software may align GPT partitions at significantly larger boundaries. For example, assuming logical block 0 is aligned, it may use LBAs that are multiples of 2,048 to align to 1,048,576 byte (1 MiB) boundaries, which supports most common physical block sizes and RAID stripe sizes.' UEFIUEFI通常有一个固件策略引擎,它可以通过efibootmgr进行配置,而且UEFI还支持安全启动,这里不会介绍关于安全的。使用efibootmgr来配置启动项,也可以在UEFI的GUI中配置,每个厂商进入UEFI配置界面的方式也不一样。 efibootmgr我们可以使用 efibootmgr -v 查看引导顺序 $ sudo efibootmgr -vBootCurrent: 0005Timeout: 0 secondsBootOrder: 0005,0000,0001,0002,0003,0004Boot0000* UiApp FvVol(7cb8bdc9-f8eb-4f34-aaea-3ee4af6516a1)/FvFile(462caa21-7614-4503-836e-8ab6f4662331)Boot0001* UEFI VBOX CD-ROM VB0-01f003f6 PciRoot(0x0)/Pci(0x1,0x1)/Ata(0,0,0)N.....YM....R,Y.Boot0002* UEFI VBOX CD-ROM VB2-01700376 PciRoot(0x0)/Pci(0x1,0x1)/Ata(1,0,0)N.....YM....R,Y.Boot0003* UEFI VBOX HARDDISK VBf5cb0757-31383519 PciRoot(0x0)/Pci(0xd,0x0)/Sata(0,65535,0)N.....YM....R,Y.Boot0004* EFI Internal Shell FvVol(7cb8bdc9-f8eb-4f34-aaea-3ee4af6516a1)/FvFile(7c04a583-9e3e-4f1c-ad65-e05268d0b4d1)Boot0005* ubuntu HD(1,GPT,6dee24a7-4fe0-466f-b6f8-546e2048aceb,0x800,0x100000)/File(\EFI\ubuntu\shimx64.efi) 这个显示默认从编号0005进行引导(BootCurrent: 0005),而Boot0005对应的是 Boot0005* ubuntu HD(1,GPT, 这里我们不会详细的介绍EFI对Linux的操作系统的引导,后面会有一个详细的介绍UEFI在linux引导中的使用。 总结通过这篇文章我们了解EFI的工作机制,它使用一个固件策略引擎来根据配置来初始化计算机,引导操作系统启动,它通常和GPT分区一起使用,虽然BIOS也支持GPT中启动,我们这里不关心这种场景。这个章节我们也详细了解GPT的分区格式。 |
|