Skip to content
Gains Summary
Main Navigation 首页 / Home
C++ 编程 / C++ Programming
系统与高性能 / Systems & Performance
Web 开发 / Web Development
人工智能 / Artificial Intelligence
工业软件 / Industrial Software
其他内容 / Other Topics
C++ 编程 / C++系统与性能 / SystemsWeb 开发 / Web人工智能 / AI工业软件 / Industrial

外观

Sidebar Navigation

← 系统与高性能 / Systems & Performance

操作系统 / Operating Systems

1. OS 底层知识学习路线 / A Learning Path for Operating System Internals

2. 存储硬件基础 — 磁盘到底怎么存数据 / Storage Hardware Fundamentals: How Disks Store Data

3. BIOS vs UEFI — 固件的本质 / BIOS and UEFI: Understanding Firmware

4. 磁盘分区表 — GPT 与 MBR / Disk Partition Tables: GPT and MBR

5. 文件系统核心概念 — inode、journal、COW / Filesystem Concepts: Inodes, Journaling, and Copy-on-Write

6. 常见文件系统格式详解 — FAT 到 ZFS 的进化史 / Filesystem Formats from FAT to ZFS

7. Linux 启动全流程 — 从通电到登录提示符 / The Linux Boot Process from Power-On to Login

8. Windows 启动全流程 — 与 Linux 的对比视角 / The Windows Boot Process in Comparison with Linux

9. Linux 文件系统层次结构 (FHS) — 目录树的哲学 / The Linux Filesystem Hierarchy Standard

10. Linux 挂载机制 — mount、VFS 与 fstab / Linux Mounting with Mount, VFS, and Fstab

11. Linux 磁盘管理实战 — 从分区到挂载全流程 / Practical Linux Disk Management from Partitioning to Mounting

12. Windows 磁盘与文件系统 — 盘符帝国的秩序 / Windows Disks and Filesystems

13. ext4 深入 — 从超级块到 Extent Tree / Ext4 in Depth from Superblocks to Extent Trees

14. btrfs 深入 — B-tree 是万能的 / Btrfs in Depth and Its B-Tree Architecture

15. 双系统 — EFI 分区共存与 GRUB chainload / Dual Boot with Shared EFI Partitions and GRUB Chainloading

本页目录

Linux 启动全流程 — 从通电到登录提示符 / The Linux Boot Process from Power-On to Login ​

📅 创建时间:2026-06-17 🏷️ 标签:#Linux #启动 #GRUB #内核 #initramfs #systemd 📚 前置知识:[[02-firmware-bios-uefi]], [[03-partition-table]], [[05-filesystem-formats]]


📋 本章目标 ​

  • 追踪 Linux 从通电到登录提示符的完整六阶段流程
  • 理解 GRUB 的工作原理——如何从 446 字节发展到加载内核
  • 理解 Linux 内核镜像(bzImage)的自解压过程
  • 理解 initramfs——为什么需要它,里面放了什么
  • 理解 systemd 作为 PID 1 的启动编排
  • 能够解释 GRUB 菜单里每个选项背后的技术含义

第1部分:完整链路速览 ​

