1. 引言与背景:Linux内核启动流程概述

1.1 启动流程全景图

Linux内核从引导到用户空间初始化,经历多个紧密衔接的阶段。解压与重定位阶段位于引导加载程序与内核初始化之间,是内核从压缩镜像到可执行实体的关键转折点。下图展示了完整的启动链路及各阶段的内存状态特征。

关键认知:解压与重定位是内核从"静态镜像"到"动态运行实体"的桥梁。此阶段完成后,CPU才能访问真正的内核代码段、数据段和BSS段。
Linux内核启动流程全景图 阶段1:引导加载程序 BIOS/UEFI → Bootloader 加载内核镜像到内存 阶段2:解压与重定位 自解压、重定位、页表 进入保护模式/长模式 阶段3:内核初始化 start_kernel() 子系统初始化 阶段4:用户空间 init进程启动 系统服务加载 各阶段内存状态:实模式 → 保护模式/长模式 → 虚拟内存全功能 → 用户态/内核态隔离 解压与重定位阶段内部子流程 子阶段1 解压入口 子阶段2 自解压执行 子阶段3 重定位计算 子阶段4 页表切换 📌 解压与重定位阶段的重要性 • 内存布局转换:从Bootloader加载的压缩镜像 → 解压后的原始内核 • 地址空间切换:从物理地址 → 虚拟地址(页表初始化) • CPU模式升级:实模式(16位)→ 保护模式(32位)→ 长模式(64位) • 重定位修正:解决内核链接地址与加载地址不一致的问题 • 错误处理:解压失败或重定位越界将直接导致系统无法启动

1.2 启动阶段详细对比

下表从CPU模式、内存管理、代码执行环境和关键数据结构四个维度,对比启动链中各阶段的特征差异。

阶段 CPU模式 内存管理 代码执行环境 关键数据结构
Bootloader 实模式(16位) 物理地址,无MMU BIOS中断可用,地址空间受限 setup_header, boot_params
解压与重定位 保护模式/长模式 临时页表,恒等映射 自解压代码,位置无关 ELF header, relocation table
内核初始化 保护模式/长模式 完整页表,虚拟内存 start_kernel(),多任务环境 task_struct, mm_struct
用户空间 保护模式/长模式 进程独立地址空间 系统调用接口,用户态/内核态切换 进程描述符,文件描述符
💡 实践要点:解压与重定位阶段是唯一一个同时操作物理地址和虚拟地址的阶段。内核在此阶段需要维护两套地址映射关系,任何映射错误都会导致系统崩溃。调试此阶段问题时,建议使用QEMU + GDB组合,在解压入口处设置断点。

1.3 解压与重定位阶段的核心任务

该阶段承担三项不可分割的任务,任何一项失败都会导致启动终止:

  1. 自解压(Self-decompression):内核镜像通常以gzip、lz4、xz等算法压缩存储。解压代码内嵌在镜像头部,负责将压缩数据还原为原始ELF格式。
  2. 重定位(Relocation):内核编译时使用固定的链接地址(如x86_64的0x1000000),但Bootloader可能将镜像加载到任意物理地址。重定位代码负责修正所有绝对地址引用。
  3. 页表初始化与模式切换:在x86架构上,需要从实模式切换到保护模式(32位)或长模式(64位),并建立临时页表保证解压后的内核能在虚拟地址空间运行。
⚠️ 常见陷阱:嵌入式开发中,若Bootloader与内核约定的加载地址不一致,重定位阶段可能覆盖Bootloader自身或设备树(DTB)所在内存区域。务必检查Bootloader配置中的 kernel_addr_r 和 fdt_addr_r 参数。

1.4 内存布局的阶段性变化

下图展示了从Bootloader加载到解压完成过程中,物理内存布局的典型变化。注意重叠区域和临时缓冲区的分配策略。

解压与重定位阶段内存布局变化 阶段A:Bootloader加载后 Bootloader 压缩内核镜像 DTB/initrd • 内核镜像以压缩形式连续存放 • 所有地址均为物理地址 • 尚未建立页表,CPU运行在实模式 阶段B:解压进行中 Bootloader 压缩内核 解压缓冲区 • 解压代码在压缩镜像头部执行 • 解压输出写入临时缓冲区 • 临时页表已建立,进入保护模式 阶段C:解压完成 + 重定位 Bootloader 解压后内核 重定位表 • 内核已解压到目标地址 • 重定位表修正所有符号地址 • 页表切换完成,准备跳转 阶段D:跳转到内核入口 Bootloader 内核代码段 内核数据段 • 解压代码释放临时缓冲区 • 跳转到startup_64/setup_arch • 进入start_kernel()初始化

1.5 架构差异与平台适配

不同CPU架构在解压与重定位阶段的实现存在显著差异。下表列出主流架构的关键区别:

架构 解压算法 重定位方式 页表层级 特殊处理
x86_64 gzip / lz4 / xz ELF重定位表 + 运行时修正 4级页表(PML4) 实模式→保护模式→长模式三级切换
ARM64 gzip / lz4 位置无关代码(PIC)+ 重定位表 3/4级页表 无需模式切换,直接进入EL2/EL1
RISC-V gzip / lz4 PIC + 链接脚本修正 Sv39 / Sv48 M态→S态切换,设备树传递
MIPS gzip KSEG0/KSEG1地址映射 TLB软件管理 Cache一致性处理复杂
🔧 调试建议:分析解压与重定位阶段问题时,推荐使用以下工具组合:
• QEMU + GDB:在解压入口处设置断点,单步跟踪重定位计算
• early_printk:在解压代码中插入早期串口输出,观察地址映射变化
• 内存dump对比:解压前后对关键内存区域做快照,验证重定位修正是否正确

1.6 本章小结

解压与重定位阶段是Linux内核启动链中最脆弱也最关键的一环。它承担着从压缩镜像到可执行内核的转换任务,同时完成CPU模式升级和地址空间初始化。后续章节将深入分析:

  • 解压算法的选择与性能权衡(第2章)
  • 重定位表的生成与运行时修正机制(第3章)
  • 页表初始化与虚拟地址映射的建立(第4章)
  • 各架构的启动汇编代码逐行解析(第5-8章)