Linux 启动和启动过程简介

有没有想过让你的系统准备好运行应用程序需要什么? 这就是幕后发生的事情。
740 位读者喜欢这篇文章。
The boot process

Penguin, Boot。 由 Opensource.com 修改。 CC BY-SA 4.0。

理解 Linux 启动和启动过程对于配置 Linux 和解决启动问题至关重要。 本文概述了使用 GRUB2 引导加载程序 的启动顺序以及由 systemd 初始化系统 执行的启动顺序。

实际上,启动 Linux 计算机并使其可用的过程需要两个事件序列:启动启动启动序列在计算机开机时开始,并在内核初始化和 systemd 启动时完成。 然后,启动过程接管并完成使 Linux 计算机进入可操作状态的任务。

总的来说,Linux 启动和启动过程相当容易理解。 它由以下步骤组成,将在以下部分中更详细地描述。

  • BIOS POST
  • 引导加载程序 (GRUB2)
  • 内核初始化
  • 启动 systemd,所有进程的父进程。

请注意,本文涵盖了 GRUB2 和 systemd,因为它们是大多数主要发行版的当前引导加载程序和初始化软件。 历史上使用过其他软件选项,并且仍然在某些发行版中找到。

启动过程

启动过程可以通过几种方式启动。 首先,如果电源已关闭,则打开电源将开始启动过程。 如果计算机已经在运行本地用户(包括 root 用户或非特权用户),则用户可以使用 GUI 或命令行启动重启来以编程方式启动启动序列。 重启将首先执行关机,然后重启计算机。

BIOS POST

Linux 启动过程的第一步实际上与 Linux 没有任何关系。 这是启动过程的硬件部分,对于任何操作系统都是相同的。 首次向计算机供电时,它会运行 POST(加电自检),这是 BIOS(基本 I/O 系统)的一部分。

当 IBM 在 1981 年设计第一台 PC 时,BIOS 被设计为初始化硬件组件。 POST 是 BIOS 的一部分,其任务是确保计算机硬件功能正常。 如果 POST 失败,计算机可能无法使用,因此启动过程不会继续。

BIOS POST 检查硬件的基本可操作性,然后发出 BIOS 中断,INT 13H,它在任何连接的可启动设备上定位引导扇区。 它找到的第一个包含有效引导记录的引导扇区被加载到 RAM 中,然后控制权转移到从引导扇区加载的代码。

引导扇区实际上是引导加载程序的第一阶段。 大多数 Linux 发行版使用三个引导加载程序:GRUB、GRUB2 和 LILO。 GRUB2 是最新的,现在比其他旧选项使用得更频繁。

GRUB2

GRUB2 代表“GRand Unified Bootloader, version 2”(大统一引导加载程序,版本 2),它现在是大多数当前 Linux 发行版的主要引导加载程序。 GRUB2 是使计算机足够智能以找到操作系统内核并将其加载到内存中的程序。 因为 GRUB 比 GRUB2 更容易编写和说,所以我可能会在本文档中使用术语 GRUB,但我将指 GRUB2,除非另有说明。

GRUB 被设计为与 多重引导规范 兼容,这允许 GRUB 启动多个版本的 Linux 和其他自由操作系统; 它还可以链式加载专有操作系统的引导记录。

GRUB 还允许用户选择从任何给定 Linux 发行版的几个不同内核中启动。 如果更新后的内核以某种方式失败或与重要的软件不兼容,这提供了启动到以前的内核版本的能力。 可以使用 /boot/grub/grub.conf 文件配置 GRUB。

GRUB1 现在被认为是遗留的,并且在大多数现代发行版中已被 GRUB2 取代,GRUB2 是 GRUB1 的重写版本。 基于 Red Hat 的发行版在 Fedora 15 和 CentOS/RHEL 7 左右升级到 GRUB2。 GRUB2 提供与 GRUB1 相同的引导功能,但 GRUB2 也是一个类似大型机的基于命令的预操作系统环境,并且在预引导阶段允许更大的灵活性。 GRUB2 使用 /boot/grub2/grub.cfg 进行配置。

GRUB 的主要功能是将 Linux 内核加载到内存中并运行。 两个版本的 GRUB 的工作方式基本相同,并且具有相同的三个阶段,但我将使用 GRUB2 来讨论 GRUB 如何完成其工作。 GRUB 或 GRUB2 的配置以及 GRUB2 命令的使用不在本文的范围之内。

虽然 GRUB2 没有正式使用阶段表示法来表示 GRUB2 的三个阶段,但以这种方式引用它们很方便,因此我将在本文中使用。

阶段 1

