Linux设备树数据结构概述

Linux设备树数据结构及内核解析

1.linux 设备树相关的数据结构

Linux设备树(Device Tree)是一种描述硬件配置的树形数据结构,通过节点(Node)和属性(Property)的层级关系,抽象化表示CPU、内存、总线、外设等硬件信息。其核心数据结构及实现逻辑如下:

一、设备树节点(Device Tree Node)

设备树由节点构成,每个节点表示一个硬件设备或逻辑组件。节点可嵌套子节点,形成树状结构。

1. 节点结构
  • 节点命名:格式为node-name@unit-address,其中node-name为设备类型(如cpui2c),unit-address为设备地址(可选)。
  • 根节点:唯一根节点/,描述整个系统信息(如compatible属性定义硬件平台)。
  • 子节点:例如CPU节点、内存节点、外设节点等。
2. 内核表示

在Linux内核中,节点通过struct device_node表示,关键字段包括:

  • name: 节点名称。
  • parent: 父节点指针。
  • child: 子节点链表。
  • properties: 属性链表(struct property)。
  • full_name: 节点完整路径(如/soc/i2c@021a0000)。

二、属性(Property)

属性是键值对,描述节点配置信息。属性值可以是字符串、整数、字节数组等。

1. 标准属性示例
  • compatible:驱动匹配关键属性,格式为"厂商,型号"(如compatible = "fsl,imx6ull-gpmi-nand")。
  • reg:设备地址及长度,格式为<address length>,受父节点#address-cells#size-cells影响。
  • interrupts:中断号及触发方式(如interrupts = <0 2 4>表示IRQ 0,边沿触发)。
  • status:设备状态("okay"启用,"disabled"禁用)。
2. 自定义属性

用户可定义任意属性(如custom-data = <0x12 0x34>),驱动通过of_property_read_u32_array等API读取。

3. 内核表示

属性通过struct property表示,关键字段包括:

  • name: 属性名。
  • length: 属性值长度。
  • value: 属性值指针(字节数组)。

三、设备树二进制格式(DTB)

设备树源文件(.dts)编译为二进制文件(.dtb),内核启动时解析。DTB结构包括:

  1. Header:魔数(0xd00dfeed)、总大小、结构块偏移等。
  2. Structure Block:线性化节点数据,包含节点开始/结束标记、属性数据。
  3. Strings Block:所有属性名的字符串表,通过偏移量引用。

四、内核解析流程

  1. Bootloader传递:U-Boot将DTB加载到内存,通过寄存器(如ARM的r2)传递地址给内核。
  2. 解压与校验:内核验证DTB完整性,解压为内存中的设备树结构。
  3. 遍历与初始化
    • 使用of_find_node_by_pathof_get_property等API遍历节点和属性。
    • 根据compatible属性匹配驱动,调用probe函数初始化设备。

五、关键数据结构关系图

设备树结构
├─ / (根节点)
│  ├─ compatible = "vendor,platform"
│  └─ memory@80000000
│     ├─ device_type = "memory"
│     └─ reg = <0x80000000 0x40000000>
├─ soc (SoC节点)
│  ├─ #address-cells = <1>
│  ├─ #size-cells = <1>
│  └─ i2c@021a0000
│     ├─ compatible = "fsl,imx6q-i2c"
│     └─ reg = <0x021a0000 0x4000>
└─ chosen (启动参数节点)
   └─ bootargs = "console=ttyS0,115200"

六、操作API示例

#include <linux/of.h>

// 查找节点
struct device_node *np = of_find_node_by_path("/soc/i2c@021a0000");

// 读取属性
const u32 *reg;
u32 reg_len;
of_property_read_u32_array(np, "reg", reg, &reg_len);

// 遍历子节点
for_each_child_of_node(np, child) {
    // 处理子节点
}

总结

