Linux的开机过程
2024-03-29 15:11:40 # 技术

Linux 的开机过程

Linux 操作系统的开机过程可以分为以下几个主要阶段:

上电自检(Power on Self Test,POST)

Linux 的 POST 自检并不是 Linux 本身的功能,而是计算机硬件启动流程的一个早期步骤,与具体的操作系统无关。POST 自检是由计算机主板上的固件负责执行的,这个固件可能是基本上输入输出系统(Basic Input Output System,BIOS)。
当计算机接通电源后,POST 自检是开机启动的第一个环节,它会立即自动运行,对计算机的硬件设备进行一系列基本的测试和初始化,确保它们能够正常工作。POST 自检的内容包括但不限于以下几个方面:

  • 检测 CPU 和其他核心硬件组件的存在和功能完整性;
  • 测试内存的基本可用性;
  • 初始化并检测系统总线和 I/O 设备;
  • CMOS 中系统配置的校验;
  • 检测和初始化显卡以便显示基本的视频输出;
  • 检查和初始化其他关键硬件,如键盘、磁盘驱动器等;

只有当 POST 自检成功完成,表明硬件层面没有致命错误时,计算机才会继续启动流程,寻找并加载操作系统引导程序,进而启动 Linux 内核或其他操作系统。如果 POST 过程中发现任何错误,系统通常会通过声音提示(蜂鸣声)、屏幕显示错误代码或信息来告知用户存在问题。

BIOS/UEFI 引导阶段

BIOS(Basic Input/Output System,基本输入输出系统)和 UEFI(Unified Extensible Firmware Interface,统一的可扩展固件接口)都是计算机启动过程中用于初始化硬件并加载操作系统的固件接口,负责查找并加载启动设备上的引导加载程序
两者之间存在的差异如下所示:

  • 架构和编程模型:
    • BIOS:基于16位实模式下的代码,受限于1MB地址空间,功能有限。
    • UEFI:基于 32 位或 64 位的保护模式,拥有更大的寻址能力,支持复杂的现代编程模型,可以使用高级编程语言开发应用程序。
  • 启动过程与分区表:
    • BIOS:使用传统的Master Boot Record (MBR) 分区方案,启动过程较为单一和线性。
    • UEFI:支持 GUID Partition Table (GPT),可直接识别和加载包含 EFI 引导程序的分区,启动过程更为灵活高效。
  • 安全特性:
    • BIOS:安全性相对较低,不支持安全启动机制。
    • UEFI:包含安全启动 (Secure Boot) 特性,能够验证操作系统的完整性,防止恶意软件篡改启动过程。
  • 硬件兼容性和性能:
    • BIOS:对新硬件的支持有限,启动速度相对较慢。
    • UEFI:支持更多现代硬件特性,如快速启动、大容量硬盘、ACPI 高级配置与电源接口规范等,从而提高启动速度和整体性能。
  • 图形用户界面与扩展性:
    • BIOS:通常提供简单的文本界面,配置选项有限,扩展性差。
    • UEFI:具备丰富的图形用户界面(GUI),提供更多可配置选项,且允许通过安装 UEFI 驱动程序来支持更多硬件,具有良好的扩展性。
  • 启动加载程序:
    • BIOS:使用传统的引导扇区加载操作系统。
    • UEFI:使用预启动执行环境(Pre-boot Execution Environment, PE)加载 UEFI 引导应用,它可以访问更广泛的资源,并直接从磁盘加载操作系统镜像。
  • 分区限制:
    • BIOS:受限于MBR分区表的设计,只支持最大2TB的硬盘分区。
    • UEFI:由于使用 GPT 分区表,理论上支持高达 9.4ZB 的分区大小。

Boot Loader 阶段(引导加载程序阶段)

引导加载程序,通常称为 Boot loader,是 Linux 操作系统启动的关键组成部分。它的主要作用是在计算机启动时加载操作系统内核,并将控制权移交给内核,从而启动操作系统。Boot loader 还负责检测和初始化硬件设备,为操作系统提供必要的信息和参数。
在 Linux 中,有几种常见的引导加载程序,其中最流行的是 GRUB(GRand Unified Bootloader)和 LILO(LInux LOader)。GRUB 具有广泛的支持和灵活性,它能够引导多个操作系统,并提供了一个命令行界面用于配置引导选项。LILO 是一种较早的引导加载程序,它的配置相对简单,但不如 GRUB 灵活。
当 BIOS/UEFI 确定了引导设备后,它会将控制权交给 Boot Loader,Boot Loader 开始启动。
第一阶段引导加载:对于 GRUB(GRand Unified Bootloader)这样的多阶段引导加载程序,在 BIOS 环境中,第一阶段引导加载程序位于 MBR 或某个活动分区的引导扇区,其体积受到限制,主要任务是定位和加载第二阶段引导程序。在 UEFI 环境下,第一阶段即引导程序本身,通常无需额外的小型装载程序。
第二阶段引导加载:第二阶段引导加载程序提供了更多的功能和灵活性,如加载额外模块、支持文件系统、显示菜单等。在 GRUB 中,这一阶段可能加载“stage1.5”(在 MBR 后的自由扇区,仅限特定情况),或者直接加载完整的第二阶段代码到内存中。第二阶段引导加载程序会显示一个启动菜单,允许用户选择不同的内核版本、调整内核启动参数。

内核加载阶段

引导加载程序根据用户选择或预设配置,从硬盘加载 Linux 内核映像(通常为 /boot/vmlinuz-<version>)到内存,并传递内核启动参数。此外,还会加载一个 initramfs 或 initrd(初始化 RAM 磁盘),这是一个压缩的临时根文件系统,包含启动系统所需的基本驱动和工具。
内核加载成功后,引导加载程序将控制权交给内核。

