1. 课程导论:Linux内核启动流程概述

1.1 启动流程全景图

Linux内核从加电到用户空间init进程启动,经历多个阶段。解压缩阶段位于内核自解压与重定位环节,是内核从压缩镜像到可执行ELF内核的桥梁。下图展示完整的启动链:

Linux内核启动流程全景图 Linux内核启动流程全景图 BootROM Bootloader 解压缩阶段 内核初始化 init进程 各阶段关键动作: • BootROM:加载Bootloader到SRAM,执行硬件最小初始化 • Bootloader:加载压缩内核镜像到RAM,传递启动参数(DTB/ATAG) • 解压缩阶段:自解压、地址重定位、校验完整性、跳转到解压后入口 • 内核初始化:setup_arch、mm_init、驱动加载、挂载根文件系统 • init进程:启动用户空间服务,完成系统初始化

1.2 解压缩阶段在启动链中的位置

解压缩阶段位于Bootloader将控制权交给内核之后、内核自身初始化之前。具体位置由内核镜像的链接布局决定:

阶段序号 阶段名称 入口地址 主要职责
1 Bootloader加载 物理内存起始(如0x8000) 将压缩内核镜像加载到RAM,设置启动参数
2 解压缩阶段 解压缩代码入口(如startup_32) 自解压、重定位、校验、跳转
3 内核入口 解压后内核基址(如0x1000000) start_kernel(),体系结构初始化
4 内核初始化 虚拟地址空间 内存管理、调度、驱动、文件系统

关键理解:解压缩阶段是内核从"压缩镜像"到"可执行ELF内核"的转换器。它负责将Bootloader加载的压缩数据解压到正确地址,并完成地址重定位,使内核能够在任意物理地址运行。

1.3 解压缩阶段的核心作用

解压缩阶段承担以下三项核心任务:

  1. 自解压(Self-extraction):内核镜像头部包含解压缩代码,启动后自动解压gzip/lz4/lzma等格式的压缩数据。
  2. 地址重定位(Address Relocation):将解压后的内核移动到最终运行地址,修正符号表与全局偏移表(GOT),确保代码段、数据段、BSS段地址正确。
  3. 完整性校验(Integrity Verification):通过CRC32或SHA校验解压后数据,防止内存损坏或恶意篡改导致内核崩溃。
解压缩阶段核心任务分解图 解压缩阶段核心任务分解图 解压缩阶段 自解压 gzip/lz4/lzma → 原始内核 地址重定位 GOT修正 · 符号表重定位 完整性校验 CRC32/SHA · 防篡改 提示:三个任务顺序执行,任一失败则内核无法启动,通常通过串口输出错误码

1.4 解压缩阶段的输入与输出

理解解压缩阶段的边界条件,有助于后续章节深入分析:

维度 输入 输出
镜像格式 zImage / bzImage(ARM: zImage, x86: bzImage) 原始ELF内核(vmlinux)
压缩算法 gzip(默认)、lz4、lzma、xz、zstd 无压缩的二进制数据
地址空间 Bootloader加载地址(可能非最终地址) 重定位后的最终运行地址
校验信息 镜像尾部附加的校验值 校验通过/失败状态
控制权交接 Bootloader跳转到解压缩入口 跳转到解压后内核入口(start_kernel)

实践要点:嵌入式开发中,解压缩阶段是调试启动失败的关键切入点。常见问题包括:解压缩地址与加载地址重叠导致数据损坏、校验失败(内存ECC错误)、重定位后符号表未修正导致函数调用崩溃。建议在解压缩阶段增加串口打印(early_printk)以定位故障。

1.5 解压缩阶段的代码组织

解压缩代码位于内核源码的 arch/<arch>/boot/compressed/ 目录下,以ARM64为例:

arch/arm64/boot/compressed/
├── head.S          # 解压缩入口,设置栈、调用解压函数
├── misc.c          # 解压算法封装(gunzip等)
├── decompress.c    # 解压核心逻辑
├── string.c        # 轻量级字符串函数(避免依赖内核库)
├── vmlinux.lds.S   # 链接脚本,定义解压缩代码布局
└── Makefile        # 编译规则

关键代码执行顺序:

  1. head.S 中的 startup_32(ARM)或 _start(x86)设置CPU模式、栈指针。
  2. 调用 decompress_kernel() 执行解压,同时进行地址重定位。
  3. 解压完成后,调用 __inflate_kernel() 进行CRC校验。
  4. 跳转到解压后内核入口 __mmap_switched(ARM)或 startup_64(x86)。

注意:解压缩阶段运行在物理地址空间,未开启MMU。所有地址操作必须使用物理地址,不能依赖虚拟内存映射。这也是地址重定位必须手动修正GOT的原因。

1.6 本章小结