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 指定的位置。
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 只需跳转到加载地址即可。以下是解压的详细步骤:
- Bootloader 跳转: 设置 CPU 寄存器(r0=0, r1=machine type, r2=DTB 地址),跳转到 zImage 加载地址。
- 自解压头部执行: 检查 CPU 架构、缓存状态,初始化解压环境(如启用 MMU 临时映射)。
- 解压内核: 将压缩内核解压到运行地址。解压算法由内核配置决定(gzip、LZ4、LZMA 等)。
- 跳转到解压后的内核: 解压完成后,跳转到运行地址的入口点(stext 或 start_kernel)。
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 地址)。这些操作应尽量精简,避免在启动关键路径上增加延迟。