基于Grub 2.00的x86内核引导流程--源代码情景分析(1)

来源:互联网 发布:淘宝让投诉盗图后果 编辑:程序博客网 时间:2024/06/01 07:45

目前Linux中使用最广泛的的bootloader是Grub(GRand Unified Bootloader)。如今Grub 2已经替换了早期的0.9x系列版本的Grub Legacy, 而且Grub Legacy已经不再开发维护。虽然Grub 2从名字上看像是Grub的升级版,但其源代码实际被完全重构了。现从源代码角度分析基于Grub 2.00的x86内核引导流程。

1. 磁盘简介

由于在Grub进行内核引导的过程中涉及到磁盘操作,先简介一下磁盘为后续引导流程分析作铺垫。磁盘三要素:由所有盘面上相同半径的同心圆形磁道(Track)组成的柱面(Cylinder), 磁头(Head), 扇区(Sector)之间的关系如下图所示:


对于磁盘,其最小存储单位为扇区(Sector),在相当长的一段时间里,扇区的大小固定在512 bytes[1]. 但是从2009年开始出现扇区大小为4096 bytes的磁盘,即Advanced Format disks。

对于扇区的编址,早期的方案是CHS编址(Cylinder-Head-Sector),即用数据元组CHS tuples (c,h,s)的形式表示一个扇区的位置,但是在CHS编址时,扇区号是从1开始的,没有扇区0,但磁头和柱面编号都是从0开始的,即CHS编址起始于地址(0,0,1)。另外一种编址方案是LBA编址(Logical Block Addressing),把整个磁盘的所有扇区资源统一分配序号。在2003年发布的ATA-6标准中,LBA采用48-bit地址。

 

CHS数据元组(c, h, s)根据如下公式转换成相应的LBA逻辑地址:

LBA  = (c×Nheads + h)×Nsectors + (s − 1)

其中:Nheads是硬盘中的磁头数目,Nsectors是每条磁道上可以划分的最大的扇区数目。上面的公式意味着LBA对扇区的编址是从0开始的,所以在Grub的boot.S源代码中,当磁盘不支持LBA模式,代码执行流回退至CHS模式继续进行处理时,会将编址的起始地址调整成从1开始。

==================grub-2.00/grub-core/boot/i386/pc/boot.S================= 288           /* normalize sector start (1-based)*/ 289           incb  %cl


[1]Floppydisks and controllers use physical sector sizes of 128, 256, 512 and 1024 bytes(e.g., PC/AX), whereby formats with 512 bytes per physical sector becamedominant in the 1980s.


磁盘在使用过程中总是会涉及到分区方案,其中一个典型的四分区MBR磁盘结构如下所示:


其中:磁盘的0柱面、0磁头、1扇区即为主引导记录MBR(MasterBoot Record)扇区。它由三个部分组成:主引导程序bootloader、磁盘分区表和有效标志(0x55AA)。在总共512字节的主引导扇区里主引导程序(boot loader)占446个字节,第二部分是Partition table区(分区表),占64个字节,磁盘中分区有多少以及每一分区的大小都记在其中。第三部分是磁盘有效标志签名,占2个字节,固定为0x55AA。 另外对于MBR磁盘,由于扇区空间限制分区表最多占用64字节,每个分区表项占用16字节,所以其最多有4个分区。

Table 1 典型的MBR结构

Address

Description

Size

Hex

Dec

(bytes)

+000

+0

Bootloader code area

446

+1BE

+446

Partition entry №1

分区表      (Partition table)

16

+1CE

+462

Partition entry №2

16

+1DE

+478

Partition entry №3

16

+1EE

+494

Partition entry №4

16

+1FE

+510

0x55

Boot signature

2

+1FF

+511

0xAA

Total size: 446 + 4×16 + 2

512

 

后续对bootloader部分会有详细分析。先来分析磁盘分区表,其定义如下:

Table 2 磁盘分区表项(DiskPartition Table)结构

Offset

Size

Description

0

byte

Boot indicator bit flag: 0 = no, 0x80 = active

1

byte

Starting Head

2

6 bits

Starting Sector

3

10 bits

Starting Cylinder (High two bits are bit 6-7 of Starting Sector)

4

byte

System ID