┌─────────────────────────────────────────────────────────────┐
│              Linux 启动六阶段全链路                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  按下电源键                                                 │
│      ↓                                                      │
│  ╔══════════════════════════════════════════════════════╗  │
│  ║ 阶段1: 固件 (UEFI/BIOS)                          ║  │
│  ║   通电 → CPU复位 → 固件运行 → 发现启动设备          ║  │
│  ║   详见 [[02-firmware-bios-uefi]]                  ║  │
│  ╚══════════════════════════════════════════════════════╝  │
│      ↓                                                      │
│  ╔══════════════════════════════════════════════════════╗  │
│  ║ 阶段2: Bootloader (GRUB)                         ║  │
│  ║   加载 grub.cfg → 显示菜单 → 加载内核+initramfs     ║  │
│  ╚══════════════════════════════════════════════════════╝  │
│      ↓                                                      │
│  ╔══════════════════════════════════════════════════════╗  │
│  ║ 阶段3: 内核加载 (bzImage 自解压)                ║  │
│  ║   解压 → 初始化硬件 → 挂载 initramfs 为临时根目录    ║  │
│  ╚══════════════════════════════════════════════════════╝  │
│      ↓                                                      │
│  ╔══════════════════════════════════════════════════════╗  │
│  ║ 阶段4: initramfs(早期用户空间)                ║  │
│  ║   加载驱动 → 发现并挂载真正的根文件系统               ║  │
│  ╚══════════════════════════════════════════════════════╝  │
│      ↓                                                      │
│  ╔══════════════════════════════════════════════════════╗  │
│  ║ 阶段5: systemd (PID 1)                          ║  │
│  ║   切换到真实根 → 启动所有服务 → 到达登录提示           ║  │
│  ╚══════════════════════════════════════════════════════╝  │
│      ↓                                                      │
│  ╔══════════════════════════════════════════════════════╗  │
│  ║ 阶段6: getty → login → shell                    ║  │
│  ║   显示登录提示符 → 你输入密码 → 进入 shell             ║  │
│  ╚══════════════════════════════════════════════════════╝  │
│      ↓                                                      │
│  $   ← 你在这里                                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

第2部分:GRUB — Bootloader 的工作 ​

2.1 GRUB 的多阶段设计 ​

为什么 GRUB 需要多个阶段?答案:446 字节根本不够用。还记得 MBR 的引导代码只有 440 字节吗?

┌─────────────────────────────────────────────────────────────┐
│              GRUB Legacy Boot (BIOS 模式) 的三阶段           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Stage 1: boot.img (446 字节)                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 存在: MBR (LBA 0 的前 446 字节)                     │   │
│  │                                                     │   │
│  │ 功能: 只做一件事                                    │   │
│  │   → 加载 LBA 1 处的 core.img 的第一个扇区            │   │
│  │                                                     │   │
│  │ 为什么这么小: 因为 MBR 只有 440 字节给代码            │   │
│  └─────────────────────────────────────────────────────┘   │
│         ↓                                                   │
│  Stage 1.5: core.img (约 32KB)                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 存在: MBR 之后、第一个分区之前的空隙 (post-MBR gap)   │   │
│  │      这个区域在现代磁盘上大约是 1MiB-512B             │   │
│  │                                                     │   │
│  │ 功能: 包含文件系统驱动                               │   │
│  │   → 能直接读取 ext4/btrfs 里的 /boot/grub/ 目录      │   │
│  │   → 加载真正的 GRUB 模块                            │   │
│  │                                                     │   │
│  │ 为什么需要这步: Stage 1 连文件系统都不懂               │   │
│  │                Stage 1.5 给它读文件的能力              │   │
│  └─────────────────────────────────────────────────────┘   │
│         ↓                                                   │
│  Stage 2: /boot/grub/x86_64-efi/normal.mod + grub.cfg       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 存在: /boot/grub/ 目录下 (普通文件, 不是扇区了)       │   │
│  │                                                     │   │
│  │ 功能:                                               │   │
│  │   1. 读取 grub.cfg → 显示启动菜单                   │   │
│  │   2. 加载用户选择的内核 (vmlinuz-linux)              │   │
│  │   3. 加载 initramfs (initramfs-linux.img)           │   │
│  │   4. 设置内核命令行参数                              │   │
│  │   5. 跳转到内核入口点                                │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  UEFI 模式的简化:                                           │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ UEFI 固件能直接读 FAT32 → 直接执行 grubx64.efi       │   │
│  │ grubx64.efi 已经包含文件系统驱动 → 相当于传统 Stg 1+1.5│   │
│  │ → 直接从 Stage 2 开始                               │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

2.2 GRUB 配置文件详解 ​

bash
# /boot/grub/grub.cfg (简化版)
# 这个文件通常由 grub-mkconfig 自动生成
# 手动编辑在 /etc/default/grub

# 加载必要的模块
insmod gzio          # gzip 解压 (内核镜像是 gz 压缩的)
insmod part_gpt      # GPT 分区表支持
insmod btrfs         # btrfs 文件系统支持

# 设置根文件系统(GRUB 视角的"根")
set root='hd0,gpt3'  # 第一块磁盘, GPT, 第3个分区
                     # GRUB 用 (hd磁盘编号, 分区类型+编号) 标识设备

