文章目录
- 前言
- 一、BIOS简介
- 二、MBR
- 三、Linux BIOS 启动
- 3.1 BIOS stage
- 3.2 Boot Loader Stage
- 3.2.1 boot.img
- 3.2.2 core.img
- 3.2.3 *.mod
- 3.3 Kernel Stage
- 参考资料
前言
本文以 centos 6/7 (2.6.32/3.10.0 ),x86_64平台为例。
固件保存在主板上的 ROM 中,是计算机上电后执行的第一段程序。固件启动阶段的核心功能包括硬件初始化、硬件自检和加载 bootloader,最终会把控制权转交给给 bootloader。
固件启动阶段主要有两种启动方式:Legacy BIOS 和 UEFI。
这篇文章描述了Linux x86_64 UEFI 启动过程:Linux x86_64 UEFI 启动,接下来描述Linux x86_64 UEFI 启动过程。
VMware Workstation Pro安装虚拟机默认都是BIOS启动:
其启动过程如下:
详细过程:
一、BIOS简介
在计算机领域,BIOS(Basic Input/Output System,基本输入/输出系统)是一种固件,用于为操作系统和程序提供运行时服务,并在引导过程(开机启动)中执行硬件初始化。BIOS固件预装在IBM PC或IBM PC兼容系统主板上,并存在于一些基于UEFI的系统中,以保持与不支持UEFI本机操作的操作系统的兼容性。这个名字起源于1975年CP/M操作系统中使用的基本输入/输出系统。最初专有于IBM PC的BIOS已被一些公司(如Phoenix Technologies)逆向工程,用于创建兼容系统。原始系统的接口成为事实上的标准。
在旧版PC中,BIOS初始化和测试系统硬件组件(自检或POST),并从存储设备加载引导加载程序,然后初始化内核。在DOS时代,BIOS为键盘、显示器、存储和其他输入/输出(I/O)设备提供了BIOS中断调用,标准化了应用程序和操作系统的接口。更近期的操作系统在启动后不再使用BIOS中断调用。
大多数BIOS实现都专门设计用于特定的计算机或主板型号,通过与各种设备特别是系统芯片组进行接口交互。最初,BIOS固件存储在PC主板上的ROM芯片中。在后期的计算机系统中,BIOS内容存储在闪存存储器中,因此可以在不移除主板上的芯片的情况下进行重写。这使得用户可以轻松更新BIOS固件,以添加新功能或修复错误,但也为计算机感染BIOS恶意软件提供了可能性。
统一可扩展固件接口(UEFI)是传统PC BIOS的后继者,旨在解决其技术限制。自2019年起,所有面向英特尔平台的PC不再支持传统BIOS。
二、MBR
主引导记录(Master Boot Record,MBR)是位于计算机分区的固定磁盘或可移动驱动器等大容量存储设备的前几个扇区中的一种引导扇区类型,用于与IBM PC兼容系统及更高版本的系统一起使用。MBR的概念在1983年的PC DOS 2.0中首次公开引入。
MBR保存了关于磁盘扇区(也称为"块")如何划分为分区的信息,每个分区理论上包含一个文件系统。MBR还包含可执行代码,用作已安装操作系统的加载程序,通常通过将控制权传递给加载程序的第二阶段或与每个分区的卷引导记录(Volume Boot Record,VBR)结合使用。这段MBR代码通常被称为引导加载程序。
MBR中的分区表组织方式将分区磁盘的最大寻址存储空间限制为2 TiB(232 × 512字节)。采用32位算术或4096字节扇区来略微提高这个限制的方法没有得到官方支持,因为这将破坏与现有引导加载程序、大多数MBR兼容的操作系统和相关系统工具的兼容性,并在狭义的系统环境之外使用时可能导致严重的数据损坏。因此,基于MBR的分区方案正在逐步被GUID分区表(GUID Partition Table,GPT)方案取代。GPT可以与MBR共存,以提供对旧系统的某种有限的向后兼容性。
MBR由位于驱动器的第一个扇区中的512字节组成。
一个经典的通用MBR的结构:
Address | Description | Size(bytes) |
---|---|---|
0x0000 (0) | Bootstrap code area | 446 |
0x01BE (446) | Partition entry №1 | 16 |
0x01CE (462) | Partition entry №2 | 16 |
0x01DE (478) | Partition entry №3 | 16 |
0x01EE (494) | Partition entry №4 | 16 |
0x01FE (510) | 0x55 | 1 |
0x01FF (511) | 0xAA | 1 |
446 + 16 *4 + 1 + 1 = 512
0~446 字节保存 bootloader;447~510 字节保存分区信息,共四个,每个 16 字节;511~512 字节保存启动签名,内容为 0xAA55,0xAA表明这是一个可启动设备。
三、Linux BIOS 启动
bootloader 启动阶段的核心功能是加载内核和 initramfs,并将控制权交给内核。
主要是:BIOS + MBR + grub2 和 UEFI + GPT + grub2
这里只介绍 BIOS+MBR+grub2 启动方案,这种引导方式,固件 BIOS 从启动设备的第一个扇区读取 bootloader。
过程如下:
boot.img(mbr 446B) => core.img(diskboot.img + kernel.img + *mod)==> /boot/grub2/grub.cfg ==> vmlinuz 和 initramfs
上述 boot.img、core.img 都是 bootloader的一部分,他们被硬编码到启动盘上,不是以文件的形式存在于文件系统中。
# cat /etc/centos-release
CentOS Linux release 7.4.1708 (Core)
# ls -l /boot/grub2/i386-pc/*.img
-rw-r--r--. 1 root root 512 Dec 9 2021 /boot/grub2/i386-pc/boot.img
-rw-r--r--. 1 root root 26676 Dec 9 2021 /boot/grub2/i386-pc/core.img
# file /boot/grub2/i386-pc/boot.img
/boot/grub2/i386-pc/boot.img: x86 boot sector; partition 4: ID=0xd4, starthead 205, startsector 4277266767, 0 sectors, code offset 0x63
# file /boot/grub2/i386-pc/core.img
/boot/grub2/i386-pc/core.img: data
Grub由2个image组成:boot.img + core.img。其中boot.img大小固定为512Byte。
Centos7系统/boot/grub2/i386-pc/*目录下存在2个image镜像文件,这些文件会被grub2-install命令安装到硬盘的相应位置。当BIOS执行完毕后,就会被加载并引导系统完成启动。
LINUX引导过程包括三个阶段:
(1) The BIOS stage.
(2)The Boot loader stage.
(3)The Kernel stage.
如下图所示:
3.1 BIOS stage
ROM中包含JUMP函数的形式的指令,告诉CPU启动BIOS。
Linux的引导过程始于BIOS阶段。BIOS是安装在主板上的一个小型存储模块。BIOS使用存储在CMOS芯片中的信息,CMOS芯片是安装在主板上的另一个存储模块,其中包含有关系统硬件配置的信息。
(1)BIOS执行电源自检(POST)-检查硬件可用性的过程。BIOS会向每个设备发送一个电脉冲。如果设备回应(ACK),则表示硬件工作正常且准备就绪。如果设备不回应(NACK),则将将其视为故障设备或从系统中移除的设备。BIOS会维护一个连接到计算机的设备列表。它会更新列表以适应任何新的硬件,并在下次启动时使用该列表。
(2)如果BIOS在POST过程中发现任何错误,它会通过一系列的蜂鸣声或在屏幕上显示的文本消息通知用户。在这个阶段发生的错误几乎总是硬件问题。
(3)激活安装在计算机中不同卡上的其他BIOS芯片-例如,SCSI(小型计算机系统接口)和图形卡通常都有自己的BIOS芯片。
(4)它通过执行对每个内存地址的读/写测试来验证RAM。它初始化寄存器、电源管理和显示设置。
(5)然后,BIOS查看在CMOS芯片中以特定顺序标识为启动设备的存储设备序列。BIOS将尝试从第一个设备开始启动序列。如果BIOS找不到启动设备,它将尝试列表中的下一个设备。如果在设备上找不到正确的文件,启动过程将停止。
请注意:要使设备可引导,它必须在其第一个/最后一个扇区(取决于制造商,通常是硬盘的第一个扇区)中具有主引导记录(MBR),也称为引导扇区。您需要格式化磁盘以在其引导扇区中添加MBR。MBR的大小为512字节(一个扇区)。
MBR包含以下详细信息:
(1)主引导加载程序代码(446字节)。
(2)分区表(64字节)。
(3)魔数(2字节)。
主引导加载程序代码:该代码提供引导加载程序信息以及实际引导加载程序代码在硬盘上的位置细节。这对CPU加载引导加载程序的第二阶段非常有帮助。
分区表:64字节的数据,用于存储诸如每个分区的起始地址和结束地址、分区大小、分区类型(主分区、扩展分区、逻辑分区或交换分区)等信息。
魔数:魔数用作MBR的验证检查。如果MBR损坏,可以使用魔数来恢复它。
MBR无法处理超过2 TB容量的磁盘。MBR最多支持四个主分区 - 如果您需要更多分区,您必须将其中一个主分区设置为“扩展分区”,并在其中创建逻辑分区。每个分区在MBR中需要占用16个字节的空间,因此最多可以获得4个分区(16 * 4 = 64)。
在现代计算机中,MBR已被UEFI(统一固件接口)取代。
3.2 Boot Loader Stage
在初始化第一个启动设备后,BIOS将控制权交还给CPU。现在,CPU将加载MBR并读取MBR的第一部分,以获取实际引导加载程序/第二阶段引导加载程序的位置。实际引导加载程序位于MBR之后硬盘的前30千字节,此空间用于存储文件系统驱动程序和模块;并加载到RAM中以读取其配置并显示引导菜单,以选择要加载到内存中的内核。
两个最常用的Linux引导加载程序是:
Linux Loader(LILO)和 Grand Unified Bootloader(GRUB)。
大多数现代LINUX版本使用GRUB而不是LILO。
GRUB的过程包括三个阶段,分别称为Stage 1、Stage 1.5和Stage 2。引导加载程序加载后,CPU可以访问磁盘和内存,并从磁盘上存储的/boot/grub/grub.conf配置文件中读取。它创建一个临时虚拟文件系统的镜像,称为INITRD或初始RAM磁盘,然后挂载INITRD镜像并加载内核。GRUB指定了一个分区,其中包含压缩的内核映像、必要的模块和initramfs(initrd)。
如下图所示:
3.2.1 boot.img
boot.img是Grub2第一个被运行的程序,它被写入到MBR(Master Boot Record),固定大小为512B。boot.img功能很简单,主要是读取磁盘中core.img中的第一个扇区(sector)到内存中并执行相应的代码,因为仅有512B,boot.img不能够加载文件系统,并且只能从硬盘固定的位置加载。
3.2.2 core.img
core.img是GRUB2的核心,由 grub-mkimage 动态创建,包括了 diskboot.img、kernel.img 和一系列模块。通常core.img包含了足够的模块(modules)为了访问xfs/ext4文件系统/boot/grub2目录,并且从/boot/grub2下加载所有剩余的模块,这些模块包含了启动目录处理,加载操作系统等等功能。目前disk限制core.img安装必须小于32KB,core.img一般被安装在硬盘特殊区域:embedding area。
Grub2认识并支持更多的文件系统,并且可以通过Grub2的主程序直接在文件系统中搜寻kernel文件:
core.img 可以直接从文件系统中读取 grub.cfg,路径为 /boot/grub2/grub.cfg,根据 grub.cfg 文件读取加载内核和 initramfs,并将控制权交给内核。
(1)diskboot.img
diskboot.img 由 grub2-pc-modules 包提供,大小 512B,组成 core.img 的第一个扇区,功能是读取 core.img 的剩余部分(kernel)到内存中,并跳转到 kernel.img。
当从硬盘启动的时候这是core.img第一个扇区(sector)的内容,主要功能是读取剩下的core.img到内存中并开始运行kernel.img。同样diskboot.img没有文件系统的功能,当读取剩余的core.img时候,依然从硬盘固定位置读取。
(2)kernel.img
kernel.img 由 grub2-pc-modules 包提供,大小 50K 左右,grub 的核心代码,包含了 GURB 的基本运行时的基础设备:设备和文件处理框架、环境变量、救援模式命令行解析器等。kernel.img 很少单独使用,一般会构建到 core.img 中(.text 和 .data 段)
3.2.3 *.mod
# ls /boot/grub2/i386-pc/*.mod | wc -l
257
/boot/grub2/i386-pc/目录下有许多.mod文件,大部分模块会被core.img在运行时自动动态加载,其中小部分被整合到core.img中,比如文件系统xfs.mod等。
3.3 Kernel Stage
以centos 6为例:
一旦内核加载到内存中,它会解压缩initrd镜像(使用zlib压缩成zImage或bzImage格式)并进行挂载。内核使用INITRD镜像创建虚拟根文件系统(VFS)并运行LINUXrc程序。该程序为内核准备真实的文件系统。
即内核使用Initial RAM Disk(initrd)建立一个临时根文件系统,直到安装了真正的文件系统。
内核检查新的硬件并加载任何所需的设备驱动程序。使用initrd镜像中的程序(例如insmod和rmmod)来加载和卸载内核模块。然后,内核按照grub.conf文件中的指定,挂载实际的根文件系统,并卸载initrd镜像,并释放磁盘映像占用的所有内存。
最后,它运行init进程。
初始化进程(init)是由内核启动的第一个进程(初始化进程)。它是所有进程的父进程。init进程的PID(进程ID)始终为1。该进程持续存在直到计算机停机。它负责系统的整个状态。该进程的设置存储在其配置文件/etc/inittab中,它是一个初始化表,定义了系统程序的启动方式。init进程使用/etc/inittab文件中的参数加载其余的系统守护进程。
备注:Centos 6 虚拟文件系统为initrd,呼叫第一个进程init;Centos 7 虚拟文件系统initramfs,呼叫第一个进程systemd。
Centos 6 :
$ cat /proc/1/comm
init
Centos 7:
# cat /etc/centos-release
CentOS Linux release 7.4.1708 (Core)
# cat /proc/1/comm
systemd
# readlink /proc/1/exe
/usr/lib/systemd/systemd
初始化进程会查看/etc/inittab文件来决定系统要引导到哪个Linux运行级别。总共有7个运行级别,编号从0到6。它们分别是:
运行级别0:将系统停止运行。
运行级别1:以单用户模式运行Linux,并提供命令行界面(CLI)。
运行级别2:以多用户模式运行Linux,禁用网络,并提供CLI。
运行级别3:以多用户模式运行Linux,启用网络,并提供CLI。
运行级别4:默认情况下未定义,允许具有必要权限的用户通过编辑"/etc/inittab"文件定义自定义的运行级别。
运行级别5:以多用户模式运行Linux,启用网络,并提供图形用户界面(GUI)和CLI。
运行级别6:重新启动系统。
centos 6 :
$ cat /etc/inittab
# inittab is only used by upstart for the default runlevel.
#
# ADDING OTHER CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# System initialization is started by /etc/init/rcS.conf
#
# Individual runlevels are started by /etc/init/rc.conf
#
# Ctrl-Alt-Delete is handled by /etc/init/control-alt-delete.conf
#
# Terminal gettys are handled by /etc/init/tty.conf and /etc/init/serial.conf,
# with configuration in /etc/sysconfig/init.
#
# For information on how to write upstart event handlers, or how
# upstart works, see init(5), init(8), and initctl(8).
#
# Default runlevel. The runlevels used are:
# 0 - halt (Do NOT set initdefault to this)
# 1 - Single user mode
# 2 - Multiuser, without NFS (The same as 3, if you do not have networking)
# 3 - Full multiuser mode
# 4 - unused
# 5 - X11
# 6 - reboot (Do NOT set initdefault to this)
#
id:5:initdefault:
初始化进程开始执行与所选运行级别相对应的脚本。脚本信息存储在/etc/文件夹中的不同文件夹中:
/etc/rc0.d/ - 包含在运行级别0中运行的启动/停止脚本
/etc/rc1.d/ - 包含在运行级别1中运行的启动/停止脚本
/etc/rc2.d/ - 包含在运行级别2中运行的启动/停止脚本
/etc/rc3.d/ - 包含在运行级别3中运行的启动/停止脚本
/etc/rc4.d/ - 包含在运行级别4中运行的启动/停止脚本
/etc/rc5.d/ - 包含在运行级别5中运行的启动/停止脚本
/etc/rc6.d/ - 包含在运行级别6中运行的启动/停止脚本
一旦初始化进程完成,init进程会运行另一个文件/etc/rc.local,其中包含在初始化进程或引导过程中运行的最后一批命令。一切完成后,控制权交还给内核。
一旦内核获得控制权,它会启动多个"getty"实例,等待控制台登录,然后生成用户的shell进程,并提供用户提示符以进行登录。
centos 7 (systemd 代替 inittab):
# cat /etc/inittab
# inittab is no longer used when using systemd.
#
# ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target
#
# systemd uses 'targets' instead of runlevels. By default, there are two main targets:
#
# multi-user.target: analogous to runlevel 3
# graphical.target: analogous to runlevel 5
#
# To view current default target, run:
# systemctl get-default
#
# To set a default target, run:
# systemctl set-default TARGET.target
#
[root@localhost ~]# cat /etc/inittab
# inittab is no longer used when using systemd.
#
# ADDING CONFIGURATION HERE WILL HAVE NO EFFECT ON YOUR SYSTEM.
#
# Ctrl-Alt-Delete is handled by /usr/lib/systemd/system/ctrl-alt-del.target
#
# systemd uses 'targets' instead of runlevels. By default, there are two main targets:
#
# multi-user.target: analogous to runlevel 3
# graphical.target: analogous to runlevel 5
#
# To view current default target, run:
# systemctl get-default
#
# To set a default target, run:
# systemctl set-default TARGET.target
#
SysVInit 是Linux中经典的初始化进程。初始化进程依赖于各个服务在/etc/init.d目录安装相关脚本。此外,这些脚本必须支持标准的命令,如start(启动)、stop(停止)和status(状态)。这个init系统的主要特点之一是它是一个一次性的启动过程,启动后不再跟踪各个服务。可以使用service命令从终端运行这些init脚本。
SystemD是一个近期的初始化系统,旨在取代SysVInit。事实上,大多数Linux发行版,如Debian和Red Hat,已经将SystemD作为默认的init系统。与SysVInit不同,SystemD在初始化完成后会作为一个守护进程持续运行。此外,它们还通过cgroups来主动跟踪服务。systemctl命令是用户与SystemD进行交互和配置的入口点。
传统的SysVinit进程使用运行级别(如前面讨论中提到的),但Systemd引入了目标(targets)的概念,提供了对系统在引导和运行时行为的更灵活和精细的控制。
参考资料
https://www.linkedin.com/pulse/linux-boot-process-sandeep-sharma-p
https://www.linkedin.com/pulse/linux-boot-procedure-sriram-ramanujam
https://mp.weixin.qq.com/s/N_lSjtorg0Ho_hSBiM5uKA
https://blog.csdn.net/Anhui_Chen/article/details/106988113
https://www.cnblogs.com/chaplain/p/16167738.html
https://www.wxtechblog.com/grub/grub-install