3. 设备树源文件(.dts)结构:/dts-v1/、根节点、aliases节点、chosen节点、memory节点

设备树源文件(.dts)是描述硬件拓扑结构的文本文件,经过设备树编译器(DTC)编译后生成二进制的设备树二进制(.dtb)文件。一个标准的 .dts 文件由版本标识、根节点以及若干特殊子节点构成。本章将深入剖析这些核心组成部分。

实战要点: 在嵌入式Linux开发中,.dts 文件是硬件与软件之间的“契约”。理解其结构是编写正确设备树、驱动能够正确匹配硬件外设的前提。

3.1 版本标识:/dts-v1/

每个合法的 .dts 文件必须以版本标识字符串开头。目前,所有新开发的设备树文件都应使用 /dts-v1/ 版本。

// 设备树源文件的标准开头
/dts-v1/;

/ {
    // 根节点内容
};

该标识告诉编译器按照 v1 版本的设备树规范解析后续内容。如果缺少此标识,编译器可能会报错或使用过时的解析规则,导致生成的 .dtb 文件无法被内核正确识别。

版本演进: 早期设备树规范存在 v0 版本,但已被废弃。/dts-v1/ 是当前唯一被广泛支持的版本标识,所有主流内核(如 Linux 4.x/5.x/6.x)均要求此标识。

3.2 根节点(Root Node)

根节点是设备树的顶层节点,用斜杠 / 表示。整个硬件系统的所有设备、总线和属性都挂载在根节点之下。根节点本身通常包含 model 和 compatible 属性,用于标识整个板卡或系统。

/dts-v1/;

/ {
    model = "TI AM335x BeagleBone Black";
    compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";

    // 子节点:CPU、内存、外设等
};
属性 描述 示例值
model 描述板卡型号的字符串,用于用户空间识别 "TI AM335x BeagleBone Black"
compatible 用于操作系统匹配驱动,按从具体到通用的顺序排列 "ti,am335x-bone-black", "ti,am33xx"
常见错误: 根节点内的 compatible 属性顺序非常重要。内核会从列表的第一个字符串开始匹配,如果找不到对应驱动,才会尝试下一个。务必把最具体的板级型号放在最前面。

3.3 aliases 节点

aliases 节点是一个特殊的子节点,用于为设备树中的其他节点定义简短的别名。这些别名通常用于引导加载程序(如 U-Boot)或内核在早期启动阶段快速定位关键设备。

/ {
    aliases {
        serial0 = &uart0;
        serial1 = &uart1;
        mmc0 = &mmc1;
        i2c0 = &i2c0;
        ethernet0 = &cpsw_emac0;
    };

    // 其他节点
};

别名的格式为 名称 = &节点引用;。通过 & 符号引用已定义的节点标签。常见的别名包括 serial0、mmc0、i2c0 等,它们使得在命令行或脚本中引用设备更加直观。

实战技巧: 在 U-Boot 中,可以通过 fdt set 命令动态修改 aliases 节点,从而改变系统启动时控制台或根文件系统的设备映射。

3.4 chosen 节点

chosen 节点不描述任何硬件设备,而是用于传递操作系统启动时的运行时参数。它由引导加载程序在启动内核前填充,内核在启动过程中读取该节点获取配置信息。

/ {
    chosen {
        bootargs = "console=ttyO0,115200 root=/dev/mmcblk0p2 rw rootfstype=ext4";
        stdout-path = &uart0;
    };
};
属性 作用 典型值
bootargs 传递给内核的命令行参数,类似传统 ATAG 方式 "console=ttyS0,115200 root=/dev/nfs"
stdout-path 指定系统早期启动时的控制台输出设备 &uart0
initrd-start 初始 RAM 磁盘(initrd)在内存中的起始地址 0x82000000
关键区别: chosen 节点是动态的,其内容由引导加载程序在每次启动时根据用户配置或硬件状态生成;而 aliases 节点通常是静态的,在 .dts 文件中预先定义好。

3.5 memory 节点

memory 节点用于描述系统的物理内存布局,包括内存的起始地址和大小。在大多数现代嵌入式系统中,内存信息由引导加载程序动态探测并填充,因此 .dts 文件中可能只包含一个占位符或空节点。

/ {
    // 方式一:静态定义(适用于内存固定的系统)
    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x20000000>;  // 起始地址 0x80000000,大小 512MB
    };

    // 方式二:动态填充(引导加载程序负责填充 reg 属性)
    memory {
        device_type = "memory";
        // reg 属性由 U-Boot 在启动时写入
    };
};

reg 属性是一个 <地址 长度> 对,可以包含多个地址范围来描述非连续的内存区域。

注意事项: 如果 memory 节点缺失或 reg 属性错误,内核将无法正确管理物理内存,导致系统崩溃或无法启动。在调试启动问题时,应首先检查 memory 节点的内容是否正确。

3.6 整体结构关系图

下图展示了 .dts 文件中各核心节点之间的层级关系与数据流向:

.dts 文件核心结构关系图 根节点 / aliases 节点 chosen 节点 memory 节点 各节点作用说明 • aliases:为关键设备定义简短别名,便于引导加载程序引用 • chosen:传递启动参数(bootargs、stdout-path),由引导加载程序动态填充 • memory:描述物理内存布局,引导加载程序可动态修改 reg 属性

3.7 节点属性与值格式

设备树中的每个节点都可以包含多个属性,属性值支持多种数据类型。下表总结了常见的属性值格式:

数据类型 语法 示例 说明
字符串 "string" model = "BeagleBone Black"; 单个字符串
字符串列表 "str1", "str2" compatible = "ti,am33xx", "ti,omap"; 逗号分隔的多个字符串
32位整数 <value> reg = <0x80000000 0x20000000>; 尖括号内包含一个或多个32位值
64位整数 <0x00000000 0x80000000> reg = <0x00000000 0x80000000 0x00000000 0x20000000>; 使用两个32位单元表示64位地址
字节数组 [hex bytes] local-mac-address = [00 11 22 33 44 55]; 方括号内为十六进制字节序列
布尔值 属性存在即为真 status = "disabled"; 或 status = "okay"; 通过属性存在与否或特定字符串表示

3.8 实战案例:最小完整 .dts 文件

以下是一个包含本章所有核心节点的最小完整 .dts 文件示例:

/dts-v1/;

/ {
    model = "Example ARM Cortex-A9 Board";
    compatible = "example,cortex-a9-board", "example,cortex-a9";

    aliases {
        serial0 = &uart0;
        mmc0 = &mmc;
    };

    chosen {
        bootargs = "console=ttyAMA0,115200 root=/dev/mmcblk0p2 rw";
        stdout-path = &uart0;
    };

    memory@80000000 {
        device_type = "memory";
        reg = <0x80000000 0x10000000>;  // 256MB 内存
    };

    // 外设节点示例
    uart0: uart@10000000 {
        compatible = "arm,pl011";
        reg = <0x10000000 0x1000>;
        interrupts = <0 5 4>;
        status = "okay";
    };

    mmc: mmc@20000000 {
        compatible = "arm,pl180";
        reg = <0x20000000 0x1000>;
        interrupts = <0 6 4>;
        status = "okay";
    };
};
总结: 掌握 /dts-v1/、根节点、aliases、chosen 和 memory 节点是理解设备树源文件结构的基础。这些节点共同构成了硬件描述的核心骨架,为后续的外设节点配置和驱动开发奠定了坚实基础。