基于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磁盘仅作提及,不作详述。
- 基于Grub 2.00的x86内核引导流程--源代码情景分析(1)
- 基于Grub 2.00的x86内核引导流程--源代码情景分析(2)
- 系统管理指南:基本管理 第11 章• x86: 基于GRUB 的引导(任务)
- Linux内核源代码情景分析-基于socket的进程间通信
- linux内核源代码情景分析
- Linux内核源代码情景分析-外部设备存储空间的地址映射
- Linux内核源代码情景分析-文件系统的安装
- Linux内核源代码情景分析-文件系统安装后的访问
- Linux内核源代码情景分析-文件的打开
- Linux内核源代码情景分析-文件的写
- 关于Linux内核源代码情景分析的点点滴滴
- Linux内核源代码情景分析学习简记1
- Linux 内核源代码情景分析 chap 1 预备知识
- Linux内存管理的基本框架(Linux内核源代码情景分析读书笔记连载)
- Linux地址映射的全过程(Linux内核源代码情景分析读书笔记连载#)
- 基于x86的Redboot启动流程分析
- x86 linux系统内核引导流程梳理
- Linux内核源代码情景分析-内存管理
- The APK file does not exist on disk
- WPF DataGrid 性能加载大数据
- unity物体的移动/脚本的添加
- C#操作XML总结
- Python文件操作与目录
- 基于Grub 2.00的x86内核引导流程--源代码情景分析(1)
- JDK之Arrays类
- Unity UGUI 原理篇 (一):Canvas 渲染模式
- ServiceStack.Redis订阅发布服务的调用(Z)
- 2017多校联合四1009/hdu 6075Questionnaire思维
- .NetChajian
- 性能优化方法(Z)
- web第四天js
- Apache 服务器搭建 总结