内核初始化阶段

初始化阶段负责初始化硬件设备、建立内存管理、设置终端处理程序等,该阶段确保系统硬件设备得到正确初始化,建立一个稳定的环境,以便用户空间程序能够正常运行。该阶段的详细工作如下所示:

  1. 硬件检测与初始化
    • 内核初始化阶段首先进行硬件检测与初始化。这包括识别和初始化 CPU、内存、硬盘、显卡、网卡等硬件设备。
    • 内核通过与硬件交互的方式,获取硬件信息并配置硬件设备,以确保它们可以正确地被系统使用。
  2. 内存管理初始化
    • 在内核初始化阶段,内核会建立起系统的内存管理机制。
    • 这包括建立页面表、设置内核堆栈、初始化内存分配器等操作。
    • 内核需要确保内存的正确管理,以便用户空间程序能够正常运行,并且避免内存泄漏等问题。
  3. 文件系统初始化
    • 内核初始化阶段还涉及到文件系统的初始化。
    • 内核会初始化虚拟文件系统(VFS),为不同的文件系统提供抽象接口。
    • 内核还会加载根文件系统,这是系统启动时所需的最基本的文件系统,通常是一个轻量级的根文件系统,用于引导系统。
  4. 设备驱动程序加载
    • 内核初始化阶段会加载并初始化系统中的设备驱动程序。
    • 设备驱动程序负责与硬件设备进行通信,并为用户空间提供访问硬件设备的接口。
    • 内核会加载与系统硬件匹配的设备驱动程序,并将其注册到内核中。
  5. 中断处理程序设置
    • 内核初始化阶段还涉及到中断处理程序的设置。
    • 中断是硬件设备与 CPU 之间的一种异步通信机制,用于处理硬件事件。
    • 内核会设置中断处理程序,以便在发生硬件中断时能够正确地处理中断并采取相应的措施。
  6. 启动完成
    • 当内核初始化阶段完成后,系统已经处于一个可以运行用户空间程序的状态。
    • 内核将控制权交给用户空间的第一个进程,通常是 init 或 systemd 进程,然后系统进入用户空间初始化阶段。

      用户空间初始化阶段

      内核初始化阶段完成后,系统已经处于一个可以运行用户空间程序的状态,此时会启动初始化进程,业绩用户空间的第一个进程。初始化进程作为 Linux 系统的第一个进程,它需要完成 Linux 系统中的相关初始化工作,为用户提供合适的工作环境。
      初始化进程在 Linux 系统中经历了从传统的 System V init 到现代的 systemd 的演变。

对于传统 System V init:

  • init 进程生成:当 Linux 内核完成初始化后,它会启动第一个用户空间进程,PID 为 1 的 init 进程。init 进程通常由内核直接执行预先放置在根文件系统中的 init 程序。
  • 运行级别设定:在 System V init 时代,Linux 系统有多个运行级别(run levels),例如运行级别 1 代表单用户模式,3 代表多用户模式无网络服务,5 代表多用户模式带图形界面等。init 进程根据配置文件 /etc/inittab 确定运行级别,并依据此级别启动对应的服务和脚本。
  • 启动脚本执行:init 会读取 /etc/rc?.d 目录下的启动脚本来启动对应运行级别的服务。每个服务都有对应的启动(S 开头的脚本)和停止(K 开头的脚本)脚本,按照字母顺序依次执行
  • 服务管理工具:System V init 使用 service 命令来管理服务,它使用 /etc/init.d/ 目录下的脚本来启动、停止、重启或查询服务状态。service 命令提供了一个简单的接口来操作服务,如 service serviceName startservice serviceName stop 等。

对于 systemd:

  • systemd 启动:在现代 Linux 发行版中,大部分已经替换为 systemd 作为初始化系统。内核仍然启动 PID 为 1 的进程,但现在这个进程是 systemd。systemd 的设计更加模块化和灵活,采用了目标(targets)的概念来替代运行级别。
  • units 和 targets:systemd 的核心概念是 units,包括 service units(服务)、socket units(套接字)、mount units(挂载点)等。初始化过程中,systemd 根据预设的默认 target(如 multi-user. target 或 graphical. target)启动一组关联的 units。
  • 启动过程:systemd 在启动时,首先激活默认 target,这涉及到一系列 unit 的依赖解析和启动。依赖关系被定义在各个 unit 文件中,systemd 按照依赖图谱有序地启动服务和执行一次性任务(如执行 systemd 执行单元类型 oneshot 的脚本)。
  • 并行启动:systemd 的一大优势在于能并行启动多个服务,通过分析依赖关系,它可以在不影响服务启动顺序的前提下加快系统启动速度。
  • 日志和状态报告:systemd 集成了 journalctl 日志服务,可以实时查看和管理启动过程中的日志信息,便于调试和监控。
  • 服务管理工具:现代 Linux 系统使用 systemctl 服务管理工具,systemctl 命令提供了更强大和灵活的服务管理功能,它可以控制单个服务、管理启动目标、查看系统日志等,与 service 不同,systemctl 不仅仅是一个命令,而是一个系统和服务管理的集合,它可以管理更多方面的系统功能。

总结起来,无论是传统的System V init还是现代的systemd,Linux系统的初始化进程均负责系统启动后的基础设施搭建,包括但不限于启动核心服务、配置网络、设置权限、加载驱动等,为用户提供一个可用的操作系统环境。同时,systemd以其高度集成化和优化的启动逻辑显著改善了系统启动时间和管理效率。