GRUB基础 — Multiboot规范

转:https://blog.csdn.net/huang987246510/article/details/136386633?spm=1001.2014.3001.5502
背景
每个操作系统(OS)在设计时都会考虑对boot loader的支持,OS的安装通常也涉及boot loader的预安装。在支持多OS的物理服务器使用场景中,通过链式机制让一个OS去引导另一个OS显然效率低下;定义一套boot loader和OS之间的接口,让遵循接口的所有boot loader都可以引导遵循相同接口的OS,才是更合理的解决方案。多OS兼容的场景我们称为Multiboot,boot loader和OS之间的接口规范我们称为Multiboot Specification。
GRUB是遵循Multiboot Specification的boot loader之一。1995年,Erich Boleyn和Brian Ford在GNU Hurd项目的开发过程中设计了Multiboot规范,并将GNU Hurd的boot loader作为规范的实现引导并其微内核GNU Mach。之后Erich尝试修改FreeBSD的boot loader让其兼容Multiboot规范,发现与其修改FressBSD的boot loader,不如直接从零开始单独写一个软件,至此GRUB诞生。可以说,GRUB就是为兼容多OS场景而生的。
GRUB在之后不断扩展以满足新的需求和场景,但很快,开发者发现GRUB遵循的Multiboot规范存在一些致命的缺陷导致对某些新功能的支持非常困难,并且设计导致的bug也不断增多,因此在2002年,Yoshinori K. Okuji开始重写GRUB的核心代码并将其重命名为GRUB2,原来的GRUB被重命名为GRUB Legacy,GRUB2遵循了Multiboot2规范。约2007年,GNU/Linux的发行版开始使用GRUB2,到2009年,大多数的Linux发行版已经将GRUB2作为默认版本安装。
目标
分析多OS使用场景,Multiboot规范需要考虑以下需求:
支持多种方式的OS启动;包括光盘启动,硬盘启动以及网络等
支持启动阶段对OS的动态配置;规范需要定义配置的标准方式
避免对OS紧耦合;方便OS功能的独立开发
支持启动模块;部分OS的启动无法独立完成,它们依赖其它预先启动的模块,如微内核操作系统Mach,规范需要考虑对启动模块的通用支持
分析boot loader和OS的交互逻辑,可以将两者的接口定义从以下三个方面拆分:
OS image format - 对OS镜像格式的定义,便于boot loader识别镜像并加载其内核到内存
Machine state - 对boot loader状态的定义,便于OS判断其引导者boot loader的状态
Boot information format - 对boot loader与OS之间传输信息的格式定义,便于控制OS的某些行为
Multiboot与Multiboot2都基于以上的分析而设计,Multiboot2在具体定义上扩展性更强,标准化做的更好,下面我们基于以上三点对比介绍两个规范的具体内容。
OS image format
OS image通常是一个普通的可执行文件(遵循ELF规范),其payload就是OS的section。通常boot loader将OS image加载到load address(ELF规范中section entry的sh_addr)对应的内存,之后跳转到entry address,最后将控制权交给OS。
如果所有的OS image都遵循ELF规范,那么boot loader总是可以根据规范找到OS image中包含的section并提取其load address,将其正确加载到load address指定的地址,但是,Mulitiboot规范需要考虑不支持ELF规范的OS image,也能被boot loader顺利地找到,就是说boot loader可以不需要理解ELF规范或者其它规范,也能正确地将OS image加载运行,要实现这个目标,需要将ELF规范中关于二进制程序加载相关的接口在Multiboot中也定义一遍,因此我们推测,OS image format必然包含了如何加载OS image的信息。
另外,某些OS image还会指定其倾向的图形模式,因此Multiboot提供了供OS image描述其推荐的图形信息可选字段。
除此之外还会有其它一些信息作为OS image format的内容,这里不赘述。
Multiboot
Mulitboot设计的OS image format分为了三个部分,其格式如下:
在这里插入图片描述
每个字段的长度和偏移如下:

在这里插入图片描述
Magic fields
Magic - 魔数,值为0x1BADB002,标示一个兼容Multiboot规范的OS image
Flags - 标识域,用于OS images向boot loader展示加载其自身涉及的一些依赖特性和可选特性。其中bit 0 ~ bit 15是依赖特性,如果boot loader无法理解这些特性,boot loader会直接报错;bit 16 ~ bit 31是可选特性,boot loader无法理解可以忽略。我们简单介绍以下特性:
bit 0,内存页对齐标记位,如果置位,OS image要求boot loader在加载启动模块(boot modules)时将其地址按照4k对齐。其原因是某些操作系统希望直接将启动模块映射到地址空间,4k对齐可以方便映射
bit 1, 内存信息标记位,如果置位,OS image期望boot loader将系统的可用内存信息按照Boot information format中的定义,写入到mem_*字段,方便OS启动后解析,如果boot loader有能力获取整个内存映射的视图,写入mmap_*字段
Bit 2,图形信息标记位,如果置位,OS image期望boot loader填入图形信息到Boot information format定义的对应字段
Bit 16,加载信息标记位,可选,如果置位,标示地址字段(address fields)有效,boot loader不再根据ELF header中的地址计算加载地址,而是按照该字段包含的地址加载OS image。当OS image遵循ELF格式时,该字段不需要OS image提供,boot loader可以直接根据ELF头部解析OS image并正确加载;当OS image不是ELF格式时,该字段就是必填项了,boot loader会从这个字段提取加载地址并加载OS image到对应的内存位置。
Checksum
Address fields
Boot loader加载非ELF格式的OS image file示意图如下所示:
在这里插入图片描述
Header_addr - OS image要求boot loader将Multiboot header加载到的内存物理地址。boot loader在加载OS images时,首先查找魔数0x1BADB002在OS image文件的偏移(后文用header_offset表示),然后从header_offset开始,加载header_addr - load_addr长度的内容到Header_addr指向物理内存,完成header的加载。
Load_addr - OS image的代码段加载地址。boot loader计算Load_end_addr - Load_addr的长度,作为代码段的长度(text segment length),然后从header_offset + (header_addr - load_addr)开始(代码段在OS image文件的偏移text_seg_offset),拷贝text segment length长度的内容到Load_addr指向的物理内存,完成代码段的拷贝。
Load_end_addr - 代码段结束地址。当该字段存在时,用于计算加载OS image代码段的长度;当该字段为零时,从text_seg_offset到文件结束都是代码段的内容,boot loader会全部加载。
Bss_end_addr - bss段地址。如果该字段不为零,boot loader会将该地段指向的物理地址预留作OS的bss段使用
Entry_addr - OS入口地址。完成整个OS image加载后,boot loader程序跳转的物理地址。
Graphics fields
Graphics fields是OS image期望boot loader设置的显卡图形模式和具体的设置参数,即显卡的framebuffer参数,有4个字段:
Mode_type - 期望boot loader设置的模式,0表示线性扫描模式,1表示EGA文本模式。
Width - 期望boot loader设置的framebuffer行数
Height - 期望boot loader设置的framebuffer列数
Depth - 期望boot loader设置的framebuffer分辨率,即每个像素包含的bit
可以看到,Multiboot规范在设计OS image format这部分时,针对每个需求场景都考虑了对应的字段,但没有做扩展性设计,一旦有新的需求引入,基于现有的OS image format很难实现其功能。
Multiboot2
Mulitboot2总结了Multiboot的缺点,设计OS image format时,在功能扩展性和架构扩展性等方面都做了对应考虑。Mulitboot2的OS image format格式设计如下:
在这里插入图片描述
Mulitboot2设计了一个通用格式(tag)来表示OS image的需求信息,将每一类信息以tag的形式存放,用特殊的tag(end tag)标识结束。可以看到,Mulitboot中设计的address fields和graphics fields包含的信息被address tag、entry tag、framebuffer tag等tag提供了。同时,Mulitboot2在magic fields中还增加了架构相关的字段,对支持架构进行了扩展。
可以看到,Multiboot2不兼容Multiboot规范,因此基于Multiboot2实现的GRUB2也不兼容GRUB。
Machine state
Boot loader在加载OS image到内存与跳转到entry address将控制权交给OS这个过程中,还有一些准备工作,包括向OS同步一些自己的状态,并向OS传递一些参数,从而实现对OS的动态配置。Boot loader利用CPU的寄存器完成这个工作。
Multiboot
Multiboot规范在设计时仅考虑了intel i386架构,因此它仅仅规定了如何使用i386CPU寄存器完成状态和参数传递。在交出控制权给OS之前,multiboot规范要求CPU具有如下状态:

EAX
存放multiboot header的魔数,0x2BADB002,以此向OS表明它是被multiboot-compliant的boot loader引导的,而非其它boot loader。
EBX
存放OS启动信息(Boot information)的物理地址,OS启动信息的格式参考下一小节
CS
存放OS image代码段(code segment)物理地址
DS
ES
SS
存放OS image数据段(data segment)物理地址
A20 gate
设置为使能
CR0
清零PG(Paging)位,禁止分页;使能PE(Protection Enable)位,开启页保护
EFLAGS
清零VM(Virtual Real Mode)位,禁止进入虚拟实模式;清零IF(Interrupt Flag)位,屏蔽中断
ESP
栈指针,由OS在启动后设置,boot loader不做设置
GDTR
全局描述符表寄存器,当OS准备好全局描述描述表之后,设置该寄存器,boot loader不做设置
IDTR
中断描述符表寄存器,当OS准备好中断描述符表之后,设置该寄存器,boot loader不做设置
Multiboot2
Multiboot2规范在设计时考虑了对不同平台的支持,而不同平台的硬件寄存器不相同,因此Multiboot2分平台定义machine state,这里的平台包括但不限于MIPS,i386,EFI i386,EFI amd64等,其内容和Multiboot类似。如下:
MIPS machine state
TBD
i386 machine state
TBD
EFI i386 machine state
TBD
EFI amd64 machine state
TBD
Boot information format
上文提到EBX中存放的物理地址指向了boot loader传递给OS的参数信息,其格式即为Boot information format,OS按照该格式解析启动信息。
Multiboot
Multiboot定义的格式信息如下:
在这里插入图片描述
Multiboot2
Multiboot定义的boot information format和OS image format相同,不具有扩展性,Multiboot2没有这一缺陷,它同样以tag为基本结构对boot information做描述,其格式如下:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值