如 BIOS POST 部分所述,在 POST 结束时,BIOS 会搜索连接的磁盘以查找引导记录,通常位于主引导记录 (MBR) 中,它将找到的第一个引导记录加载到内存中,然后开始执行引导记录。 引导代码,即 GRUB2 阶段 1,非常小,因为它必须与分区表一起放入硬盘驱动器上的第一个 512 字节扇区中。 经典通用 MBR 中为实际引导代码分配的总空间为 446 字节。 阶段 1 的 446 字节文件名为 boot.img,不包含单独添加到引导记录的分区表。

由于引导记录必须非常小,因此它也不是很智能,并且不了解文件系统结构。 因此,阶段 1 的唯一目的是定位和加载阶段 1.5。 为了实现这一点,GRUB 的阶段 1.5 必须位于引导记录本身和驱动器上第一个分区之间的空间中。 将 GRUB 阶段 1.5 加载到 RAM 后,阶段 1 将控制权交给阶段 1.5。

阶段 1.5

如上所述,GRUB 的阶段 1.5 必须位于引导记录本身和磁盘驱动器上第一个分区之间的空间中。 历史上,由于技术原因,此空间一直未使用。 硬盘驱动器上的第一个分区从扇区 63 开始,MBR 在扇区 0 中,这留下了 62 个 512 字节的扇区(31,744 字节)来存储 core.img 文件,它是 GRUB 的阶段 1.5。 core.img 文件为 25,389 字节,因此 MBR 和第一个磁盘分区之间有足够的空间来存储它。

由于阶段 1.5 可以容纳更多代码,因此它可以有足够的代码来包含一些常见的文件系统驱动程序,例如标准 EXT 和其他 Linux 文件系统、FAT 和 NTFS。 GRUB2 core.img 比旧的 GRUB1 阶段 1.5 复杂得多且功能更强大。 这意味着 GRUB2 的阶段 2 可以位于标准 EXT 文件系统上,但不能位于逻辑卷上。 因此,阶段 2 文件的标准位置在 /boot 文件系统中,特别是 /boot/grub2。

请注意,/boot 目录必须位于 GRUB 支持的文件系统上。 并非所有文件系统都支持。 阶段 1.5 的功能是开始执行文件系统驱动程序,这些驱动程序对于定位 /boot 文件系统中的阶段 2 文件并加载所需的驱动程序是必需的。

阶段 2

GRUB 阶段 2 的所有文件都位于 /boot/grub2 目录和几个子目录中。 GRUB2 没有像阶段 1 和 2 这样的映像文件。 相反,它主要由运行时内核模块组成,这些模块根据需要从 /boot/grub2/i386-pc 目录加载。

GRUB2 阶段 2 的功能是定位 Linux 内核并将其加载到 RAM 中,并将计算机的控制权交给内核。 内核及其关联文件位于 /boot 目录中。 内核文件是可识别的,因为它们都以 vmlinuz 开头命名。 您可以列出 /boot 目录的内容,以查看系统上当前安装的内核。

GRUB2 与 GRUB1 一样,支持从选择的 Linux 内核之一启动。 Red Hat 包管理器 DNF 支持保留内核的多个版本,以便在新版本出现问题时,可以启动旧版本的内核。 默认情况下,GRUB 提供已安装内核的预启动菜单,包括救援选项,如果配置,还包括恢复选项。

GRUB2 的阶段 2 将选定的内核加载到内存中,并将计算机的控制权交给内核。

内核

所有内核都采用自解压压缩格式以节省空间。 内核与初始 RAM 磁盘映像和硬盘驱动器的设备映射一起位于 /boot 目录中。

选定的内核加载到内存并开始执行后,它必须首先从文件的压缩版本中解压自身,然后才能执行任何有用的工作。 内核解压自身后,它会加载 systemd,它是旧的 SysV init 程序的替代品,并将控制权交给它。

这是启动过程的结束。 此时,Linux 内核和 systemd 正在运行,但由于没有其他任何东西在运行,因此无法为最终用户执行任何生产性任务。

启动过程

启动过程在启动过程之后进行,并将 Linux 计算机提升到可用于生产性工作的可操作状态。

systemd

systemd 是所有进程的母进程,它负责将 Linux 主机提升到可以完成生产性工作的状态。 它的一些功能(远比旧的 init 程序广泛)是管理正在运行的 Linux 主机的许多方面,包括挂载文件系统,以及启动和管理使 Linux 主机具有生产力的系统服务。 systemd 的任何与启动序列无关的任务都不在本文的范围之内。

