2. 内核编译基础:获取Linux内核源码、配置内核(make menuconfig)、编译内核(make bzImage)、编译设备树(dtbs)

内核编译是嵌入式开发和内核调试的起点。只有掌握了从源码获取到生成可执行镜像的完整链路,才能在后续章节中精准定位启动异常。本章聚焦于四个核心步骤:获取源码、配置内核、编译内核、编译设备树。

2.1 获取Linux内核源码

获取内核源码有三种主流方式,根据使用场景选择合适的方法:

方式 命令/示例 适用场景 特点
主线发布版 wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.tar.xz 标准开发、学习 稳定、经过广泛测试
Git 克隆 git clone --depth=1 https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 跟踪最新主线、贡献补丁 可获取完整历史,--depth=1 减少下载量
发行版源码包 apt-get source linux-image-$(uname -r) 基于当前系统配置编译 包含发行版特定补丁和配置
建议: 对于本课程,推荐使用 git clone --depth=1 获取最新稳定主线,既能保证代码新鲜度,又能节省磁盘空间和下载时间。

解压或克隆完成后,进入源码根目录:

cd linux-6.6
# 或
cd linux

2.2 配置内核(make menuconfig)

内核配置决定了哪些功能、驱动和特性被编译进内核。配置系统基于 Kconfig(Kernel Configuration)语言,提供多种配置界面。

2.2.1 配置界面选择

命令 界面类型 依赖 推荐场景
make menuconfig 文本菜单(ncurses) libncurses-dev SSH 远程、无图形环境
make xconfig 图形界面(Qt) qtbase5-dev 本地桌面环境,搜索方便
make nconfig 文本菜单(ncurses 增强) libncurses-dev 比 menuconfig 更快的搜索
make defconfig 默认配置(无交互) 无 快速生成基础配置

2.2.2 配置操作流程

  1. 清理旧配置(可选):make mrproper
  2. 生成默认配置:make defconfig 或 make ARCH=arm64 defconfig
  3. 启动菜单配置:make menuconfig
  4. 保存退出:选择 Save,默认保存为 .config
关键操作: 在 menuconfig 界面中,使用 / 键可以搜索配置项名称或描述,支持模糊匹配。例如搜索 EXT4 可以快速定位文件系统相关选项。

2.2.3 配置项三态

符号 含义 编译结果
[*] 或 y 编译进内核(built-in) 直接链接到 vmlinux
[M] 或 m 编译为模块(module) 生成 .ko 文件,动态加载
[ ] 或 n 不编译 完全排除
调试提示: 在调试启动异常时,建议将关键驱动(如串口、存储控制器)设置为 [*] 编译进内核,避免因模块加载失败导致无法输出调试信息。

2.3 编译内核(make bzImage)

bzImage 是 x86 架构下压缩后的内核镜像,也是 QEMU 调试中最常用的内核格式。对于 ARM64 架构,对应的是 Image 或 Image.gz。

2.3.1 编译命令

# x86 架构
make bzImage -j$(nproc)

# ARM64 架构
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image -j$(nproc)

参数说明:

  • -j$(nproc):并行编译,使用所有 CPU 核心加速。
  • CROSS_COMPILE=:交叉编译工具链前缀,仅跨平台编译时需要。
  • ARCH=:指定目标架构,如 x86_64、arm64、arm。

2.3.2 编译产物

文件 路径 说明
vmlinux 源码根目录 未压缩的原始内核,包含调试符号
bzImage arch/x86/boot/bzImage x86 压缩内核镜像,QEMU 直接加载
Image arch/arm64/boot/Image ARM64 未压缩内核镜像
System.map 源码根目录 符号地址映射表,调试辅助
调试技巧: 保留 vmlinux 文件,它包含完整的调试符号(DWARF 信息),GDB 调试时必须使用 vmlinux 而非 bzImage。

2.4 编译设备树(dtbs)

设备树(Device Tree)是描述硬件拓扑和资源的数据结构,在 ARM、RISC-V 等非 x86 架构中替代了传统的 ACPI 或硬编码板级文件。QEMU 模拟的 virt 平台、vexpress 平台都需要设备树来告知内核硬件布局。

2.4.1 设备树编译命令

# 编译所有设备树
make dtbs

# 编译指定设备树(以 ARM64 virt 平台为例)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- dtbs

# 编译单个设备树文件
make ARCH=arm64 qemu-virt.dtb

2.4.2 设备树文件类型

扩展名 格式 说明
.dts Device Tree Source 可读的文本源文件
.dtsi Device Tree Source Include 公共头文件,被 .dts 包含
.dtb Device Tree Blob 编译后的二进制文件,QEMU 加载
.dtbo Device Tree Blob Overlay 运行时覆盖片段

2.4.3 设备树在 QEMU 中的使用

QEMU 启动时通过 -dtb 参数指定设备树文件:

qemu-system-aarch64 \
  -machine virt \
  -cpu cortex-a57 \
  -kernel arch/arm64/boot/Image \
  -dtb arch/arm64/boot/dts/qemu/qemu-virt.dtb \
  -append "console=ttyAMA0" \
  -nographic
常见错误: 如果 QEMU 启动后内核无任何输出,首先检查是否提供了正确的 -dtb 文件。缺少设备树或设备树与机器类型不匹配,会导致内核无法识别串口、内存等基础硬件,从而完全静默。

2.5 内核编译与设备树关系总览

下图展示了从源码到 QEMU 启动镜像的完整编译链路:

内核编译与设备树关系总览 内核编译与设备树关系总览 Linux 内核源码 设备树源文件 (.dts) make menuconfig .config 配置文件 make bzImage make dtbs bzImage / Image .dtb 设备树二进制 QEMU 启动 -kernel bzImage -dtb board.dtb 调试关键文件 vmlinux(含符号) + .dtb(硬件描述)

2.6 常见编译错误与解决

错误信息 原因 解决方案
ncurses development packages not found 缺少 ncurses 库 sudo apt install libncurses-dev
No rule to make target 'debian/certs/signing_key.pem' 模块签名证书缺失 make modules_prepare 或关闭 CONFIG_MODULE_SIG
arch/arm64/Makefile: No such file or directory ARCH 参数错误 检查 ARCH=arm64 拼写,确认源码支持该架构
Kernel: arch/x86/boot/bzImage is ready 但 QEMU 无法启动 设备树缺失或不匹配 使用 -dtb 参数指定正确的 .dtb 文件

2.7 本章小结

  • 获取源码:推荐 git clone --depth=1 获取最新主线。
  • 配置内核:make menuconfig 是远程调试的首选配置方式,注意三态选择对调试的影响。
  • 编译内核:make bzImage -j$(nproc) 生成压缩内核镜像,保留 vmlinux 用于 GDB 调试。
  • 编译设备树:make dtbs 生成 .dtb 文件,QEMU 启动时必须通过 -dtb 参数加载。
  • 调试准备:确保 vmlinux、bzImage、.dtb 三个文件齐全且版本一致。