Linux 系统启动流程

概述

Linux 系统启动流程十分复杂,这里仅做一简单说明,以供日后参考之用。

为说明方便,我们作如下限定:磁盘采用 MBR 分区格式、Boot Loader 采用 GRUB2、linux 采用 systemd 启动方式。

Linux 系统启动流程大致可分为如下步骤:

  1. BIOS 硬件自检与选择启动顺序
  2. 读取 MBR 并加载 Boot Loader
  3. 初始化内存盘及加载内核
  4. systemd 系统初始化

详述

按下主机电源后,计算机主板开始上电并初始化相关固件,随后启动 CPU 并开始执行 BIOS 程序。

  1. BIOS 硬件自检与选择启动顺序

    为保证系统能够稳定运行,BIOS 首先检查各硬件的基本功能是否正常 (此过程称为硬件自检,即 POST)。如果某些硬件出现问题,计算机主板会报以不同含义的蜂鸣声;反之,BIOS 程序会输出相关硬件信息至屏幕。

    硬件自检完成后,BIOS 将会执行硬件设备中 MBR 内的程序。由于计算机内部往往存在多个硬件设备,因此需要选择启动哪个硬件设备。默认情况下,BIOS 保存一个默认顺序,当然用户也可自行定义硬件设备的顺序。

  2. 读取 MBR 并加载 Boot Loader

    选定某硬件设备之后,BIOS 会加载 MBR 中的 Boot Loader 至内存,随后 CPU 开始执行其中指令。

    MBR 等概念详见 Linux 磁盘与分区

    这里以 GRUB2 说明 Boot Loader 的工作详情。

    如果你已知晓 MBR 等概念,那么就会知道:MBR 内部仅有 446 个字节用于存放 Boot Loader。由于 Boot Loader 包含较多功能,因此这点空间根本无法容纳其实现代码。

    为容纳其实现代码,GRUB2 这样操作: MBR 内部的 Boot Loader 代码用于定位和加载另外一处位置的代码,而该部分代码为 Boot Loader 的实际实现代码。

    在该实际实现代码所在空间内,其中还会存放一些通用的文件系统驱动程序。借助于这些驱动程序,Boot Loader 可加载 /boot 目录之中的 initrdvmlinuz 文件 (vmlinuz 为 Linux 核心文件)。

    注意:/boot 目录所在的文件系统必须要为 GRUB2 所支持,否则无法存取这两个文件。

  3. 初始化内存盘并加载内核

    在此先行说明加载 initrd 文件的原因。

    为方便开发商和核心功能开发者,Linux 核心允许动态载入核心模块 (它们位于 /lib/modules 目录之下);并且实际之中,USB 等磁盘设备的驱动程序都是作为核心模块存在于 Linux 系统之中的 (如此可大大降低 Linux 核心的大小)。为使用这些核心模块所提供的功能,Linux 核心便需要挂载根目录,并载入核心模块。由于 Linux 核心内部并不存在相关磁盘设备的驱动程序,那么它就无法识别并挂载根目录。为解决这一问题,我们需要求助于 initrd 文件。

    如果 Linux 核心内部包含相关磁盘设备的驱动程序,则其无需使用 initrd 文件。

    initrd 全称为 Initial RAM Disk。当该文件被加载至内存后,它会被解压缩并仿真成为一个小型根目录文件系统,且该系统之中内含与磁盘相关度较高的设备驱动程序。借助于这些驱动程序,便可为 Linux 核心挂载根目录。

    Linux 核心成功挂载根目录后,它会执行一系列任务,包括测试并驱动周边设备、重新侦测硬件、释放小型根目录文件系统等,如此便成功构建硬件环境。

  4. systemd 系统初始化

    构建完成硬件环境后,Linux 核心开始构建软件环境,它会调用第一支程序 systemd,并为其分配 PID = 1。

    根据系统的配置文件,Linux 核心会执行指定的服务集 (见 *.target 文件,这些服务提供 Linux 的基础功能),从而完成软件环境的建立。在此软件环境建立过程中,Linux 核心主要完成如下工作:挂载文件系统及相关的内存交换空间、载入核心模块、载入网络服务、载入图形化界面等。