3. 设备树编译器:DTC(Device Tree Compiler)的使用方法

设备树源文件(.dts)是给人阅读和编辑的文本格式,而内核引导时实际加载的是二进制设备树 Blob(.dtb)。DTC(Device Tree Compiler)就是完成这一转换的核心工具。本章将系统讲解 DTC 的安装、编译、反编译以及常见调试技巧。

核心概念: DTC 是设备树生态的“翻译官”,负责将人类可读的 .dts 转换为机器可解析的 .dtb,同时支持反向还原,是驱动开发调试中不可或缺的瑞士军刀。

3.1 DTC 工具链安装与验证

DTC 通常包含在 device-tree-compiler 软件包中。不同发行版的安装命令如下:

发行版 安装命令 验证命令
Ubuntu / Debian sudo apt install device-tree-compiler dtc --version
Fedora / RHEL sudo dnf install dtc dtc --version
Arch Linux sudo pacman -S dtc dtc --version
Yocto / Buildroot 默认包含在 host-utils 中 dtc -v
提示: 如果系统未安装,也可以从内核源码的 scripts/dtc/ 目录下直接编译使用:make scripts/dtc/dtc。

3.2 从 .dts 编译为 .dtb

编译是最常用的操作。基本语法如下:

dtc -I dts -O dtb -o output.dtb input.dts

参数说明:

  • -I dts:指定输入格式为设备树源文件(.dts)。
  • -O dtb:指定输出格式为设备树二进制 Blob(.dtb)。
  • -o output.dtb:指定输出文件名。
  • input.dts:输入的源文件。

实战示例: 假设我们有一个简单的设备树源文件 myboard.dts:

/dts-v1/;

/ {
    compatible = "myboard,devkit";
    #address-cells = <1>;
    #size-cells = <1>;

    uart0: serial@10000000 {
        compatible = "ns16550";
        reg = <0x10000000 0x1000>;
        interrupts = <0 33 4>;
        clock-frequency = <24000000>;
    };
};

执行编译命令:

dtc -I dts -O dtb -o myboard.dtb myboard.dts

编译成功后,会生成 myboard.dtb 文件。可以使用 hexdump 或 strings 查看其二进制内容:

hexdump -C myboard.dtb | head -20
strings myboard.dtb
常见错误: 如果 .dts 文件中引用了 .dtsi 头文件(如 #include "soc.dtsi"),编译时需确保头文件路径正确,或使用 -i 参数指定搜索路径:dtc -I dts -O dtb -i ./include -o output.dtb input.dts。

3.3 从 .dtb 反编译为 .dts

反编译用于调试、逆向分析或从现有系统中提取设备树配置。基本语法:

dtc -I dtb -O dts -o output.dts input.dtb

参数说明:

  • -I dtb:指定输入格式为二进制设备树。
  • -O dts:指定输出格式为源文件。
  • -o output.dts:输出反编译后的源文件。

实战示例: 将上一节编译出的 myboard.dtb 反编译:

dtc -I dtb -O dts -o myboard_recovered.dts myboard.dtb

查看反编译结果:

cat myboard_recovered.dts

输出应基本还原原始 .dts 内容,但节点顺序和注释可能会丢失。

实用技巧: 在嵌入式 Linux 开发板上,可以通过 /sys/firmware/fdt 获取当前内核使用的设备树二进制文件:cp /sys/firmware/fdt /tmp/current.dtb,然后反编译分析实际生效的设备树配置。

3.4 DTC 编译与反编译流程 SVG 图

下图展示了 DTC 在设备树开发中的核心工作流:

DTC 编译与反编译工作流 .dts 源文件 (人类可读文本) DTC 编译 -I dts -O dtb .dtb 二进制文件 (机器可解析) DTC 反编译 -I dtb -O dts .dts 还原文件 (用于调试分析) 💡 编译用于内核加载,反编译用于调试和逆向分析现有系统 常用选项:-I 指定输入格式,-O 指定输出格式,-o 指定输出文件,-i 指定头文件搜索路径

3.5 常用编译选项详解

DTC 提供了丰富的选项来控制编译行为,下表列出了最常用的参数:

选项 全称 功能说明 示例
-I Input format 指定输入文件格式:dts、dtb、fs(文件系统) -I dts
-O Output format 指定输出文件格式:dts、dtb、asm(汇编) -O dtb
-o Output file 指定输出文件名 -o board.dtb
-i Include path 添加头文件搜索路径(可多次使用) -i ./include
-@ Symbols 生成符号节点(用于设备树叠加层) -@
-H Phandle format 指定 phandle 格式:legacy、epapr -H epapr
-W Warning 启用特定警告(如 -W unit_address_vs_reg) -W no-unit_address_vs_reg
-E Error 将警告升级为错误 -E unit_address_vs_reg

3.6 编译检查与调试

DTC 在编译时会进行语法和语义检查,常见警告及处理方法如下:

  • unit_address_vs_reg:节点名中的地址与 reg 属性不匹配。检查节点命名规范,如 serial@10000000 应与 reg = <0x10000000 ...> 一致。
  • avoid_unnecessary_addr_size:根节点不必要地定义了 #address-cells 和 #size-cells。如果子节点没有 reg 属性,可以移除。
  • graph_child_address:图形相关节点地址格式错误。检查 ports、endpoint 等节点的 reg 属性。
  • interrupt_provider:中断控制器节点缺少 #interrupt-cells 属性。确保中断控制器节点正确声明。
调试技巧: 使用 -W no-xxx 可以临时屏蔽特定警告,但建议在开发阶段保持所有警告可见。使用 -E xxx 可将特定警告升级为错误,强制修复问题。

3.7 设备树叠加层(DT Overlay)编译

设备树叠加层(.dtbo)用于运行时动态修改设备树,常用于 FPGA 配置、外设热插拔等场景。编译叠加层需要添加 -@ 选项:

dtc -I dts -O dtb -@ -o overlay.dtbo overlay.dts

叠加层源文件示例:

/dts-v1/;
/plugin/;

/ {
    fragment@0 {
        target = &uart0;
        __overlay__ {
            status = "okay";
            baud-rate = <115200>;
        };
    };
};

编译后生成 overlay.dtbo,可通过内核的 configfs 接口动态加载:

mkdir /sys/kernel/config/device-tree/overlays/my_overlay
cat overlay.dtbo > /sys/kernel/config/device-tree/overlays/my_overlay/dtbo

3.8 实战:完整编译与反编译流程

以下是一个完整的实战流程,涵盖从编写到验证的全过程:

  1. 编写源文件:创建 myboard.dts,包含必要的节点和属性。
  2. 编译为 .dtb:dtc -I dts -O dtb -o myboard.dtb myboard.dts
  3. 检查编译结果:dtc -I dtb -O dts myboard.dtb 快速查看内容。
  4. 反编译验证:dtc -I dtb -O dts -o myboard_check.dts myboard.dtb
  5. 对比差异:diff myboard.dts myboard_check.dts 确认还原度。
  6. 生成叠加层:dtc -I dts -O dtb -@ -o myboard.dtbo myboard_overlay.dts
最佳实践: 在版本控制中同时保存 .dts 和 .dtsi 源文件,.dtb 作为构建产物不纳入仓库。每次修改后执行编译+反编译双重验证,确保设备树语义正确。

3.9 本章小结

DTC 是设备树开发的核心工具,掌握其编译与反编译操作是驱动开发的基本功。通过本章学习,你应该能够:

  • 独立完成 .dts 到 .dtb 的编译。
  • 从现有 .dtb 反编译出可读的 .dts 用于调试。
  • 理解常用编译选项的含义和适用场景。
  • 处理常见的编译警告和错误。
  • 编译设备树叠加层用于动态配置。