5

byte

Ending Head

6

6 bits

Ending Sector

7

10 bits

Ending Cylinder (High two bits are bit 6-7 of Ending Sector)

8

4 bytes

Relative Sector (The partition's starting LBA value)

12

4 bytes

Partition Length (Total Sectors in partition)

磁盘分区表项结构定义对柱面、磁头和扇区的大小分别限定在10 bits、8 bits和6 bits,

该种定义隐含着限制了磁盘的大小。分区表可描述磁盘容量的大小根据如下公式计算:

MaxCapacity  =Nheads×Nsectors×Ncylinders×SectorSize

取(c,h,s)的上限便可得到最大磁盘容量:

MaxCapacity  =256×64×1024×512 bytes = 8GB

即:现有的分区表项结构定义只能描述8GB容量以下的硬盘。

 

随着磁盘的容量越来越大,8GB的容量限制显然亟待扩容,最好的方式应该是重新定义分区表项结构,但不幸的是:对于容量大于8GB的磁盘,磁盘分区表项结构定义并没有更新,只是将其中CHS相关的结构体变量设置成一个不合理配置(Cylinder = 1023, Head = 255, Sector = 63),然后用32位LBA扇区地址(Relative Sector)和32位分区长度(PartitionLength)去描述某个磁盘分区,但是该用法依然会限制磁盘容量:

MaxCapacity  =232  512 bytes = 2TB

让人感觉更不合理的是:在2003年发布的ATA-6标准中,LBA采用48-bit地址,在此分区表项定义中却只能使用其低32bit,这是一种自废武功的做法。为何不将结构体中空闲的CHS相关字段组合起来保存LBA-48的高16位呢?下面就是一种非官方的定义,悲哀的是:这种合理的定义并没有被实现。

Table 3 "Unofficial" 48bit LBA Proposed MBR Format

Offset

Size

Description

0

byte

Bit flags field: 1 = not bootable, 0x81 = active

1

byte

Signature-1 (0x14)

2

2 bytes

Partition Start LBA (high 16-bit of 48 bit value)

4

byte

System ID

5

byte

Signature-2 (0xeb)

6

2 bytes

Partition Length (high 16-bit of 48 bit value)

8

4 bytes

Partition Start LBA

12

4 bytes

Partition Length

 

追根溯源,对于MBR磁盘,由于扇区空间大小的限制,留给磁盘分区表项的空间只有64 bytes,仅有的这点空间还要平均分配给若干个分区。清晰描述一个分区所需的最小空间需求摆在那里,无论怎么设计磁盘分区表项,用一个受限的分区表空间去描述的磁盘空间也同样是受限的。于是为了解决MBR磁盘分区表可描述磁盘容量受限的问题,在2004年,Wintel在共同推出的一种可扩展固件接口(EFI: Extensible Firmware Interface)的主板升级换代方案中提出了GPT分区模式。

 

GPT(Globally Unique Identifier Partition Table Format)磁盘分区模式虽然是EFI方案的一部分,但并不依赖于EFI主板,在BIOS主板的PC中也可使用GPT分区。与MBR分区方案的最大4个分区表项的限制相比,GPT对分区数量没有限制。GPT还允许将主磁盘分区表和备份磁盘分区表用于冗余,支持唯一的磁盘和分区GUID。GPT分区方案目前在Windows操作系统上应用比较广泛。GPT分区方案示意图如下:


为了前向兼容性,在GPT分区方案中传统的MBR空间被保留下来,但是其用途是防止基于MBR分区的磁盘工具误判以及可能误写GPT磁盘。这也是第一个逻辑扇区LBA0称为保护分区PMBR(Protective MBR)的缘由。

Linux支持通过BIOS从基于GPT的磁盘中进行引导,即所谓的Hybrid MBR模式。该模式下保护分区PMBR与传统的MBR作用相同:该扇区被用来存放引导程序bootloader第一阶段(Stage 1)的代码,但是磁盘分区表项中仅包含一种类型为0xEE的主分区表项(Primary Partition Entry)。

Note: 后续内核引导流程分析时,以当下主流的MBR分区磁盘为主,GPT磁盘仅作提及,不作详述。 


阅读全文
0 0
原创粉丝点击