4. 内核编译基础:配置内核 .config 文件、编译内核与模块、编译设备树
在成功获取内核源码并安装交叉编译工具链后,下一步是配置内核、编译内核镜像与模块,以及生成设备树二进制文件(.dtb)。这是 DRM/KMS 驱动开发的基础操作,直接影响驱动能否正确加载与运行。
4.1 内核配置基础与 .config 文件
Linux 内核的编译行为由顶层 .config 文件控制。该文件记录了所有内核选项的开关状态(y 编译进内核、m 编译为模块、n 不编译)。对于 DRM/KMS 驱动开发,必须确保以下选项被正确启用:
| 配置选项 | 推荐值 | 说明 |
|---|---|---|
CONFIG_DRM |
y |
启用 DRM 核心框架 |
CONFIG_DRM_KMS_HELPER |
y |
启用 KMS 辅助层 |
CONFIG_DRM_XXX(具体驱动) |
y 或 m |
目标 SoC 的 DRM 驱动(如 CONFIG_DRM_IMX) |
CONFIG_FB |
n |
建议关闭传统 fbdev,避免与 DRM 冲突 |
CONFIG_OF |
y |
设备树支持,ARM/ARM64 平台必须 |
配置方法:推荐使用
make menuconfig 进行交互式配置。该命令基于 ncurses 提供图形化菜单,支持按 / 搜索选项,适合初学者和调试场景。
4.1.1 配置流程
- 加载默认配置:使用厂商提供的 defconfig,例如
make ARCH=arm imx_v7_defconfig。 - 定制配置:运行
make menuconfig ARCH=arm,进入Device Drivers → Graphics support路径,确认 DRM 相关选项。 - 保存配置:退出 menuconfig 时选择
Save,配置写入.config文件。 - 备份配置:将
.config复制为my_drm_defconfig,便于后续复用。
常见错误:直接修改
.config 文件而不运行 make olddefconfig 同步依赖,会导致编译时出现未定义的宏或选项冲突。修改后务必执行 make olddefconfig ARCH=arm。
4.2 编译内核与模块
内核编译分为两个主要产物:内核镜像(zImage/Image)和可加载模块(.ko)。DRM 驱动通常以模块形式编译,便于开发阶段快速迭代。
4.2.1 编译命令详解
# 编译内核镜像与所有模块
make -j$(nproc) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules
# 仅编译指定模块(加速调试)
make -j$(nproc) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- drivers/gpu/drm/imx/
# 安装模块到临时目录
make modules_install ARCH=arm INSTALL_MOD_PATH=./modules_install
| 参数 | 作用 |
|---|---|
-j$(nproc) |
并行编译,使用所有 CPU 核心 |
ARCH=arm |
指定目标架构 |
CROSS_COMPILE=... |
交叉编译工具链前缀 |
zImage |
编译压缩内核镜像(ARM 常用) |
modules |
编译所有标记为 m 的模块 |
4.2.2 编译流程示意图
4.3 编译设备树(Device Tree Blob)
设备树是 ARM/ARM64 平台描述硬件拓扑的标准方式。DRM/KMS 驱动通过设备树节点获取显示控制器、HDMI/DP 编码器、面板等外设的地址、中断、时钟和 GPIO 信息。编译设备树的命令为 make dtbs。
4.3.1 设备树编译命令
# 编译所有设备树
make dtbs ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-
# 编译单个设备树(加速调试)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- \
arch/arm/boot/dts/imx6q-sabresd.dtb
4.3.2 设备树与 DRM 驱动的关系
一个典型的 DRM 设备树节点包含以下关键属性:
/* imx6qdl.dtsi 中的 IPU 显示节点示例 */
&ipu1 {
compatible = "fsl,imx6q-ipu";
reg = <0x02400000 0x400000>;
interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>,
<0 5 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks IMX6QDL_CLK_IPU1>;
clock-names = "bus";
port@0 {
reg = <0>;
ipu1_di0: endpoint {
remote-endpoint = <&hdmi_mux_0>;
};
};
};
| 属性 | 作用 | DRM 驱动使用场景 |
|---|---|---|
compatible |
匹配驱动 | of_match_table 查找 |
reg |
寄存器地址范围 | devm_ioremap_resource |
interrupts |
中断号 | devm_request_irq |
clocks |
时钟源 | clk_get / clk_prepare_enable |
remote-endpoint |
显示管道连接 | drm_of_find_possible_crtcs |
4.3.3 设备树编译流程
4.4 编译产物验证
编译完成后,建议检查以下关键文件是否存在:
# 内核镜像
ls -lh arch/arm/boot/zImage
# 设备树
ls -lh arch/arm/boot/dts/imx6q-sabresd.dtb
# 模块(以 DRM 为例)
find drivers/gpu/drm/ -name "*.ko" | head -5
开发建议:在 DRM 驱动开发阶段,建议将驱动编译为模块(
m),配合 insmod/rmmod 快速迭代。每次修改驱动源码后,只需重新编译对应模块并复制到目标板,无需重新烧写内核镜像。
4.5 常见编译错误与解决
| 错误现象 | 原因 | 解决方法 |
|---|---|---|
*** No rule to make target 'zImage' |
ARCH 未设置或错误 | 检查 ARCH=arm 是否正确 |
undefined reference to `drm_atomic_helper_xxx' |
CONFIG_DRM_KMS_HELPER 未开启 | 启用 CONFIG_DRM_KMS_HELPER=y |
Error: unrecognized/unsupported machine ID |
设备树未正确编译或未加载 | 确认 make dtbs 成功,检查 U-Boot 加载地址 |
multiple definition of `xxx' |
同一符号被多次编译 | 检查 Makefile 是否重复添加源文件 |