首先,systemd 挂载 /etc/fstab 定义的文件系统,包括任何交换文件或分区。 此时,它可以访问位于 /etc 中的配置文件,包括它自己的配置文件。 它使用其配置文件 /etc/systemd/system/default.target 来确定它应该将主机启动到哪个状态或目标。 default.target 文件只是指向真实目标文件的符号链接。 对于桌面工作站,这通常将是 graphical.target,它等效于旧 SystemV init 中的 运行级别 5。 对于服务器,默认值更可能是 multi-user.target,它类似于 SystemV 中的 运行级别 3emergency.target 类似于单用户模式。

请注意,目标和服务是 systemd 单元。

下表 1 是 systemd 目标与旧 SystemV 启动运行级别的比较。 systemd 目标别名 由 systemd 提供,用于向后兼容。 目标别名允许脚本(以及许多像我这样的系统管理员)使用 SystemV 命令(如 init 3)来更改运行级别。 当然,SystemV 命令被转发到 systemd 进行解释和执行。

SystemV 运行级别 systemd 目标 systemd 目标别名 描述
  halt.target   停止系统,但不关闭电源。
0 poweroff.target runlevel0.target 停止系统并关闭电源。
S emergency.target   单用户模式。 没有服务正在运行; 文件系统未挂载。 这是最基本的操作级别,只有紧急 shell 在主控制台上运行,供用户与系统交互。
1 rescue.target runlevel1.target 基本系统,包括挂载文件系统,仅运行最基本的服务,并在主控制台上提供救援 shell。
2   runlevel2.target 多用户,没有 NFS,但所有其他非 GUI 服务都在运行。
3 multi-user.target runlevel3.target 所有服务都在运行,但仅限命令行界面 (CLI)。
4   runlevel4.target 未使用。
5 graphical.target runlevel5.target 多用户,带有 GUI。
6 reboot.target runlevel6.target 重启
  default.target   此目标始终与指向 multi-user.target 或 graphical.target 的符号链接别名。 systemd 始终使用 default.target 来启动系统。 default.target 永远不应别名为 halt.target、poweroff.target 或 reboot.target。

表 1:SystemV 运行级别与 systemd 目标和一些目标别名的比较。

每个目标都在其配置文件中描述了一组依赖项。 systemd 启动所需的依赖项。 这些依赖项是在特定功能级别运行 Linux 主机所需的服务。 当目标配置文件中列出的所有依赖项都已加载并运行时,系统将在该目标级别运行。

systemd 还查看旧的 SystemV init 目录,以查看那里是否存在任何启动文件。 如果是这样,systemd 会将这些文件用作配置文件来启动文件描述的服务。 弃用的网络服务是仍然在 Fedora 中使用 SystemV 启动文件的服务的典型例子之一。

下图 1 直接从 bootup 手册页 复制而来。 它显示了 systemd 启动期间的一般事件序列和基本排序要求,以确保成功启动。

sysinit.targetbasic.target 目标可以被视为启动过程中的检查点。 尽管 systemd 的设计目标之一是并行启动系统服务,但仍然存在某些服务和功能目标必须在其他服务和目标启动之前启动。 在满足该检查点所需的所有服务和目标之前,无法通过这些检查点。

因此,当其依赖的所有单元都完成时,将达到 sysinit.target。 所有这些单元(挂载文件系统、设置交换文件、启动 udev、设置随机生成器种子、启动低级服务以及在加密一个或多个文件系统的情况下设置加密服务)都必须完成,但在 sysinit.target 中,这些任务可以并行执行。

sysinit.target 启动系统基本功能所需的所有低级服务和单元,并且这些服务和单元是启用移动到 basic.target 所必需的。

   local-fs-pre.target
            |
            v
   (various mounts and   (various swap   (various cryptsetup
    fsck services...)     devices...)        devices...)       (various low-level   (various low-level
            |                  |                  |             services: udevd,     API VFS mounts:
            v                  v                  v             tmpfiles, random     mqueue, configfs,
     local-fs.target      swap.target     cryptsetup.target    seed, sysctl, ...)      debugfs, ...)
            |                  |                  |                    |                    |
            \__________________|_________________ | ___________________|____________________/
                                                 \|/
                                                  v
                                           sysinit.target
                                                  |
             ____________________________________/|\________________________________________
            /                  |                  |                    |                    \
            |                  |                  |                    |                    |
            v                  v                  |                    v                    v
        (various           (various               |                (various          rescue.service
       timers...)          paths...)              |               sockets...)               |
            |                  |                  |                    |                    v
            v                  v                  |                    v              rescue.target
      timers.target      paths.target             |             sockets.target
            |                  |                  |                    |
            v                  \_________________ | ___________________/
                                                 \|/
                                                  v
                                            basic.target
                                                  |
             ____________________________________/|                                 emergency.service
            /                  |                  |                                         |
            |                  |                  |                                         v
            v                  v                  v                                 emergency.target
        display-        (various system    (various system
    manager.service         services           services)
            |             required for            |
            |            graphical UIs)           v
            |                  |           multi-user.target
            |                  |                  |
            \_________________ | _________________/
                              \|/
                               v
                     graphical.target