设备树通过节点和属性抽象硬件,内核通过struct device_nodestruct property解析配置,实现驱动与硬件解耦。这种设计使得同一内核支持多硬件平台,无需修改内核代码,仅需更换设备树文件。

2.设备树相关的结构体 

Linux设备树(Device Tree)通过一组核心数据结构抽象硬件配置,使内核与硬件解耦。以下是其关键结构体及作用详解:

一、核心结构体:struct device_node

表示设备树中的一个节点,描述一个硬件设备或逻辑组件。

字段解析

字段说明示例
name节点名称(不含@unit-addresscpui2c
type设备类型memoryserial
full_name节点完整路径/soc/i2c@021a0000
properties属性链表指针存储compatiblereg等属性
parent/child/sibling树形结构指针用于遍历父子/兄弟节点
phandle唯一句柄用于跨节点引用(如中断控制器)
内核操作
  • 解析函数__unflatten_device_tree() 将DTB解析为device_node树。
  • 遍历API
     

    struct device_node *child = NULL;
    for_each_child_of_node(parent_node, child) {
        // 遍历子节点
    }

二、属性结构体:struct property

描述设备树节点的配置信息(键值对)。

字段解析

字段说明示例值
name属性名compatiblereg
value属性值(字节数组)"fsl,imx6ull-gpmi-nand"<0x80000000 0x40000000>
length属性值长度strlen("fsl,imx6ull-gpmi-nand")
标准属性示例
  • compatible:驱动匹配关键属性,格式为"厂商,型号"
  • reg:设备地址及长度,受父节点#address-cells#size-cells影响。
  • interrupts:中断号及触发方式(如<0 2 4>表示IRQ 0,边沿触发)。
API操作

// 读取属性值
const u32 *reg_val;
u32 reg_len;
of_property_read_u32_array(np, "reg", reg_val, &reg_len);


// 读取字符串属性
const char *model;
of_property_read_string(np, "model", &model);

三、通用硬件节点标识符:struct fwnode_handle

抽象设备树节点,支持跨硬件描述接口(如ACPI)操作。

应用场景
  • 在驱动中动态获取硬件配置(如SPI/GPIO参数),无需硬编码内核。
  • 示例:通过fwnode_handle获取I2C控制器地址。

四、设备树二进制格式(DTB)结构

内核启动时解析的二进制格式,包含以下部分:

  1. Header
    • 魔数(0xd00dfeed)、总大小、结构块偏移等。
  2. Structure Block
    • 线性化节点数据,包含节点开始/结束标记(OF_DT_BEGIN_NODE/OF_DT_END_NODE)。
    • 属性数据格式:[属性值长度][属性名偏移][属性值]
  3. Strings Block
    • 存储所有属性名的字符串表,通过偏移量引用。

五、内核解析流程

  1. Bootloader传递
    U-Boot将DTB加载到内存,地址通过寄存器(如ARM的r2)传递给内核。

  2. 解压与校验
    内核验证DTB完整性,解压为内存中的设备树结构。

  3. 遍历与初始化

    • 使用of_find_node_by_pathof_get_property等API遍历节点和属性。
    • 根据compatible属性匹配驱动,调用probe函数初始化设备。

六、代码示例

#include <linux/of.h>

// 查找I2C控制器节点
struct device_node *i2c_node = of_find_node_by_path("/soc/i2c@021a0000");

// 读取reg属性
const u32 *reg;
u32 reg_len;
of_property_read_u32_array(i2c_node, "reg", reg, &reg_len);

// 遍历子节点(如I2C设备)
struct device_node *child;
for_each_child_of_node(i2c_node, child) {
    // 处理子节点(如传感器、EEPROM)
}

总结

设备树通过struct device_nodestruct property抽象硬件,内核通过解析DTB构建树形结构,驱动通过compatible属性匹配并初始化设备。struct fwnode_handle提供跨硬件接口的抽象能力,增强代码复用性。此设计使同一内核支持多硬件平台,无需修改内核代码,仅需更换设备树文件。

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值