当前位置:

首页 > 编程开发 > c++如何读取Linux内核生成的Device Tree二进制流【深度】

c++如何读取Linux内核生成的Device Tree二进制流【深度】

C++如何读取Linux内核生成的Device Tree二进制流【深度】 Linux用户态如何解析内核加载的dtb文件 内核启动时加载的dtb(Device Tree Blob)文件,在系统运行后通常已经被解压并转换成了内核内部的结构体(比如struct device_node)。这里有个关键点:*

本文目录

    C++如何读取Linux内核生成的Device Tree二进制流【深度】

    c++如何读取Linux内核生成的Device Tree二进制流【深度】

    Linux用户态如何解析内核加载的dtb文件

    内核启动时加载的dtb(Device Tree Blob)文件,在系统运行后通常已经被解压并转换成了内核内部的结构体(比如struct device_node)。这里有个关键点:**用户态程序是无法直接访问这些内核内存数据的**。所以,如果你想在用户空间读取设备树的内容,就得换个思路,从源头找起。无非两条路:要么去读取启动时传入的那个原始dtb二进制文件本身,要么就利用内核已经为我们准备好的一个接口——/proc/device-tree这个伪文件系统。

    一个常见的误区是,试图用mmap去映射/sys/firmware/devicetree/base或者/proc/device-tree下的某个文件。这行不通。这些文件是特殊的只读文件,没有传统意义上的“长度”,你用stat()去查,会发现st_size返回0。正确的姿势是使用read()系统调用来读取内容。

    • /proc/device-tree是首选方案:它以目录树的形式直观地暴露了所有设备树节点和属性。你不需要自己解析任何二进制格式,直接按文件操作就行,而且兼容性很好(主流内核版本>=3.10都支持)。
    • 如果确实需要原始的dtb文件(比如为了做签名验证或者离线分析),那就得确认你的启动环境里是否还保留着这个文件。它可能存在于U-Boot的环境变量fdt_addr_r指向的内存地址,也可能被打包进了initramfs里(例如放在/dtb路径下)。
    • 尽量不要依赖/sys/firmware/devicetree/base:在某些ARM64平台上它可能不可见,而且部分Linux发行版默认并不会挂载这个路径。

    用C++递归遍历/proc/device-tree提取节点信息

    这是最轻量、也最可靠的方法。逻辑很直观:/proc/device-tree下的每一个子目录,就对应设备树里的一个节点(device node);而目录里的每一个普通文件,则对应一个属性(property),文件的内容就是这个属性的值(注意,内容里可能包含'\0'字符,所以必须用read(),不能用fgets这类字符串函数)。

    操作起来有几个关键点:

    立即学习“C++免费学习笔记(深入)”;

    • 使用opendir()和readdir()来遍历目录,记得跳过“.”和“..”这两个特殊条目。
    • 对每个条目调用stat()来判断其类型:如果是目录(S_ISDIR()),就递归进入,处理子节点;如果是普通文件(S_ISREG()),就读取其内容作为属性值。
    • 属性值的末尾并不自动附加'\0',其真实长度需要通过stat()得到的st_size来获取。对于字符串类属性(比如compatible),其内容本身会以'\0'结尾;但对于二进制属性(比如reg),它就是原始的字节流。
    • 设备树路径可能很深,为了输出清晰,建议用栈结构或者递归来控制缩进显示,避免在代码里硬编码层级限制。

    来看一个简单的代码片段,演示如何读取/proc/device-tree/cpus/cpu@0/compatible这个属性:

    int fd = open("/proc/device-tree/cpus/cpu@0/compatible", O_RDONLY);
    struct stat st;
    fstat(fd, &st);
    std::vector buf(st.st_size);
    read(fd, buf.data(), st.st_size);
    // 此时,buf[0]...buf[st.st_size-1] 就是原始的属性值字节
    close(fd);

    用libfdt解析原始dtb文件(需链接libfdt)

    当你不得不处理原始的dtb二进制文件时(例如从Flash存储中直接dump出来,或者需要与内核启动参数进行一致性校验),libfdt库就成了事实上的标准工具。它被dtc(设备树编译器)、u-boot等广泛使用,头文件是,所有函数都有统一的fdt_前缀。

    典型的解析流程是这样的:

    • 首先,用fdt_open_into()或fdt_load()这样的函数,将完整的dtb文件加载到内存中。这里要特别注意:你提供的dtb数据必须是完整且未被截断的二进制流。
    • 接着,可以使用fdt_first_subnode()和fdt_next_subnode()这对组合来遍历设备树的子节点。
    • 读取属性则使用fdt_getprop()函数。它返回一个指向dtb内部缓冲区的指针,**这个指针绝对不能手动free,并且它的生命周期完全依赖于fdt blob本身的有效性**。属性的实际长度会通过一个输出参数(lenp)传回。

    使用libfdt时,有几个容易踩坑的地方:

    • 在进行任何其他操作之前,必须先调用fdt_check_header()来校验dtb头的合法性,否则一个非法的dtb文件很可能导致程序段错误(Segmentation Fault)。
    • fdt结构体本身并不管理内存,所以承载dtb数据的那个缓冲区(buffer)在整个使用周期内都必须保持有效,不能是栈上的临时变量,也不能被realloc这类操作移动。
    • 如果在多线程环境下使用,需要自行加锁,因为libfdt本身不是线程安全的,同一个fdt实例不能支持并发访问。

    为什么不用libdevicetree或自己写解析器

    或许有人会问,有没有其他库,或者干脆自己写一个解析器?答案是,通常不建议。

    libdevicetree这类非主流的库,往往缺乏持续维护,API可能不稳定。而自己动手写一个解析器,风险则非常高。dtb的二进制格式包含了magic number、总长度、结构体偏移量、字符串表偏移量等多个字段,并且存在版本差异(如v17/v18)、对齐要求(通常是8字节)、以及复杂的字符串表引用机制。即便你跳过了严格的校验,仅仅是想正确识别节点和属性的边界,也极易发生数组越界读取的错误。

    在真实的开发场景中,大约95%的需求,通过/proc/device-tree这个接口就能完美解决。剩下的那5%,比如进行bootloader调试或者固件签名校验,才是libfdt的用武之地。如果非要绕过这两条成熟路径,大概率会在自己实现的fdt_next_tag()循环里卡住,或者读出一堆乱码。

    说到底,真正有挑战性的从来不是“怎么把数据读出来”这个动作,而是搞清楚你需要的数据究竟在哪一层:是启动时传给内核的原始硬件描述,还是内核解析后生成的运行时视图,又或者是驱动实际看到的platform_device资源?这三者的语义各不相同,绝对不能混为一谈。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Linux C++
    相关文章 更多
    linux删除用户与用户组的方法及命令教程
    linux删除用户与用户组的方法及命令教程

    掌握Linux中删除用户和用户组的正确方法,避免残留文件和进程冲突。本文深入解析userdel和groupdel命令的参数用法,提供处理“用户仍在使用”等常见错误的实战方案。

    Linux如何开启端口号?开放端口命令详解
    Linux如何开启端口号?开放端口命令详解

    详细讲解Linux如何开启端口号以及常用的开放端口命令。

    crossover卸载软件下载及重新安装教程
    crossover卸载软件下载及重新安装教程

    遇到CrossOver运行错误或需要更新版本时,如何彻底卸载旧版并干净重装?本教程详解macOS和Linux下的卸载步骤、残留文件清理方法及官方下载渠道,确保软件环境纯净稳定。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。