Linux 内核启动过程中两个先有鸡还是先有蛋的地方

前言

在 Linux 的启动过程中,有一些比较奇怪的地方,它们有些让人摸不着头脑因为看起来自相矛盾。例如,内核没有启动之前 Bootloader 怎么读取到储存在磁盘上的内核的?内核启动会载入模块,但是磁盘驱动模块本身又储存在磁盘上,内核又是怎么载入到模块的呢?

揭秘

第一个问题,引导程序要读取相关配置,根据相关配置载入内核。例如 GRUB 会读取 /boot/grub 目录下的配置文件,根据配置文件载入同样储存在磁盘上的内核相关文件。
但是问题来了,内核还没有启动连文件系统都没有加载,引导程序该往哪儿读取内容?毕竟我们一般认为文件系统挂载需要启动内核,但是内核又需要引导启动… 所以这难道不是先有鸡还是先有蛋的问题?

答案其实很简单,秘密就在 GRUB 上。我们查阅资料以后发现,GRUB 不仅仅只是个简单的引导程序,甚至可以称作微型的引导“系统”,非常的强大。 列举一下看起来不像是引导程序该有的功能:

  1. 自带命令行环境
  2. 实现了很多仿 *nix 系统上的终端工具,甚至可以进行配置文件编辑、查看分区细节/修改分区设置等操作
  3. 支持非常多的文件系统,其中包括大部分的 Unix 文件系统 还有例如 FAT 以及 Windows 上的 NTFS 等
  4. 可以从网络下载操作系统,支持无盘启动系统
  5. 支持图形,可以做到用户界面的定制
  6. 等等

上面已经划重点… 秘密就在于 GRUB 或者说引导程序自身就能挂载文件系统,并不是也不需要内核参与。也就是说,第一个问题的答案是:文件系统的挂载跟内核是否启动毫无关系,故不存在矛盾。

第二个问题,重述一遍就是:GRUB 载入的内核核心并不包含模块,单纯启动它无法实现对文件系统的挂载,那么它又是如何从磁盘上载入模块的呢?
原来 GRUB 载入的文件并不那么“单纯”,在 /boot 目录会有 vmlinuz 开头的文件(可能有多个),它就是被引导所载入的文件之一,它是内核本身。这个文件是一个包含自解压功能的压缩文件(听起来有些绕口),简单来说就是其文件组成是前一部分字节包含解压程序,后面才是具体压缩数据。同时引导还有将 initrd.img 文件载入内存,而重点就是这个 initrd 。
当内核启动以后会解压并挂载 initrd 中的文件系统,并进行初始化操作。期间包括载入必要驱动,而这个驱动就是磁盘的驱动。至于载入驱动的过程和驱动内容都是 initrd 压缩镜像所包含,并由内核挂载到基于内存的文件系统上进行读取。所以可以将 initrd 过程看做内核正式初始化系统前的准备工作。
当工作做完,内核已经包含储存设备的驱动,便可以挂载真正的根文件系统并载入众多模块,以及进行后续的 init 过程完成操作系统的启动。所以 initrd 的作用是让内核载入磁盘驱动,目的是另内核在不必要包含多余内容的情况下还能挂载根文件系统并完成对模块的载入。
这个过程又称作两段式启动,第一个阶段是为第二个阶段做准备,第二个阶段则是真正的系统启动过程。而这一切的源头是内核和模块分离造成的,毕竟驱动在 Linux 平台和 Windows 的存在形式截然不同,又不像 Apple 一样固定硬件,所以以模块的形式存在和载入是更适合的方式。

最后

关于本文的内容是我在上网时看到有人在讨论,并且提出了相关疑问。对于了解不深入的人而言,其疑问还听起来比较有理有据,所以才觉得有点意思。虽然实际上疑问内容的前提本身就是错误的。但是其原理无不充斥着前人伟大的“智慧”。