Linux系统启动过程

说启动过程之前,先说说一些背景知识。

系统的启动模式有BIOS和UEFI两种,前者比较老,是一直在使用的方式,后者比较性,但是性能比较好,微软知道win10才支持UEFI启动方式。

硬盘的分区格式也有GPT和MBR两种,而且启动模式和硬盘分区格式还有一些关系,具体如下:

  1.BIOS模式可启动GPT和MBR硬盘上的系统;

  2.UEFI一般只能启动GPT上的系统,虽然也支持MBR,但是不推荐这种方式,因为UEFI不会执行主分区记录(不管它存在与否)而是执行ESP。而且要求硬盘必须是原生硬盘(不能是虚拟机),也就是说UEFI启动方式不支持虚拟机。

根据这种对应关系,所以我们装系统的时候就有3中选择:

  1.BIOS/MBR 这是最老的方案,几乎支持所有的系统。在BIOS/MBR方案上,需要给引导器留一小块位置,这一小块位置叫做post-MBR gap,这是MBR分区方案下一块处于512byte(MBR第一个扇区)之后,第一个分区开始之前的一段内存。这段内存推荐1到2M。但是为了兼容windows的31k对齐,所以最好用一个支持1M对齐的的分区工具来做分区。

  2.BIOS/GPT 这是比较奇怪的方案,一般只有受限的情况下才会使用(比如虚拟机中不支持UEFI,所以只能用这种方案)。在BIOS/GPT方案上,需要给引导器(比如GRUB)一个安放镜像空间的位置,这通常是一个只要几M的小空间,分区的格式是BIOS Boot,并且这个分区不能分配文件系统格式,也不能被挂载。另外这个分区不一定要在硬盘的开头,可以在任意位置,这点区分了它和post-MBR gap的区别。

  3.UEFI/GPT 这是比较推崇的方案。这种方式强制需要一个专门用以安装UEFI应用的ESP分区(EFI System Partition),ESP分区只能是原生的物理硬盘,不能是LVM或者是RAID,这算是UEFI的缺点。ESP的文件系统格式支持vfat(一般都用FAT32)。

需要指出的是,BIOS无论采用各种硬盘分区方案,都会用到MBR。UEFI无论采用那种分区方案,也不管MBR存在不存在,都不会从MBR启动任何代码,UEFI从NVRAM中直接读取相关配置,配置文件中以变量的形式保存了一些成为启动点(boot entry)的东西,通过boot entry,UEFI就知道从哪里启动相应的UEFI应用(the boot configuration is defined by variables stored in NVRAM, including variables that indicate the file system paths to OS loaders and OS kernels),如果是从磁盘启动,那么这些UEFI应用都是存放在磁盘的EFI System Partition(ESP)中的,可以是 bootloaders, operating system kernels, and utility software等等。一般都是bootloader比如grub2.

 

BIOS启动过程:

  1. System switched on, the power-on self-test (POST) is executed.
  2. After POST, BIOS initializes the necessary system hardware for booting (disk, keyboard controllers etc.).
  3. BIOS launches the first 440 bytes (the Master Boot Record bootstrap code area) of the first disk in the BIOS disk order. ——stage 1
  4. The boot loader's first stage in the MBR boot code then launches its second stage code (if any) from either:  —— stage 1.5
  5. The actual boot loader is launched.
  6. The boot loader then loads an operating system by either chain-loading or directly loading the operating system kernel.   —— stage 2

UEFI启动过程:

  1. System switched on, the power-on self-test (POST) is executed.
  2. UEFI initializes the hardware required for booting.
  3. Firmware reads the boot entries in the NVRAM to determine which EFI application to launch and from where (e.g. from which disk and partition).
    • A boot entry could simply be a disk. In this case the firmware looks for an EFI system partition on that disk and tries to find a EFI application in the fallback boot path \EFI\BOOT\BOOTX64.EFI (BOOTIA32.EFI on systems with a IA32 (32-bit) UEFI). This is how UEFI bootable removable media work.
  4. Firmware launches the EFI application.

 

GRUB2

grub2是一个类unix操作系统中常用的启动加载器,在常见的BIOS启动模式中,它分为三个部分。

   stage 1:

   负责stage 1 的代码 boot.img 放在MBR中分区表后面,具体在434 到446 bytes之间,以机器码的形式存在,由于这块区域实在太小了,放不下复杂的操作,也没法安装文件系统驱动器,所以它不认识文件系统。stage 1 的任务就是加载stage1.5。

  stage 1.5:

 负责stage 1.5的代码 core.img 通常位于住分区记录(MBR)后到第一个分区前的被称为post-MBR gap的以小段区域内(MBR分区方案)或者一个专门的BIOS Boot分区内(GPT分区方案)。这段区域稍微大一点,所以它可以安装文件系统驱动器,也就可以识别文件路径,所以stage 2的相关文件可以放到某个文件路径下面了。stage 1.5的任务就是定位到stage 2阶段的相关文件并且加载执行他们。

 stage 2:

stage 2才是真正执行功能的模块,stage 2的代码通常放在/boot 尤其是 /boot/grub2中,文件系统可以是standard EXT and other Linux filesystems, FAT, and NTFS等选择。stage 2不像前两个阶段,它没有镜像镜像文件,而是有很多个子文件夹,里面包含了runtime kernel modules that are loaded as needed from the /boot/grub2/i386-pc directory。 stage 2 的任务就是加载操作系统内核进内存,并且把控制权交给操作系统,至此,grub的任务就完成了。

GRUB2在BIOS平台上的常规启动步骤是这样的:BIOS --> boot.img[MBR] --> core.img[MBR gap/embedding area/BIOS Boot Partition] --> 设置"prefix root cmdpath"环境变量 --> 加载"normal.mod"模块[同时还包括它所依赖的 terminal crypto extcmd boot gettext 模块] --> 执行"normal $prefix/grub.cfg"命令

GRUB2在UEFI平台上的常规启动步骤是这样的:UEFI --> core.img[BOOTX64.EFI/BOOTX86.EFI] --> 设置"prefix root cmdpath"环境变量 --> 加载"normal.mod"模块[同时还包括它所依赖的 terminal crypto extcmd boot gettext 模块] --> 执行"normal $prefix/grub.cfg"命令

 

grub有一些特殊的环境变量,其中最重要的三个是:

  prefix:绝对路径形式的'/boot/grub'目录位置(也就是GRUB2的安装目录),例如'(hd0,gpt1)/grub'或'(hd0,msdos2)/boot/grub'。这是安装grub时写死在core.img中的。你只应该使用此变量,而不应该修改它,除非系统不能启动了,你得在grub的rescue重新指定它。

  cmdpath:    当前被加载的"core.img"所在目录(绝对路径)。例如:UEFI启动可能是'(hd0,gpt1)/EFI/UBUNTU'或'(cd0)/EFI/BOOT',BIOS启动可能是'(hd0)'。由GRUB2自动设置。你只应该使用此变量,而不应该修改它。

  root:    设置"根设备"。任何未指定设备名的文件都视为位于此设备。初始值由GRUB在启动时根据"prefix"变量的值自动设置。在大多数情况下,你都需要修改它。

 

 

 参考:

《主引导区MBR》

《启动过程》

《GRUB》

《ESP》

《linux启动过程简介》

《GNU GRUB Wikipedia》

《Unified Extensible Firmware Interface Wikipedia》

《GRUB2配置文件 grub.cfg详解》

posted on 2018-12-27 11:18  J.M.Liu  阅读(1544)  评论(0编辑  收藏  举报