Linux驱动配置:驱动移植与设备树实例工程实践 - 第1节

1.1 交叉编译工具链安装

嵌入式Linux开发与桌面开发最大的区别在于交叉编译。目标板(ARM/RISC-V/MIPS)资源有限,无法直接运行本地编译器,因此需要在性能强大的宿主机(x86_64)上安装交叉编译工具链,生成目标架构的可执行文件。

1.1.1 工具链获取方式

方式 适用场景 典型命令/路径
发行版包管理器 快速验证、通用ARM平台 sudo apt install gcc-arm-linux-gnueabihf
芯片厂商SDK 量产项目、特定SoC优化 NXP Yocto / TI Processor SDK
Linaro预编译包 ARMv7/ARMv8标准工具链 gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
Buildroot/Yocto自编译 深度定制、全系统构建 make toolchain

1.1.2 安装步骤(以Linaro ARM工具链为例)

  1. 下载工具链压缩包到 /opt/toolchains/ 目录。
  2. 解压并确认路径:
cd /opt/toolchains/
sudo tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
ls gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin/
# 应看到 arm-linux-gnueabihf-gcc, arm-linux-gnueabihf-ld 等文件
  1. 将工具链加入 PATH 环境变量(建议写入 ~/.bashrc):
export PATH=/opt/toolchains/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin:$PATH
  1. 验证安装:
arm-linux-gnueabihf-gcc --version
# 输出应显示版本号,如 "arm-linux-gnueabihf-gcc (Linaro GCC 7.5-2019.12)"
提示: 交叉编译工具链的命名规则为 arch-vendor-os-abi。例如 arm-linux-gnueabihf 表示 ARM 架构、Linux 系统、使用硬浮点 ABI。选择错误的工具链会导致内核编译失败或运行时崩溃。

1.2 内核源码获取与解压

Linux内核源码可以从 kernel.org 官方仓库或芯片厂商提供的定制内核仓库获取。本课程使用长期支持版本(LTS)进行实践。

1.2.1 源码获取方式对比

方式 命令/操作 优点 缺点
wget 下载压缩包 wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.38.tar.xz 稳定、可校验哈希 下载大文件较慢
git 克隆主线仓库 git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 可切换分支、增量更新 首次克隆数据量大
厂商BSP源码包 从NXP/TI/ST官网获取 包含板级配置和补丁 版本可能滞后

1.2.2 解压与目录结构

tar -xvf linux-6.1.38.tar.xz -C ~/workspace/
cd ~/workspace/linux-6.1.38/
ls -F

解压后,内核源码顶层目录包含以下关键子目录:

  • arch/ — 体系结构相关代码(arm64, x86, riscv 等)
  • drivers/ — 设备驱动代码(char, net, i2c, spi 等)
  • include/ — 内核头文件
  • Documentation/ — 内核文档(设备树绑定、API说明)
  • scripts/ — 编译脚本、设备树编译工具
实践要点: 建议在 ~/workspace/ 下建立 linux-<version> 目录,并创建软链接 linux 指向当前工作版本,方便多版本切换。

1.3 内核配置(menuconfig)

内核配置是决定哪些功能、驱动被编译进内核的关键步骤。menuconfig 是基于 ncurses 的图形化配置界面,是嵌入式开发中最常用的配置方式。

1.3.1 配置流程

  1. 加载默认配置(以 ARM64 为例):
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
  1. 启动图形化配置界面:
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
  1. 在界面中导航:
  • 方向键 — 上下移动
  • Enter — 进入子菜单
  • Y — 编译进内核(built-in)
  • M — 编译为模块(module)
  • N — 不编译
  • ? — 查看帮助
  1. 保存退出,生成 .config 文件。

1.3.2 配置项分类

配置类型 示例 说明
bool CONFIG_ARM64 Y/N 二选一
tristate CONFIG_I2C_DESIGNWARE Y/M/N 三选一(驱动常用)
int CONFIG_HZ 输入整数值
string CONFIG_DEFAULT_HOSTNAME 输入字符串
常见错误: 直接修改 .config 文件而不执行 menuconfig 或 oldconfig,会导致依赖关系不一致,编译时出现 undefined reference 或 implicit declaration 错误。务必使用 make oldconfig 更新依赖。

1.4 内核编译流程

配置完成后,执行编译命令生成内核镜像(Image/zImage)和设备树二进制文件(.dtb)。

1.4.1 编译命令详解

# 编译内核镜像(ARM64 生成 Image)
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) Image

# 编译设备树
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) dtbs

# 编译内核模块
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) modules

# 安装模块到目标目录
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=~/rootfs modules_install

1.4.2 编译产物清单

文件 路径 说明
Image arch/arm64/boot/Image 未压缩的内核镜像(ARM64)
zImage arch/arm/boot/zImage 压缩的内核镜像(ARM32)
*.dtb arch/arm64/boot/dts/<vendor>/ 编译后的设备树二进制文件
vmlinux 源码根目录 未压缩的ELF格式内核(调试用)
System.map 源码根目录 内核符号表

1.5 完整编译流程SVG架构图

下图展示了从源码获取到生成最终烧录镜像的完整编译流水线:

Linux内核编译完整流程 Linux内核编译完整流程 1. 源码获取 2. 内核配置 3. 编译构建 kernel.org 厂商BSP defconfig menuconfig make Image make dtbs 编译输出产物 Image / zImage *.dtb 设备树 内核模块 (.ko) vmlinux + System.map 烧录到目标板启动

1.6 常见编译问题与排查

错误现象 根本原因 解决方案
arm-linux-gnueabihf-gcc: command not found 工具链未加入 PATH 检查 export PATH 是否生效,或使用绝对路径
*** Can't find default configuration "arch/arm64/configs/defconfig" ARCH 或 CROSS_COMPILE 设置错误 确认目标架构,ARM64 使用 ARCH=arm64
undefined reference to `__aeabi_uidiv' 工具链 ABI 不匹配(软浮点 vs 硬浮点) 使用 gnueabihf 工具链,或配置 CONFIG_AEABI
Kernel panic - not syncing: VFS: Unable to mount root fs 根文件系统驱动未编译进内核 确保 CONFIG_EXT4_FS 等文件系统驱动为 built-in
调试技巧: 编译时添加 V=1 参数(如 make V=1)可输出完整编译命令,便于定位头文件路径、链接顺序等问题。首次编译建议使用 make -j1 观察完整输出,确认无误后再启用多核并行编译。

1.7 本章小结

本章完成了嵌入式Linux内核编译环境的完整搭建:

  • 安装交叉编译工具链并验证其可用性
  • 获取并解压内核源码,熟悉顶层目录结构
  • 使用 menuconfig 进行内核功能配置
  • 执行编译命令生成内核镜像、设备树和模块
  • 掌握常见编译错误的排查方法