说明

这里只讨论 x86 架构。

Before the kernel

MBR and BIOS

传统的操作系统都是通过 MBR 分区格式和 BIOS 来启动。简单来讲:

  1. 当计算机系统上电开机或者按了机箱上的复位按钮;此时 80x86 结构的 CPU 将自动进入实模式。
  2. CPU会自动把代码段寄存器 CS设置为0xF000,其段基地址则被设置为 0xFFFF0000,段长度设置为 64KB。而 IP 被设置为 0xFFF0,因此此时 CPU 代码指针指向 0xFFFFFFF0 处,即 4G 空间最后一个 64K 的最后 16 字节处;
  3. 这里正是系统 ROM BIOS 存放的位置。并且 BIOS 会在这里存放一条跳转指令 JMP 跳转到 BIOS 代码中 64KB 范围内的某一条指令开始执行。这部分官方内容可以在 Intel 手册的 11.1.1 章节看到:

image-20241124181640140

而其设计缘由,可追溯到 1981 年 IBM PC 机。这部分内容可参考赵炯老师的《Liunx 内核完全注释》第五版 2.3.1 章节。

  1. 所以 BIOS 是硬件到软件的桥梁,是 CPU 执行的第一条指令。BIOS 包括开机后自检程序和系统自启动程序,它可从CMOS中读写系统设置的具体信息。 其主要功能是为计算机提供最底层的、最直接的硬件设置和控制。
  2. BIOS 程序会在物理地址 0 处开始设置和初始化中断向量,然后 BIOS 直接读取磁盘上的第一个扇区(512 字节)也就是 MBR (主引导记录),加载到内存的 0x7c00 地址。然后 BIOS 就会跳到 0x7c00 这个地址,然后继续执行。BIOS 的使命结束,CPU 执行权将交给操作系统。
  3. 那么 MBR 主引导扇区放的是什么代码呢?在这里,Linux 会有一段汇编代码在这个地方,用于启动内核。后面就是初始化内核、初始化并切换到保护模式、等等。

GPT and UEFI

现在基本上用 GPT 磁盘和 UEFI 启动方式,是目前和未来增量的主流。这个过程不详细讲了,写得有点慢了,找了一篇讲得比较规范的文章可以参考:https://medium.com/@adilrk/booting-with-uefi-unified-extensible-firmware-interface-c719929b253c

官方规范可访问 UEFI 组织手册:https://uefi.org/specs/UEFI/2.10_A/02_Overview.html

Part of Liunx Boot

读完上面的内容,读者可能感觉硬件初始化后直接就启动 Liunx 了。这种启动方式就是直接加载引导程序(boot program),但实际上现在基本上都是先启动一个叫 grub 的东西,然后 grub 再去启动内核。这是一个 GNU 的项目,可以去官网查看:https://www.gnu.org/software/grub/index.html

这种启动方式就是加载引导加载程序(bootloader)。linux 基本都用 grub,但是 windows 有自己的bootloader叫做EFI bootloader,你自己装 windows 然后去 efi 分区看下 efi 引导就知道了。

Boot Process on GRUB2

简单来讲:

  1. GRUB2 根据预先的配置(或者是进入 GRUB 后,用户可以选择),加载对应的内核。这一步 GRUB 有一个自己的命令提示符,但是现在很多系统基本上会配置一个图形化的 GRUB 启动界面,例如 Kalilinux;GRUB 可以设置一些内核参数啥的,用于传递给内核。
  2. 内核文件、initial ram disk image、设备映射、硬盘设备等文件,都在文件系统的/boot目录里。读者可以自己查看一下自己电脑的该目录中有什么内容。
  3. 内核完成硬件初始化、挂载根文件系统等操作后,将启动第一个用户空间程序。
  4. 内核将控制权交给 init(PID 为 1) 或其替代品(现在用的最多的就是systemd)。通常,这个程序路径是 /sbin/init 或由内核启动参数 init= 指定。你可以输入ps -p 1看下自己用的哪一种。
    1. 如果是 systemd,那么它会启动一系列服务。一般我们通过systemctl status xxx来查看这些服务,相信这个命令你也很熟悉。
    2. systemd 的配置文件在/etc/systemd目录下。那systemd具体要怎么启动 Linux 启动后要启动的一系列程序呢,我们可以看/etc/systemd/system/default.target这个文件链接到啥文件上,也可以用systemctl get-default命令查看。这个就是 systemd 的默认目标
    3. 如果默认目标是graphical.target,那么就是常见的启动一个图形化系统。systemd 就是通过目标服务的启动顺序依赖关系,这样的一套机制来管理的。比如查看 graphical.target 的依赖:systemctl show graphical.target --property=Wants
    4. 如果你通过sudo systemctl set-default multi-user.target命令,将目标设置成multi-user.target,那 systemd 启动后就不会启动graphical.target的相关依赖,而是直接进入命令行界面。
    5. 同样的,最权威的资料,永远来自于官方的文档:https://systemd.io/

其他

https://www.golinuxhub.com/2017/12/step-by-step-linux-boot-process-with/

https://medium.com/@gangulysutapa96/6-stages-of-linux-boot-process-5ee84265d8a0

⬆︎TOP