# 默认启动项
set default=0         # 第 0 个菜单项为默认
set timeout=5         # 5 秒超时

# Linux 启动菜单项
menuentry 'Arch Linux' {
    # 加载内核 (vmlinuz = bzImage)
    linux /boot/vmlinuz-linux root=UUID=xxx-xxx rw quiet

    # 加载 initramfs
    initrd /boot/initramfs-linux.img
}

# 如果装了双系统, 这里会有 Windows 菜单项
menuentry 'Windows Boot Manager' {
    # 搜索 ESP 分区里的 Windows Boot Manager
    search --fs-uuid --set=root <ESP-UUID>
    chainloader /EFI/Microsoft/Boot/bootmgfw.efi
    #         ↑ chainload = 把控制权交给另一个 .efi 文件
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

2.3 内核命令行参数 ​

┌─────────────────────────────────────────────────────────────┐
│              你 GRUB 里看到的内核命令行参数                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  linux /boot/vmlinuz-linux root=UUID=xxx rw quiet           │
│         │                    │              │               │
│         │                    │              └── quiet: 减少启动日志输出 │
│         │                    └── rw: 以读写模式挂载根文件系统 │
│         └── root=UUID=xxx: 告诉内核根文件系统在哪个分区      │
│                                                             │
│  这是你 Arch 安装时必须填对的一个参数!                      │
│  错了 → 内核找不到根 → kernel panic → 启动失败              │
│                                                             │
│  其他常见参数:                                              │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ init=/bin/bash      启动到 bash 而不是 systemd       │   │
│  │                     用于修复系统时的救援模式         │   │
│  │                                                     │   │
│  │ single              进入单用户维护模式               │   │
│  │                                                     │   │
│  │ nomodeset           禁用内核图形模式设置              │   │
│  │                     显卡驱动问题时用                 │   │
│  │                                                     │   │
│  │ rootflags=subvol=@  告诉内核挂载 btrfs 的哪个 subvol │   │
│  │                     你的 Arch 就是这么启动的         │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

第3部分:内核加载 — bzImage 的秘密 ​

3.1 bzImage 格式 ​

┌─────────────────────────────────────────────────────────────┐
│              bzImage 的内部结构                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  bzImage = setup header + 压缩的内核 + 解压代码              │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  ┌──────────────────┐                              │   │
│  │  │  Setup Header    │  实模式启动代码                  │   │
│  │  │  (约 20KB)      │  设置 32/64 位模式               │   │
│  │  │                  │  检测内存布局                    │   │
│  │  └──────────────────┘                              │   │
│  │  ┌──────────────────┐                              │   │
│  │  │  解压代码        │  自解压器 (decompressor)         │   │
│  │  │  (misc.c)       │  一小段 C 代码                   │   │
│  │  └──────────────────┘                              │   │
│  │  ┌──────────────────┐                              │   │
│  │  │                  │                              │   │
│  │  │  压缩的内核      │  gzip/bzip2/lz4/xz/zstd 压缩   │   │
│  │  │  (vmlinux)      │  解压后约 30-50MB               │   │
│  │  │                  │  这是真正执行的内核代码         │   │
│  │  │                  │                              │   │
│  │  └──────────────────┘                              │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  GRUB 加载 bzImage → 跳转到 setup header                     │
│  → setup header 做模式切换 → 跳转到 解压代码                   │
│  → 解压代码把压缩内核解压到正确的位置 → 跳转到内核入口点        │
│                                                             │
│  "bz" = "big zImage" (不是 bzip2!)                          │
│  这是一个历史命名——早期的 zImage 必须放在 1MB 以下的物理内存   │
│  bzImage 可以放在任意位置                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

3.2 内核初始化——start_kernel() ​

c
// 内核入口: arch/x86/kernel/head_64.S
// → 最终调用 init/main.c 中的 start_kernel()

asmlinkage __visible void __init start_kernel(void)
{
    // 1. 基础设置
    setup_arch(&command_line);       // 架构特定初始化 (CPU/内存/设备树)
    setup_command_line();           // 保存内核命令行参数

    // 2. 内存管理初始化
    mm_init();                      // 建立页表、初始化内存分配器

    // 3. 调度器初始化
    sched_init();                   // 初始化进程调度器

    // 4. 中断和定时器
    init_IRQ();                     // 中断子系统
    init_timers();                  // 定时器

    // 5. VFS 和 文件系统
    vfs_caches_init();              // 虚拟文件系统缓存

    // 6. 最后一步: 启动 init 进程
    arch_call_rest_init();
    // → 创建第一个内核线程 → 加载 initramfs → 执行 /init
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

关键点:start_kernel() 结束时,第一个进程(PID 1)被创建。它做的第一件事就是尝试执行 initramfs 里的 /init。


第4部分:initramfs — 临时根文件系统 ​

4.1 为什么需要 initramfs? ​

┌─────────────────────────────────────────────────────────────┐
│              鸡生蛋蛋生鸡问题                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  内核需要:                                                  │
│  • 挂载根文件系统 → 需要读磁盘                                │
│  • 读磁盘 → 需要磁盘驱动                                     │
│  • 磁盘驱动 → 在根文件系统里 (/lib/modules/...)              │
│                                                             │
│  但我们还没挂载根文件系统!                                  │
│                                                             │
│  这就是 initramfs 的用途:                                    │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  initramfs = 一个微型 Linux 系统, 打包成 cpio 归档    │   │
│  │                                                      │   │
│  │  UEFI 固件 → GRUB→内核→挂载initramfs为临时的 '/'      │   │
│  │                                │                    │   │
│  │                      initramfs 里有:                 │   │
│  │                       • NVMe/SATA 驱动               │   │
│  │                       • btrfs/ext4 驱动              │   │
│  │                       • 设备检测工具 (blkid)          │   │
│  │                       • 挂载脚本 (mount)             │   │
│  │                       • 一个简化的 init 程序           │   │
│  │                                │                    │   │
│  │                      加载驱动 → 发现 nvme0n1          │   │
│  │                             → mount 真实的 /           │   │
│  │                             → 切换到真实根            │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  没有 initramfs, 内核只能挂载那些"编译进内核的驱动所支持       │
│  的设备"。但把所有可能的磁盘驱动编译进内核 → 内核太大。        │
│                                                             │
│  initramfs 的设计哲学:                                      │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 内核保持精简, 驱动放进 initramfs                      │   │
│  │ 一个 initramfs 可以在所有机器上工作 ——                 │   │
│  │ 只要包含足够多的驱动 (现代 initramfs 通常 20-50MB)    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

4.2 initramfs 内部 ​

$ lsinitcpio /boot/initramfs-linux.img
# 输出 (简化):

# 目录结构
/
├── init              ← 内核执行的第一个程序
├── bin/
│   ├── busybox       ← 瑞士军刀: sh/mount/cat/ls 全在一个文件
│   └── blkid         ← 检测文件系统 UUID
├── lib/
│   └── modules/
│       └── 6.x.x-arch1-1/  ← 内核模块
│           ├── kernel/drivers/nvme/   ← NVMe 驱动
│           ├── kernel/drivers/ata/    ← SATA 驱动
│           └── kernel/fs/btrfs/       ← btrfs 驱动
├── etc/
│   └── fstab         ← 临时的挂载配置
└── usr/lib/systemd/
    └── systemd-udevd ← 设备管理器

# 你的 Arch 用 mkinitcpio 生成 initramfs
# mkinitcpio 的配置在 /etc/mkinitcpio.conf
# HOOKS=(base udev autodetect modconf block filesystems fsck)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

4.3 从 initramfs 切换到真实根 ​

┌─────────────────────────────────────────────────────────────┐
│              pivot_root / switch_root 操作                   │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  initramfs 的 /init 做的最后一步:                            │
│                                                             │
│  1. 挂载真实根文件系统到 /new_root:                          │
│     mount /dev/nvme0n1p3 /new_root                          │
│                                                             │
│  2. 切换根目录:                                             │
│     exec switch_root /new_root /sbin/init                   │
│                                                             │
│     switch_root 做的事:                                     │
│     ┌─────────────────────────────────────────────────────┐  │
│     │ • 把 /new_root 变成新的 '/'                          │  │
│     │ • 把旧的 initramfs 文件移走 (释放内存)              │  │
│     │ • exec 执行新根里的 /sbin/init (通常是 systemd)     │  │
│     └─────────────────────────────────────────────────────┘  │
│                                                             │
│  从这一刻起, initramfs 的使命结束                            │
│  控制权交给 systemd (PID 1)                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

第5部分:systemd — PID 1 的编排 ​

5.1 systemd 的核心职责 ​

┌─────────────────────────────────────────────────────────────┐
│              systemd 的启动编排                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  systemd 作为 PID 1 (init 进程) 负责:                        │
│                                                             │
│  1. 挂载剩余的文件系统 → 读取 /etc/fstab                      │
│     mount /home (btrfs subvolume @home)                     │
│     mount /boot (ESP, FAT32)                                │
│                                                             │
│  2. 启动服务 → 按依赖关系并行启动                             │
│     ┌─────────────────────────────────────────────────┐    │
│     │                                                 │    │
│     │  network.target                                 │    │
│     │      │                                          │    │
│     │      ├── NetworkManager.service                  │    │
│     │      │      └→ 配网                              │    │
│     │      │                                          │    │
│     │      ├── sshd.service                            │    │
│     │      │      └→ SSH 服务                          │    │
│     │      │                                          │    │
│     │      └── bluetooth.service                       │    │
│     │                                                  │    │
│     │  multi-user.target                               │    │
│     │      │                                          │    │
│     │      └── display-manager.service                  │    │
│     │             └→ 启动登录管理器 (GDM/SDDM/LightDM)  │    │
│     │                                                 │    │
│     └─────────────────────────────────────────────────┘    │
│                                                             │
│  3. 启动 getty → 在 tty 上显示登录提示                       │
│     systemd 为每个虚拟终端 (tty1-tty6) 启动一个 getty        │
│                                                             │
│  4. 管理运行级别 (target)                                    │
│     rescue.target  → 救援模式                                │
│     multi-user.target → 多用户文本模式                        │
│     graphical.target → 带图形界面                            │
│                                                             │
│  你可以看到 systemd 的分析:                                  │
│  # systemd-analyze                                           │
│  Startup finished in 3.456s (kernel) + 2.123s (userspace)   │
│                                                             │
│  # systemd-analyze blame                                     │
│  1.234s NetworkManager.service                              │
│  0.567s systemd-journald.service                            │
│  ...                                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

第6部分:getty → login → shell ​

┌─────────────────────────────────────────────────────────────┐
│              最后一公里: 从 getty 到 shell                    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  systemd 为每个虚拟终端启动一个 getty:                        │
│                                                             │
│  getty@tty1.service:                                        │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                                                     │   │
│  │  1. 打开 /dev/tty1 (虚拟终端设备)                     │   │
│  │  2. 显示: "Arch Linux 6.x.x (tty1)"                 │   │
│  │  3. 显示: "hostname login: "                        │   │
│  │  4. 等待用户输入用户名                               │   │
│  │                                                     │   │
│  │  用户输入 "Jaten" + <Enter>                           │   │
│  │                                                     │   │
│  │  5. getty exec → /bin/login                          │   │
│  │     login 程序: 显示 "Password: "                    │   │
│  │     验证 /etc/shadow 里的密码哈希                     │   │
│  │                                                     │   │
│  │  6. 验证通过 → login exec → /bin/bash (或 zsh/fish) │   │
│  │     bash 读取 ~/.bashrc → 设置环境                   │   │
│  │     → 显示提示符: [Jaten@arch ~]$                   │   │
│  │                                                     │   │
│  │  此时你登录的 shell 是 getty → login → bash           │   │
│  │  的子进程链. PID 1 (systemd) 是它们的祖先.            │   │
│  │                                                     │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  这个链条可以用 pstree 验证:                                │
│  $ pstree -p                                               │
│  systemd(1)───systemd-logind(456)                           │
│           ├──getty(789)───login(790)───bash(791)             │
│                                                             │
│  注意: 每次 exec 替换进程镜像, PID 保持不变.                │
│        getty(PID 789) → login(PID 789) → bash(PID 789)    │
│                                                             │
└─────────────────────────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

核心总结 ​

总结1:六阶段完整链 ​

UEFI → grubx64.efi → 加载 vmlinuz + initramfs → 内核自解压
→ initramfs 挂载真实根 → switch_root → systemd → getty → login → shell
1
2

总结2:为什么需要 initramfs ​

内核需要驱动才能挂载根 → 但驱动在根里 → initramfs 打破循环
GRUB 加载内核 + initramfs → 内核用 initramfs 里的驱动挂载真实根
1
2

总结3:哪些环节你可以干预 ​

1. UEFI 设置 → 改变启动顺序、开关 Secure Boot
2. GRUB 命令行 → 临时修改内核参数 (按 e 编辑)
3. /etc/default/grub → 永久修改内核参数
4. /etc/mkinitcpio.conf → 控制 initramfs 里放什么
5. systemd 服务 → systemctl enable/disable
1
2
3
4
5

章节测试 ​

测试1:GRUB 的阶段 ​

GRUB 为什么设计成多阶段(boot.img → core.img → normal.mod)?

测试2:initramfs 的必要性 ​

如果没有 initramfs,内核在一个使用 NVMe SSD + btrfs 的系统上能否成功启动?为什么?

测试3:pivot_root ​

switch_root 做了什么?为什么要"切换根"?

测试4:内核参数 ​

root=UUID=xxx 这个参数是给谁看的?作用是什么?

测试5:系统分析 ​

运行 systemd-analyze 看到的 "kernel" 时间和 "userspace" 时间分别指什么阶段?


参考答案 ​

测试1答案 ​

因为 MBR 引导代码只有 440 字节,放不下文件系统驱动。Stage 1(boot.img,446B)只能跳到 Stage 1.5(core.img,~32KB),后者包含文件系统驱动才能读 /boot/grub/ 目录加载 Stage 2。这是受限于硬件的渐进式加载设计。UEFI 模式下固件直接执行 grubx64.efi(≈Stage 1+1.5),简化了这个过程。

测试2答案 ​

不能。内核本身不包含 NVMe 驱动和 btrfs 驱动(作为可加载模块放在 /lib/modules/)。要挂载 btrfs 格式的根文件系统,必须先加载这两个模块。但模块在根文件系统里——这就陷入循环。initramfs 包含了这两个模块,在挂载真实根之前把它们加载到内核。

测试3答案 ​

switch_root 做三件事:(1) 把挂载了真实根文件系统的 /new_root 变成新的 /,(2) 释放旧的 initramfs 占用的内存,(3) 执行新 / 里的 /sbin/init(systemd)。它的核心意义是将系统从"临时急救系统"切换到"真正的操作系统"。

测试4答案 ​

root=UUID=xxx 是给内核看的。在 initramfs 阶段,init 脚本读取这个参数,用 blkid 找到对应 UUID 的分区(如 /dev/nvme0n1p3),然后挂载它作为新的根文件系统。这个参数是 initramfs 和内核命令行之间的关键约定。

测试5答案 ​

  • kernel 时间:从 GRUB 跳转到内核入口点到 start_kernel() 执行完毕、挂载 initramfs 并调用 initramfs 内 /init 的这段时间。包括内核自解压、硬件初始化。
  • userspace 时间:从 initramfs 的 /init 开始执行,经过 switch_root、systemd 启动服务,到 graphical.target 或 multi-user.target 就绪的这段时间。

相关笔记 ​

  • [[02-firmware-bios-uefi]] - 启动的第一步:固件
  • [[07-windows-boot]] - Windows 的启动链,对照阅读
  • [[14-dual-boot]] - GRUB 链式加载 Windows 的实现原理

下一步学习 ​

  • [ ] 阅读 07 - Windows 启动全流程

学习状态:🟡 开始学习

最后更新于:

Pager
上一篇6. 常见文件系统格式详解 — FAT 到 ZFS 的进化史 / Filesystem Formats from FAT to ZFS
下一篇8. Windows 启动全流程 — 与 Linux 的对比视角 / The Windows Boot Process in Comparison with Linux

持续记录,持续成长

Copyright © Tidenflow