如何进行Linux设备树传递及Kernel对设备树分析

发布时间:2022-01-20 17:52:51 作者:kk
来源:亿速云 阅读:645
# 如何进行Linux设备树传递及Kernel对设备树分析

## 1. 设备树技术背景

### 1.1 设备树的起源与发展

设备树(Device Tree)最初由Open Firmware提出,用于描述硬件配置信息。随着Linux在嵌入式领域的广泛应用,传统的"硬编码"硬件描述方式暴露出严重问题:

1. 每个板级支持包(BSP)都需要单独维护
2. 内核镜像需要为不同硬件重新编译
3. 硬件变更导致大量代码修改

设备树通过将硬件描述与内核代码分离,实现了:
- **硬件描述标准化**:采用.dts文本格式描述硬件
- **平台无关性**:同一内核镜像可支持多种硬件
- **维护便利性**:硬件变更只需修改设备树文件

### 1.2 设备树在ARM体系中的采用

2011年后,ARM社区正式采用设备树作为标准硬件描述方法。主要推动因素包括:

- ARM架构变种繁多(如Cortex-A/R/M系列)
- 同一SoC在不同板卡上外设配置不同
- 嵌入式系统对快速启动的需求

典型应用场景:
```dts
// 示例:描述UART控制器
uart0: serial@101f1000 {
    compatible = "arm,pl011";
    reg = <0x101f1000 0x1000>;
    interrupts = <0 12 4>;
};

2. 设备树数据传递机制

2.1 Bootloader到内核的传递流程

2.1.1 传统传递方式(ATAGS)

在设备树普及前,ARM Linux使用ATAGS(ARM Tagged List)传递参数: - 通过寄存器r2传递物理地址 - 包含内存大小、命令行参数等基本信息 - 无法描述复杂硬件拓扑

2.1.2 设备树传递方式(DTB)

现代Bootloader(如U-Boot)使用更先进的DTB传递: 1. Bootloader加载DTB到内存 2. 通过寄存器r2传递DTB物理地址 3. 内核通过early_init_dt_scan()解析

关键数据结构对比:

特性 ATAGS DTB
扩展性 有限 强(树形结构)
硬件描述能力 仅基础参数 完整硬件拓扑
维护成本 需修改内核代码 仅修改DTB文件

2.2 设备树二进制格式解析

DTB文件由四部分组成:

  1. Header:包含魔数、版本等信息
struct fdt_header {
    uint32_t magic;         // 0xd00dfeed
    uint32_t totalsize;
    uint32_t off_dt_struct;
    uint32_t off_dt_strings;
    uint32_t off_mem_rsvmap;
    uint32_t version;
    uint32_t last_comp_version;
    // ...
};
  1. Memory Reserve Map:保留内存区域列表

  2. Structure Block:设备树结构主体,采用嵌套标记:

    • FDT_BEGIN_NODE (0x00000001)
    • FDT_END_NODE (0x00000002)
    • FDT_PROP (0x00000003)
    • FDT_END (0x00000009)
  3. Strings Block:属性名字符串池

2.3 典型Bootloader实现分析

以U-Boot为例的关键步骤:

  1. 加载阶段:
int fdt_chosen(void *fdt) {
    int nodeoffset;
    char *str;

    nodeoffset = fdt_add_subnode(fdt, 0, "chosen");
    fdt_setprop(fdt, nodeoffset, "bootargs", str, strlen(str)+1);
}
  1. 传递设置:
// ARMv7启动代码片段
ldr r0, =0x10000000   // DTB物理地址
ldr r1, =0x10000      // DTB大小
mov r2, #0            | 机器ID(已弃用)

3. Linux内核设备树处理机制

3.1 早期初始化流程

内核启动阶段的关键函数调用链:

  1. start_kernel()setup_arch()setup_machine_fdt()
  2. unflatten_device_tree():将DTB转换为内核数据结构
  3. of_platform_populate():创建设备节点

内存转换过程:

DTB二进制 → device_node结构体 → platform_device

3.2 设备节点到平台设备的转换

内核通过以下步骤完成转换:

  1. 扫描设备树根节点
const struct of_device_id matches[] = {
    { .compatible = "simple-bus", },
    { /* sentinel */ }
};
of_platform_populate(NULL, matches, NULL, NULL);
  1. 为每个兼容节点创建platform_device:
struct platform_device *pdev;
pdev = of_device_alloc(np, bus_id, parent);
if (pdev)
    of_device_add(pdev);
  1. 资源映射处理:
struct resource res;
of_address_to_resource(np, 0, &res);
platform_device_add_resources(pdev, &res, 1);

3.3 设备树与驱动匹配机制

驱动匹配的核心是compatible属性:

  1. 驱动声明匹配表:
static const struct of_device_id mydrv_match[] = {
    { .compatible = "vendor,device-123" },
    {}
};
MODULE_DEVICE_TABLE(of, mydrv_match);
  1. 平台驱动注册:
struct platform_driver mydrv = {
    .probe = mydrv_probe,
    .driver = {
        .name = "mydrv",
        .of_match_table = mydrv_match,
    },
};
  1. 内核匹配过程:
of_device_is_compatible() → driver_match_device() → probe()

4. 高级设备树技术解析

4.1 设备树覆盖(Overlay)技术

动态设备树修改实现原理:

  1. 基础DTB加载后,应用叠加片段:
fdtoverlay -i base.dtb -o final.dtb overlay1.dtbo overlay2.dtbo
  1. 内核支持机制:
int of_overlay_fdt_apply(void *fdt, u32 fdt_size);
  1. 典型应用场景:

4.2 设备树调试技巧

4.2.1 运行时查看

通过/sys文件系统访问设备树:

# 查看完整设备树
cat /sys/firmware/devicetree/base/compatible

# 查看特定节点属性
ls /sys/firmware/devicetree/base/soc/

4.2.2 内核调试选项

关键配置选项:

CONFIG_DEBUG_FS=y
CONFIG_OF_DEBUG=y
CONFIG_OF_OVERLAY=y

常用调试函数:

of_print_phandle_args(const struct of_phandle_args *args);
of_node_full_name(const struct device_node *np);

4.3 设备树与ACPI的协同

在x86/ARM混合架构下的处理策略:

  1. 检测顺序:
if (acpi_disabled)
    setup_device_tree();
else
    acpi_boot_table_init();
  1. 优先规则:

5. 实践案例分析

5.1 Raspberry Pi设备树解析

树莓派4B的典型设备树结构:

  1. 核心节点:
/ {
    compatible = "raspberrypi,4-model-b";
    memory@0 {
        device_type = "memory";
        reg = <0 0x40000000>;
    };

    soc {
        ranges = <0x7e000000 0xfe000000 0x1000000>;
        gpio@7e200000 {
            compatible = "brcm,bcm2711-gpio";
            reg = <0x7e200000 0xb4>;
        };
    };
};
  1. 启动日志分析:
[    0.000000] OF: fdt: Machine model: Raspberry Pi 4 Model B
[    0.000000] OF: reserved mem: initialized node linux,cma

5.2 自定义设备树开发

添加新设备的完整流程:

  1. 编写DTS片段:
/ {
    my_device {
        compatible = "custom,mydev";
        reg = <0x12340000 0x1000>;
        interrupts = <0 45 4>;
        status = "okay";
    };
};
  1. 编译验证:
dtc -I dts -O dtb -o mydev.dtbo mydev.dts
fdtdump mydev.dtbo  # 验证二进制内容
  1. 内核驱动匹配:
static int mydev_probe(struct platform_device *pdev)
{
    struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    void __iomem *base = devm_ioremap_resource(&pdev->dev, res);
    // ...
}

6. 性能优化与最佳实践

6.1 设备树优化技巧

  1. 结构优化原则:
  1. 大小优化方法:
dtc -@ -Hepapr -O dtb -o reduced.dtb -Wno-unit_address_vs_reg input.dts

6.2 常见问题解决方案

6.2.1 启动失败排查

典型错误处理流程: 1. 检查内核日志:

[    0.000000] OF: bad range /soc/usb@7e980000
  1. 使用-dump-dtb参数保存实际使用的DTB
  2. 反编译验证:
dtc -I dtb -O dts dumped.dtb > debug.dts

6.2.2 资源冲突处理

识别方法:

cat /proc/iomem
cat /proc/interrupts

设备树解决方案:

/delete-node/ &conflicting_node;

7. 未来发展趋势

7.1 设备树标准演进

最新规范发展: - Devicetree Specification v0.4新增特性: - 条件包含(#ifdef样式语法) - 增强类型系统 - 更严格的验证规则

7.2 与其它技术的融合

  1. 设备树与虚拟化:
  1. 异构计算支持:
accelerator {
    compatible = "opencl,accelerator";
    method = "pci";
    regions = <&fpga_region 0>;
};

结论

Linux设备树技术通过将硬件描述与内核代码解耦,显著提高了嵌入式系统的灵活性和可维护性。本文详细分析了从Bootloader传递DTB到内核解析的完整流程,深入探讨了设备节点到平台设备的转换机制,并给出了实际开发中的优化建议。随着Specification的持续演进,设备树将继续作为ARM体系结构的标准硬件描述方法,并在异构计算、虚拟化等新兴领域发挥更重要作用。

附录

A. 常用工具链

B. 参考文档

  1. Devicetree Specification v0.4
  2. Linux内核文档:Documentation/devicetree/
  3. U-Boot设备树处理源码:common/fdt_support.c

”`

推荐阅读:
  1. 芯灵思Sinlinx A64 linux 通过设备树写LED
  2. 关于linux ARM device tree设备树

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux kernel

上一篇:win10取消粘滞键的方法是什么

下一篇:css怎么实现禁止文字被选择

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》