图 1:systemd 启动图。

sysinit.target 完成后,systemd 接下来启动 basic.target,启动满足它所需的所有单元。 basic 目标通过启动下一个目标所需的单元来提供一些附加功能。 这些包括设置各种可执行目录的路径、通信套接字和计时器等。

最后,可以初始化用户级别目标 multi-user.targetgraphical.target。 请注意,必须先达到 multi-user.target ,然后才能满足 graphical 目标依赖项。

图 1 中带下划线的目标是常用的启动目标。 当达到这些目标之一时,启动就完成了。 如果 multi-user.target 是默认值,那么您应该在控制台上看到文本模式登录。 如果 graphical.target 是默认值,那么您应该看到图形登录; 您看到的特定 GUI 登录屏幕将取决于您使用的默认 显示管理器

问题

我最近需要更改使用 GRUB2 的 Linux 计算机上的默认启动内核。 我发现某些命令似乎对我不起作用,或者我没有正确使用它们。 我还不确定是哪种情况,需要做更多的研究。

grub2-set-default 命令没有正确地在 /etc/default/grub 文件中为我设置默认内核索引,因此所需的备用内核没有启动。 因此,我手动将 /etc/default/grub 中的 GRUB_DEFAULT=saved 更改为 GRUB_DEFAULT=2,其中 2 是我要启动的已安装内核的索引。 然后我运行命令 grub2-mkconfig > /boot/grub2/grub.cfg 以创建新的 grub 配置文件。 这种规避方法按预期工作,并启动到备用内核。

结论

GRUB2 和 systemd init 系统是大多数现代 Linux 发行版启动和启动阶段的关键组件。 尽管围绕 systemd 尤其存在争议,但这两种组件协同工作顺畅,首先加载内核,然后启动生成功能性 Linux 系统所需的所有系统服务。

尽管我确实发现 GRUB2 和 systemd 比它们的 predecessors 更复杂,但它们也同样易于学习和管理。 手册页包含大量关于 systemd 的信息,并且 freedesktop.org 在线提供了完整的 systemd 手册页。 有关更多链接,请参阅下面的资源。

其他资源

标签
David Both
David Both 是一位开源软件和 GNU/Linux 倡导者、培训师、作家和演讲者。 自 1996 年以来,他一直从事 Linux 和开源软件方面的工作,自 1969 年以来一直从事计算机方面的工作。 他是“系统管理员 Linux 哲学”的坚定支持者和传播者。

10 条评论

非常感谢您撰写关于 Linux 启动的文章! 我想找到这样的资源已经很久了。

我怀念过去启动操作的旧流。 我想这可能对某些人来说太可怕了,所以我们不得不使用这种图形化启动,它什么也没告诉我们。

这可以修复。 编辑 /etc/default/grub 并从内核参数行中删除“rhgb”和“quiet”。 然后运行命令

grub2-mkconfig > /boot/grub2/grub.cfg

该命令使用修改后的内核参数创建一个新的 grub.cfg,因此您现在应该看到启动期间所有可用的有趣信息。

由于启动期间可能出现问题甚至崩溃,我发现这些信息非常有用。 我可以通过观看信息的流动来了解很多信息,听起来你也可以。

尽情享受吧!

回复 ,作者 Greg P

当我搞乱启动过程时,我总是要深吸一口气,当系统无法启动时,这真是一件痛苦的事情。
无论如何,我发现我需要成为真正的 root 用户而不是 sudo 才能运行此命令(我认为是因为文件的权限),而我真正需要做的是(在 F24 上)
grub2-mkconfig > /boot/grub2/grub.cfg
因为这是 grub.cfg 实际所在的位置。

我想补充一点,在实践层面,我发现启动消息更常提醒您一些不会阻止启动的事情,但可能会影响您之后需要的某些服务,并让您提前了解某些故障。

对我来说,这篇文章非常及时,因为我昨天不得不深入研究所有这些!

非常感谢您撰写这篇文章,它很棒。

在 2017 年谈论 mbr 和 bios 似乎很奇怪,曾希望您能涵盖 gpt 和 uefi。

感谢您对启动和启动过程的精彩总结。 考虑更新以解释哪些发行版可能遵循您描述的方案。 例如,尽管 'systemd' 在启动+启动过程中使用,但我无法在我的 Linux Mint 17.3 工作站上“找到”任何 *.target 文件。

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 获得许可。
© 2025 open-source.net.cn. All rights reserved.