从按下开机键到Linux系统界面显示,这中间究竟经历了怎样的过程?本文将为您一一揭开Linux启动的神秘面纱,详细剖析每个环节的工作原理,让你从内核出生到系统服务启动,一路见证这个过程的壮阔与精彩。
一、概述
Linux系统的启动过程大致可以分为以下几个阶段:
- 上电自检(POST)
- 基础输入输出系统(BIOS)
- 主引导记录(MBR)和引导加载程序(GRUB)
- 加载内核(Kernel)
- 初始化init进程
- 启动运行级别(Runlevel)
接下来,我们就一起走进每个阶段,深入探索其中的奥秘。
二、上电自检(POST)
上电后,首先是上电自检(Power-On Self-Test,POST)环节,主要工作是检查计算机硬件是否正常。
POST由主板上的BIOS芯片中的指令完成,它会逐一检查系统中的硬件设备,包括CPU、内存、硬盘等。
POST 工作流程如下:
- 当计算机加电时,BIOS 会首先进行加电自检 (POST),检查计算机硬件是否正常工作,例如 CPU、内存、硬盘等。
- 如果硬件检测失败,BIOS 会发出警报或显示错误信息。
- 如果硬件检测成功,BIOS 会继续执行启动过程。
三、基础输入输出系统(BIOS)
BIOS 是英文 Basic Input/Output System 的缩写,中文意思是基本输入输出系统。它是一段固化到计算机主板上的程序, 它负责管理计算机最基本的硬件设备,例如键盘、鼠标、显示器、硬盘等,并引导操作系统,提供系统设置选项,负责管理电源 。
1、BIOS 的功能和作用
-
硬件检测和初始化,确保计算机硬件正常工作
在计算机启动时,BIOS 会检测并初始化所有连接到主板的硬件设备,例如键盘、鼠标、显示器、硬盘等,确保这些设备能够正常工作。
-
引导操作系统
BIOS 会从硬盘或其他启动设备中加载操作系统内核,并将其传递给操作系统进行启动。
-
提供系统设置选项
BIOS 提供一些系统设置选项,例如启动顺序、日期和时间、硬件配置等,方便用户进行系统配置。
-
管理电源
BIOS 可以控制计算机的电源状态,例如开机、关机、休眠等,方便用户进行电源管理。
2、 BIOS 的类型
-
传统 BIOS: 传统 BIOS 是使用 16 位代码编写的,它只支持 16 位 CPU 和 1MB 以下的内存。
-
UEFI BIOS: UEFI BIOS 是使用 32 位或 64 位代码编写的,它支持 32 位或 64 位 CPU 和更大的内存。
3、BIOS 的工作流程
Step1, 加电自检 (POST)过程
BIOS 系统存储于主板的ROM芯片上,计算机在开机时,会最先读取该系统,然后会有一个加电自检过程(按下电源开关后,BIOS检查设备,可以听到“滴”的一声就说明设备正常),这个过程其实就是检查CPU和内存,计算机最基本的组成单元(控制器、运算器和存储器)。
Step2, 加载 MBR
BIOS还有一个主要的功能就是存储了磁盘的启动顺序,BIOS会按照启动顺序去查找第一个磁盘头的MBR信息,并加载和执行MBR中的Bootloader程序,若第一个磁盘不存在MBR,则会继续查找第二个磁盘,一旦BootLoader程序被检测并加载内存中,BIOS就将控制权交接给了BootLoader程序。
四、主引导记录(MBR)和引导加载程序(GRUB)
1、MBR
MBR(Master Boot Record) 是主引导记录,是硬盘的第一个扇区,里面存储着少量启动代码和分区表信息。每个可启动的操作系统都需要在MBR或分区表中留有相应的引导代码。
MBR存储于磁盘的头部(它指的是硬盘的第一个扇区),大小为512bytes。
- Boot Loader ,占用446字节,存储有操作系统(OS)相关信息,如操作系统名称,操作系统内核位置等,它的主要功能是加载内核到内存中运行。
- Partition Table 分区表,占用64字节,每个主分区占用16字节(这就是为啥一块硬盘只能有4个主分区)
- 分区表有效性标记占用2字节 (“55,AA”是分区表结束的标志)
对于Linux系统,MBR中的代码将会加载并运行GRUB(GRand Unified Bootloader)引导加载程序。GRUB提供了一个菜单,可以选择要启动的操作系统或内核版本。选择后,它会加载指定的内核映像到内存。
可以查阅GRUB的源码了解其工作原理:
// grub-core/kern/main.c
int main()
{/* 初始化GRUB环境 */grub_init_all();/* 显示GRUB菜单 */grub_menu_show_entry_sequence();/* 选择内核映像并加载到内存 */grub_linux_boot();
}
2、Boot Loader
Boot Loader,中文翻译为引导加载程序,是计算机启动过程中必不可少的程序,它很小但非常重要,负责将操作系统内核加载到内存中,并启动操作系统。
(1)、 Boot Loader 的功能
-
加载操作系统内核到内存中
-
启动操作系统
-
提供一些系统设置选项
-
管理启动过程
(2)、Boot Loader 的类型
-
主引导记录 (MBR): MBR 是存储在硬盘第一个扇区上的引导程序,它负责加载第一个操作系统的引导扇区。
-
引导扇区: 引导扇区是存储在每个分区上的引导程序,它负责加载操作系统的内核。
-
GRUB: GRUB 是一个通用的引导加载程序,它支持多种操作系统,例如 Linux、Windows、FreeBSD 等。
-
LILO: LILO 是另一个通用的引导加载程序,它主要用于 Linux 操作系统。
(3)、Boot Loader 的工作流程
-
当计算机加电时,BIOS 会首先读取硬盘第一个扇区上的 MBR。
-
MBR 会加载第一个操作系统的引导扇区到内存中。
-
引导扇区会加载操作系统的内核到内存中。
-
操作系统内核会启动操作系统。
3、GRUB
GRUB (GRand Unified Bootloader) 是一个通用的引导加载程序,它支持多种操作系统,例如 Linux、Windows、FreeBSD 等。 GRUB 是目前最流行的引导加载程序之一,它被广泛应用于各种 Linux 发行版中。
(1)、GRUB 的功能
-
加载操作系统内核到内存中
-
启动操作系统
-
提供一些系统设置选项
-
管理启动过程
-
支持多种操作系统
-
支持多种文件系统
-
支持多种硬件平台
(2)、GRUB 的工作流程
-
当计算机加电时,BIOS 会首先读取硬盘第一个扇区上的 MBR。
-
MBR 会加载 GRUB 的第一个阶段到内存中。
-
GRUB 的第一个阶段会加载 GRUB 的第二个阶段到内存中。
-
GRUB 的第二个阶段会显示启动菜单,允许用户选择要启动的操作系统。
-
用户选择要启动的操作系统后,GRUB 会加载该操作系统的内核到内存中。
-
操作系统内核会启动操作系统。
(3)、GRUB 的配置
GRUB 的配置可以通过编辑配置文件进行。配置文件通常位于 /boot/grub/grub.cfg 文件中。
grub.conf:#boot=/dev/sda default=0 #设定默认启动的title的编号,从0开始 timeout=5 #等待用户选择的超时时间 splashimage=(hd0,0)/boot/grub/splash.xpm.gz #GRUB的背景图片 hiddenmenu #隐藏菜单 title CentOS (2.6.18-194.el5PAE) #内核标题 root (hd0,0) #内核文件所在的设备 kernel /vmlinuz-2.6.18-194.el5PAE ro root=LABEL=/ #内核文件路径以及传递给内核的参数 initrd /initrd-2.6.18-194.el5PAE.img #ramdisk文件路径
在/boot/grub/grub.conf中可以看到:
-
root (hd0,0) 这一行实际上是指定了/目录的所在的位置,但这个根并不是真正的根,而是/所在的位置,可以理解成/boot是处在(hd0,0)/boot,而这里的(hd0,0)指的是第一个磁盘的第一个分区。
-
GRUB不是通过文件系统来访问内核的,因为此时内核还没有启动,不存在文件系统,而是直接访问 第一个磁盘的第一个分区(通过MBR中的分区表来识别分区),而识别MBR中的分区的文件系统,则是由GRUB通过加载自身携带的系统文件来实现的,这些文件在/boot/grub目录中。
五、加载内核(Kernel)
内核是操作系统中最核心的部分,它负责管理计算机的硬件资源,为上层应用程序提供支持和服务。
在Linux系统中,内核是压缩后的vmlinuz文件,GRUB会将其加载并解压到内存中。内核启动后,会进行一系列的初始化操作,如探测硬件资源、设置终端、挂载根文件系统等。
// linux-x.x.x/init/main.c
int __init start_kernel()
{/* 初始化各种子系统,如体系结构、内存管理、调度器等 */setup_arch(&command_line);setup_memory();scheduler_init();....../* 挂载根文件系统 */prepare_namespace();/* 启动init程序 */kernel_thread(kernel_init, NULL, CLONE_FS);return 0;
}
Kernel 内核是 Linux 操作系统最主要的程序,它负责管理系统资源和运行应用程序。 内核是操作系统的心脏,它控制着所有硬件和软件的交互。
(1)、 Kernel的功能
-
进程管理: 内核负责创建、调度和终止进程。
-
内存管理: 内核负责分配和管理内存。
-
文件系统管理: 内核负责管理文件系统,例如创建、删除和访问文件。
-
设备驱动程序: 内核负责管理设备驱动程序,以便操作系统能够使用硬件设备。
-
网络管理: 内核负责管理网络连接,例如发送和接收数据包。
-
安全: 内核负责保护系统免受安全威胁,例如病毒和黑客攻击。
(2)、 Kernel的结构
Linux 内核是一个单内核系统,这意味着它只有一个内核。
内核由以下几个主要部分组成:
- 内核核心: 内核核心是内核最核心的部分,它负责管理系统资源和运行应用程序。
- 设备驱动程序: 设备驱动程序负责管理硬件设备,以便操作系统能够使用硬件设备。
- 文件系统: 文件系统负责管理文件,例如创建、删除和访问文件。
- 网络协议栈: 网络协议栈负责管理网络连接,例如发送和接收数据包。
(3)、 Kernel工作流程
-
Kernel的文件很小,只保留了最基本的模块,并以压缩的文件形式存储在硬盘中,当GRUB将Kernel读进内存,内存开始解压缩内核文件。
-
内核启动,在stage2这个步骤时,就将initrd(Initial RAM Disk) 文件拷贝到了内存中,这个文件是在安装系统时产生的,是一个临时的根文件系统(rootfs)。 initrd这个文件,装载了必要的驱动模块,当Kernel启动时,可以从initrd文件中装载驱动模块,直到挂载真正的rootfs,然后将initrd从内存中移除。
-
Kernel会以只读方式挂载根文件系统,当根文件系统被挂载后,开始装载第一个进程(用户空间的进程),执行/sbin/init,之后就将控制权交接给了init程序。
六、初始化init进程
内核启动后,会执行/sbin/init程序,该程序是所有其他进程的祖先进程。
Init 是 Linux 系统中最古老的进程,它的 PID 始终为 1。
Init进程会根据运行级别(runlevel)来决定启动哪些程序。
在大多数Linux发行版中,init程序是systemd,负责启动和管理整个系统。你可以在源码systemd/src/core/main.c中看到它的入口:
// systemd/src/core/main.c
int main() {....../* 初始化systemd管理器 */ r = manager_init();....../* 启动监控循环,运行系统服务 */r = manager_run(m);......
}
内核并加载进内存运行并以读写方式挂载完根文件系统后,执行第一个用户进程init,init首先运行/etc/init/rcS.conf脚本,如下图:
上图可以看到,init进程通过执行/etc/rc.d/rcS.conf首先调用了/etc/rc.d/rc.sysinit,对系统做初始化设置,这是真正的OS初始化脚本。
事实上init执行/etc/rc.d/rc.sysinit的初始化将会做很多设置:
1、获得网络环境
2、挂载设备
3、开机启动画面Plymouth(取替了过往的 RHGB)
4、判断是否启用SELinux
5、显示于开机过程中的欢迎画面
6、初始化硬件
7、用户自定义模块的加载
8、配置内核的参数
9、设置主机名
10、同步存储器
11、设备映射器及相关的初始化
12、初始化软件磁盘阵列(RAID)
13、初始化 LVM 的文件系统功能
14、检验磁盘文件系统(fsck)
15、设置磁盘配额(quota)
16、重新以可读写模式挂载系统磁盘
17、更新quota(非必要)
18、启动系统虚拟随机数生成器
19、配置机器(非必要)
20、清除开机过程当中的临时文件
21、创建ICE目录
22、启动交换分区(swap)
23、将开机信息写入/var/log/dmesg文件中
init执行完/etc/rc.d/rc.sysinit后,将会执行/etc/inittab来设定系统运行的默认级别:
七、启动运行级别(Runlevel)
Runlevel 是 Linux 系统中的一种概念,它表示系统的运行级别。
每个运行级别都定义了一组特定的系统服务和应用程序。
例如,运行级别 0 表示关机状态,运行级别 1 表示单用户模式,运行级别 2 表示多用户模式,运行级别 3 表示图形界面模式,运行级别 5 表示图形界面模式并启动 X Window System。
(1)、 Runlevel 的类型
-
运行级别 0: 关机状态
-
运行级别 1: 单用户模式
-
运行级别 2: 多用户模式,没有图形界面
-
运行级别 3: 多用户模式,有图形界面
-
运行级别 4: 未使用
-
运行级别 5: 多用户模式,有图形界面并启动 X Window System
-
运行级别 6: 重启
(2)、Runlevel 的配置
Runlevel 的配置通常位于 /etc/inittab 文件中。 在 /etc/inittab 文件中,可以使用 id 字段指定默认的运行级别。 例如,以下代码指定默认运行级别为 3:
id:3:initdefault:
(3)、Runlevel 的切换
可以使用 init
命令切换运行级别。 例如,以下命令将系统切换到运行级别 1:
init 1
(4)、Runlevel 的作用
Runlevel 用于控制系统的运行状态。 例如,可以在系统启动时指定默认的运行级别,或者在需要进行系统维护时切换到单用户模式。
在systemd中,运行级别的概念已被target取代,通过target可以灵活地启动任意的程序。
八、总结
通过上述分析,我们从整体上把握了Linux系统启动的全过程。每个环节都扮演着至关重要的角色,缺一不可。Linux启动之所以如此复杂,是为了保证系统的稳定性和高效性。如果你有独特的见解和想法,欢迎在评论区与我分享交流。