3. 内核加载机制:内核镜像格式与解压过程

Bootloader 完成硬件初始化后,核心任务是将内核从存储介质(Flash、eMMC、SD 卡或网络)加载到 RAM 中,并跳转到内核入口。内核镜像的格式、加载地址和解压方式直接影响启动时序。本章深入分析 zImage、Image、DTB 三种关键镜像的布局与加载流程。

3.1 内核镜像格式对比

嵌入式 Linux 内核编译后生成多种镜像格式,Bootloader 需要根据硬件平台和启动方式选择正确的格式。下表列出三种常见格式的核心差异:

特性 Image(原始内核) zImage(压缩内核) DTB(设备树二进制)
文件大小 大(未压缩,约 5–15 MB) 小(压缩后,约 2–5 MB) 小(约 10–200 KB)
加载地址 直接加载到 RAM 运行地址 加载到临时解压缓冲区 加载到约定地址(如 0x48000000)
解压阶段 无需解压 内核自解压(头部包含解压代码) 无需解压
启动速度 快(无解压开销) 慢(解压耗时 50–200 ms) 极快(直接解析)
存储占用 高 低 极低
适用场景 XIP(原地执行)、大 RAM 设备 Flash 空间受限的嵌入式设备 所有 ARM/ARM64/RISC-V 平台
关键时序指标: zImage 解压时间通常占内核加载总时间的 40%–60%。在启动时序调优中,优先考虑使用 Image(如果 Flash 空间允许)或优化解压算法(如 LZ4 替代 gzip)。

3.2 zImage 镜像结构:自解压头部与加载流程

zImage 是 ARM Linux 最常用的压缩内核格式。其头部包含一段自解压代码(decompressor stub),负责将压缩的内核主体解压到正确的运行地址。理解 zImage 的布局是优化加载间隙的前提。

zImage 加载地址规则: Bootloader 必须将 zImage 加载到 解压缓冲区地址(通常为 RAM 起始地址偏移 32 KB 处),而非最终运行地址。解压代码会自动将内核解压到 TEXT_OFFSET 指定的位置。
zImage 镜像结构:自解压头部与解压流程 zImage 镜像(压缩内核 + 自解压头部) 自解压头部(decompressor stub) 压缩内核主体(gzip / LZ4 / LZMA) Bootloader 加载到解压缓冲区 解压后的内核(Image)— 运行地址 自解压 DTB 设备树(加载到独立地址) Bootloader 传递 DTB 地址 解压缓冲区与运行地址不能重叠,否则解压时会覆盖自身,导致崩溃

3.3 加载地址与解压缓冲区规划

加载地址的选择直接影响解压过程的可靠性和速度。错误的地址重叠会导致内核解压时自我覆盖,造成启动失败。以下是地址规划的核心原则:

  • 解压缓冲区(Load Address): Bootloader 将 zImage 加载到 RAM 中一个临时区域。典型地址为 0x30008000(ARM 平台)或 0x80008000(ARM64 平台)。
  • 运行地址(Run Address): 解压后的内核 Image 最终运行的物理地址。由内核链接脚本中的 TEXT_OFFSET 决定,通常为 0x30008000 + 0x8000(32 KB 偏移)。
  • DTB 加载地址: 独立于内核镜像,通常加载到 0x48000000 或紧邻内核末尾的地址。Bootloader 通过寄存器(如 r2)将 DTB 地址传递给内核。
常见陷阱: 如果解压缓冲区与运行地址重叠,解压代码会逐步覆盖尚未解压的部分,导致 CRC 校验失败或解压异常。务必确保 Load Address + zImage Size < Run Address 或 Load Address > Run Address + Image Size。

3.4 解压过程:从 zImage 到 Image

zImage 的解压过程由内核头部自带的 decompressor stub 完成,Bootloader 只需跳转到加载地址即可。以下是解压的详细步骤:

  1. Bootloader 跳转: 设置 CPU 寄存器(r0=0, r1=machine type, r2=DTB 地址),跳转到 zImage 加载地址。
  2. 自解压头部执行: 检查 CPU 架构、缓存状态,初始化解压环境(如启用 MMU 临时映射)。
  3. 解压内核: 将压缩内核解压到运行地址。解压算法由内核配置决定(gzip、LZ4、LZMA 等)。
  4. 跳转到解压后的内核: 解压完成后,跳转到运行地址的入口点(stext 或 start_kernel)。
zImage 解压过程时序(从 Bootloader 跳转到内核入口) 时间 Bootloader 跳转 自解压头部初始化 解压内核主体 跳转到内核入口 ~1 µs ~10 µs 50–200 ms ~1 µs 解压耗时优化建议 • 使用 LZ4 解压算法:比 gzip 快 2–3 倍,但压缩率略低(约 5% 空间增加) • 启用内核预取(Prefetch):在解压时提前加载后续数据到缓存 • 如果 Flash 空间充足,直接使用 Image(未压缩)消除解压阶段

3.5 DTB 加载与传递机制

设备树(Device Tree)是现代 ARM 平台描述硬件配置的标准方式。Bootloader 必须将 DTB 加载到 RAM 中,并将地址通过寄存器传递给内核。DTB 的加载位置和完整性直接影响内核的硬件初始化。

  • 加载位置: DTB 通常加载到内核解压地址之后,或独立的固定地址(如 0x48000000)。必须确保 DTB 区域不会被内核解压覆盖。
  • 地址传递: ARM 平台通过 r2 寄存器传递 DTB 物理地址;ARM64 通过 x0 寄存器传递。Bootloader 必须在跳转前设置正确。
  • DTB 大小限制: 典型 DTB 大小为 10–200 KB,但复杂平台(如多核、多外设)可能超过 1 MB。Bootloader 需预留足够空间。
启动时序影响: DTB 加载本身耗时极短(< 1 ms),但 Bootloader 需要额外执行 DTB 的校验(CRC32)和可能的修补(如修改内存大小、MAC 地址)。这些操作应尽量精简,避免在启动关键路径上增加延迟。

3.6 本章小结