首页 游戏 软件 资讯 排行榜 专题
首页
编程语言
c++如何读取Linux内核生成的Device Tree二进制流【深度】

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

热心网友
13
转载
2026-05-06

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

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

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

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

Linux内核在启动过程中会加载并解析dtb(设备树二进制)文件,将其转换为内部数据结构(如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数据的缓冲区在整个使用周期内都必须保持有效,不能是栈上的临时变量,也不能被realloc等操作移动。
  • 若在多线程环境下使用,需自行加锁,因为libfdt本身并非线程安全,同一fdt实例不支持并发访问。

为何不推荐使用libdevicetree或自行编写解析器

或许有人会问,是否存在其他库,或者是否可以自行编写解析器?通常不建议这样做。

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

在实际开发中,大约95%的需求通过/proc/device-tree接口即可完美解决。剩余的5%场景,如bootloader调试或固件签名校验,才是libfdt的用武之地。若非要绕过这两条成熟路径,很可能在自行实现的fdt_next_tag()循环中陷入困境,或读取到乱码数据。

归根结底,真正的挑战并非“如何读取数据”这一动作,而是明确所需数据究竟位于哪一层:是启动时传给内核的原始硬件描述,还是内核解析后生成的运行时视图,亦或是驱动实际看到的platform_device资源?这三者的语义截然不同,绝不能混为一谈。

来源:https://www.php.cn/faq/2320694.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

C++如何控制YAML输出时的块模式与流模式_SetMapFormat用法【进阶】
编程语言
C++如何控制YAML输出时的块模式与流模式_SetMapFormat用法【进阶】

C++如何控制YAML输出时的块模式与流模式_SetMapFormat用法【进阶】 YAML-CPP 中 SetMapFormat 不控制块 流模式 首先需要明确一个关键点:SetMapFormat 函数本身并不直接控制YAML文档的块(Block)或流(Flow)显示样式。它的核心功能是调整 st

热心网友
05.06
c++如何处理文件读取过程中的非法UTF8编码_异常容错【避坑】
编程语言
c++如何处理文件读取过程中的非法UTF8编码_异常容错【避坑】

C++文件读取中非法UTF-8编码的异常处理与容错方案【避坑指南】 遇到 std::invalid_argument 或乱码时,先别急着抛出异常 许多C++开发者在控制台看到 std::invalid_argument 异常时,第一反应是文件读取操作本身出现了问题。实际上,这里存在一个普遍的误解:标

热心网友
05.06
C++ std::any_of/all_of/none_of _ 逻辑条件判定算法【详解】
编程语言
C++ std::any_of/all_of/none_of _ 逻辑条件判定算法【详解】

C++ std::any_of all_of none_of:逻辑条件判定算法【详解】 开门见山,先说一个核心结论:std::all_of、std::any_of、std::none_of 这三个算法,绝非简单的“语法糖”。它们看似直观,但其内部的短路求值逻辑、对空容器的特殊处理以及谓词的调用时机,

热心网友
05.06
C++ std::execution并行算法 _ C++17多线程优化sort【干货】
编程语言
C++ std::execution并行算法 _ C++17多线程优化sort【干货】

C++ std::execution并行算法深度解析 | C++17多线程优化sort性能实战指南 你是否认为,只需简单调用 std::sort(std::execution::par, begin, end) 就能让程序性能飙升?现实往往更为复杂。许多开发者发现,代码执行后CPU占用率并未提升,耗

热心网友
05.06
c++如何读取Linux内核生成的Device Tree二进制流【深度】
编程语言
c++如何读取Linux内核生成的Device Tree二进制流【深度】

C++如何读取Linux内核生成的Device Tree二进制流【深度】 Linux用户态如何解析内核加载的dtb文件 Linux内核在启动过程中会加载并解析dtb(设备树二进制)文件,将其转换为内部数据结构(如struct device_node)。一个关键限制是:**用户态程序无法直接访问内核内

热心网友
05.06

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

荣耀400pro关机要按几秒
电脑教程
荣耀400pro关机要按几秒

荣耀400 Pro正确关机全指南:从常规操作到故障应对详解 需要关闭您的荣耀400 Pro手机?日常操作其实非常简便。只需长按位于机身右侧的电源键约3秒钟,屏幕上便会浮现一个简洁的半透明菜单,其中明确列出了“关机”、“重启”以及“紧急呼叫”选项。直接点击“关机”,系统将启动一次10秒的安全倒计时,随

热心网友
05.06
红米K30Pro如何拆后盖胶怎么清理
电脑教程
红米K30Pro如何拆后盖胶怎么清理

红米K30 Pro后盖拆解教程:专业工具与细致手法的完美结合 红米K30 Pro的后盖采用了高强度背胶配合隐藏式螺丝的双重固定设计,想要实现无损拆解,绝非依靠蛮力可以完成。整个操作流程对加热温度、撬启手法以及清洁标准都有严格要求,任何环节的疏忽都可能导致部件损伤。具体而言,其后盖边缘使用了耐高温的工

热心网友
05.06
三星zflip电池百分比需要root吗
电脑教程
三星zflip电池百分比需要root吗

无需Root权限:三星Galaxy Z Flip系列电量数字显示设置全解析 很多三星折叠屏手机用户都想知道,如何在状态栏直接查看精确的电池百分比数字,是否必须获取Root权限才能实现?实际上完全不需要。三星自Galaxy Z Flip 5、Z Flip 4等主流机型开始,已在系统层面内置了这一实用功

热心网友
05.06
笔记本开机自检时能看到DDR3或DDR4吗
电脑教程
笔记本开机自检时能看到DDR3或DDR4吗

笔记本开机自检信息虽不直接标注“DDR3”或“DDR4”,但联想、戴尔、华硕等品牌BIOS画面常以“PC3-”或“PC4-”编码间接揭示内存代际。UEFI自检显示的内存频率(如2400MHz 3200MHz)结合JEDEC规范可辅助推断:PC3对应DDR3,PC4对应DDR4。更高精度的识别方案包括

热心网友
05.06
空调制冷但不太凉是压缩机问题吗?
电脑教程
空调制冷但不太凉是压缩机问题吗?

空调制冷不足怎么办?先别急着维修压缩机,这些问题更常见 夏天开空调却感觉不够凉爽?很多朋友的第一反应是压缩机坏了,其实压缩机故障的概率相对较低。根据维修行业的大数据统计,绝大多数制冷效果不佳的情况,源于几个容易被忽略的日常维护与环境因素。滤网积尘、制冷剂泄漏、外机散热不良才是真正的高发原因。盲目更换

热心网友
05.06