热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

目前Linux中使用最广泛的的bootloader是Grub(GRandUnifiedBootloader)。如今Grub2已经替换了早期的0.9x系列版本的GrubLegacy,而且Gru

目前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磁盘仅作提及,不作详述。 



推荐阅读
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 配置IPv4静态路由实现企业网内不同网段用户互访
    本文介绍了通过配置IPv4静态路由实现企业网内不同网段用户互访的方法。首先需要配置接口的链路层协议参数和IP地址,使相邻节点网络层可达。然后按照静态路由组网图的操作步骤,配置静态路由。这样任意两台主机之间都能够互通。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • 本文介绍了Windows操作系统的版本及其特点,包括Windows 7系统的6个版本:Starter、Home Basic、Home Premium、Professional、Enterprise、Ultimate。Windows操作系统是微软公司研发的一套操作系统,具有人机操作性优异、支持的应用软件较多、对硬件支持良好等优点。Windows 7 Starter是功能最少的版本,缺乏Aero特效功能,没有64位支持,最初设计不能同时运行三个以上应用程序。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • Windows7 64位系统安装PLSQL Developer的步骤和注意事项
    本文介绍了在Windows7 64位系统上安装PLSQL Developer的步骤和注意事项。首先下载并安装PLSQL Developer,注意不要安装在默认目录下。然后下载Windows 32位的oracle instant client,并解压到指定路径。最后,按照自己的喜好对解压后的文件进行命名和压缩。 ... [详细]
  • MPLS VP恩 后门链路shamlink实验及配置步骤
    本文介绍了MPLS VP恩 后门链路shamlink的实验步骤及配置过程,包括拓扑、CE1、PE1、P1、P2、PE2和CE2的配置。详细讲解了shamlink实验的目的和操作步骤,帮助读者理解和实践该技术。 ... [详细]
  • 解决github访问慢的问题的方法集锦
    本文总结了国内用户在访问github网站时可能遇到的加载慢的问题,并提供了解决方法,其中包括修改hosts文件来加速访问。 ... [详细]
author-avatar
一粒星尘ch
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有