Rust设备树解析库fdt的使用,高效处理Flattened Device Tree数据结构
Rust设备树解析库fdt的使用,高效处理Flattened Device Tree数据结构
安装
在项目目录中运行以下Cargo命令:
cargo add fdt
或者在Cargo.toml中添加以下行:
fdt = "0.1.5"
基本使用示例
下面是一个使用fdt库解析设备树的基本示例:
use fdt::Fdt;
fn main() {
// 假设我们有一个设备树二进制数据
let dtb_data = include_bytes!("path/to/device_tree.dtb");
// 解析设备树
let fdt = Fdt::new(dtb_data).expect("Failed to parse device tree");
// 获取根节点
let root = fdt.root();
// 遍历所有子节点
for node in root.children() {
println!("Found node: {}", node.name);
// 遍历节点属性
for prop in node.properties() {
println!(" Property: {} ({} bytes)", prop.name, prop.value.len());
}
}
// 查找特定节点
if let Some(uart_node) = fdt.find_node("/soc/uart@10000000") {
println!("Found UART node");
// 获取特定属性值
if let Some(reg) = uart_node.property("reg") {
println!("UART registers at {:?}", reg.value);
}
}
}
完整示例代码
下面是一个更完整的示例,展示了如何使用fdt库处理设备树数据:
use fdt::Fdt;
fn main() {
// 加载设备树二进制数据
let dtb_data = include_bytes!("path/to/device_tree.dtb");
// 解析设备树
match Fdt::new(dtb_data) {
Ok(fdt) => {
// 打印设备树基本信息
println!("Device tree version: {}", fdt.version());
println!("Total size: {} bytes", fdt.total_size());
// 处理内存节点
if let Some(memory_node) = fdt.find_node("/memory") {
println!("\nMemory information:");
// 获取内存区域
if let Some(reg) = memory_node.property("reg") {
let regions = reg.as_reg().unwrap();
for (i, region) in regions.enumerate() {
println!(" Region {}: start={:#x}, size={:#x}",
i, region.starting_address, region.size.unwrap_or(0));
}
}
}
// 处理CPU节点
println!("\nCPU information:");
for cpu_node in fdt.find_all_nodes("/cpus/cpu@*") {
println!("Found CPU: {}", cpu_node.name);
// 获取CPU兼容性信息
if let Some(compatible) = cpu_node.property("compatible") {
println!(" Compatible: {}", compatible.as_str().unwrap());
}
// 获取CPU时钟频率
if let Some(clock_freq) = cpu_node.property("clock-frequency") {
let freq = clock_freq.as_u32().unwrap();
println!(" Clock frequency: {} MHz", freq / 1_000_000);
}
}
// 处理中断控制器
if let Some(intc_node) = fdt.find_node("/intc") {
println!("\nInterrupt controller:");
println!(" Compatible: {}",
intc_node.property("compatible").unwrap().as_str().unwrap());
// 获取中断号
if let Some(interrupts) = intc_node.property("interrupts") {
println!(" Interrupts: {:?}", interrupts.value);
}
}
},
Err(e) => eprintln!("Failed to parse device tree: {}", e),
}
}
高级用法
use fdt::{Fdt, standard_nodes::Compatible};
fn enumerate_devices(fdt: &Fdt) {
// 查找所有兼容特定驱动的设备
for node in fdt.find_all_nodes("/soc/*") {
if let Some(compatible) = node.property("compatible") {
if compatible.as_str().unwrap().contains("usb") {
println!("Found USB device at {}", node.name);
// 获取设备地址
if let Some(reg) = node.property("reg") {
let regions = reg.as_reg().unwrap();
for region in regions {
println!(" Base address: {:#x}", region.starting_address);
}
}
// 获取中断信息
if let Some(interrupts) = node.property("interrupts") {
println!(" Interrupts: {:?}", interrupts.value);
}
}
}
}
}
fn check_compatibility(fdt: &Fdt) -> bool {
// 检查设备树是否与我们的系统兼容
let root = fdt.root();
// 检查兼容性字符串
if let Some(compatible) = root.property("compatible") {
let comp = Compatible::new(compatible);
if comp.matches("my-company,my-board") {
return true;
}
}
false
}
完整示例demo
下面是一个综合性的设备树解析示例,展示了fdt库的核心功能:
use fdt::{Fdt, standard_nodes::Compatible};
fn main() {
// 加载设备树数据
let dtb_data = include_bytes!("path/to/device_tree.dtb");
// 解析设备树
let fdt = match Fdt::new(dtb_data) {
Ok(fdt) => fdt,
Err(e) => {
eprintln!("设备树解析失败: {}", e);
return;
}
};
// 1. 打印设备树基本信息
println!("=== 设备树基本信息 ===");
println!("版本: {}", fdt.version());
println!("总大小: {} 字节", fdt.total_size());
// 2. 检查兼容性
println!("\n=== 兼容性检查 ===");
if check_compatibility(&fdt) {
println!("设备树与系统兼容");
} else {
println!("设备树与系统不兼容");
}
// 3. 枚举所有设备
println!("\n=== 设备枚举 ===");
enumerate_devices(&fdt);
// 4. 详细内存信息
println!("\n=== 内存信息 ===");
if let Some(memory_node) = fdt.find_node("/memory") {
if let Some(reg) = memory_node.property("reg") {
let regions = reg.as_reg().unwrap();
for (i, region) in regions.enumerate() {
println!("内存区域 {}: 起始地址={:#x}, 大小={:#x}",
i, region.starting_address, region.size.unwrap_or(0));
}
}
}
}
// 检查设备树兼容性
fn check_compatibility(fdt: &Fdt) -> bool {
let root = fdt.root();
if let Some(compatible) = root.property("compatible") {
let comp = Compatible::new(compatible);
comp.matches("my-company,my-board")
} else {
false
}
}
// 枚举所有设备
fn enumerate_devices(fdt: &Fdt) {
// 遍历所有节点
for node in fdt.all_nodes() {
println!("设备节点: {}", node.name);
// 打印所有属性
for prop in node.properties() {
println!(" 属性: {} ({}字节)", prop.name, prop.value.len());
}
// 特殊处理有reg属性的设备
if let Some(reg) = node.property("reg") {
if let Ok(regions) = reg.as_reg() {
for (i, region) in regions.enumerate() {
println!(" 寄存器区域 {}: 地址={:#x}, 大小={:#x}",
i, region.starting_address, region.size.unwrap_or(0));
}
}
}
// 特殊处理中断属性
if let Some(interrupts) = node.property("interrupts") {
println!(" 中断信息: {:?}", interrupts.value);
}
}
}
注意事项
- fdt库支持no_std环境,适合嵌入式开发
- 设备树二进制数据必须正确对齐
- 解析时要注意处理可能的错误情况
- 属性值的解释需要根据设备树绑定规范进行
这个库提供了高效的方式来解析和处理Flattened Device Tree数据结构,特别适合嵌入式系统开发和裸机编程场景。
1 回复
Rust设备树解析库fdt的使用指南
概述
fdt
是一个用于解析和处理Flattened Device Tree (FDT)数据的Rust库。设备树是嵌入式系统中常用的硬件描述机制,用于描述系统硬件配置而不需要硬编码。这个库提供了高效、安全的方式来访问和操作设备树数据。
安装
在Cargo.toml中添加依赖:
[dependencies]
fdt = "0.3"
基本使用方法
1. 加载设备树
use fdt::Fdt;
// 从字节切片加载设备树
let dtb = include_bytes!("path/to/your.dtb");
let fdt = Fdt::new(dtb).expect("Failed to parse device tree");
2. 遍历节点
// 获取根节点
let root = fdt.root();
// 遍历所有子节点
for node in root.children() {
println!("Node: {}", node.name);
// 遍历节点的属性
for prop in node.properties() {
println!(" Property: {} = {:?}", prop.name, prop.value);
}
}
3. 查找特定节点
// 通过路径查找节点
if let Some(uart_node) = fdt.find_node("/soc/serial@40001000") {
println!("Found UART node: {}", uart_node.name);
// 获取特定属性
if let Some(reg) = uart_node.property("reg") {
println!("Register info: {:?}", reg.value);
}
}
高级功能
1. 处理地址信息
use fdt::standard_nodes::MemoryRegion;
// 获取内存信息
for mem in fdt.memory().regions() {
println!("Memory region: {:#x} - {:#x}", mem.starting_address, mem.size);
}
2. 处理中断信息
if let Some(intc) = fdt.find_node("/intc") {
if let Some(interrupts) = intc.property("interrupts") {
println!("Interrupt info: {:?}", interrupts.as_cells());
}
}
3. 处理兼容性信息
// 查找所有兼容特定驱动的设备
for node in fdt.all_nodes() {
if let Some(compatible) = node.property("compatible") {
if compatible.as_str().contains("arm,pl011") {
println!("Found PL011 UART at {}", node.name);
}
}
}
实用示例
获取CPU信息
for cpu in fdt.cpus() {
println!("CPU {}: {}", cpu.id, cpu.name);
if let Some(clock_freq) = cpu.property("clock-frequency").and_then(|p| p.as_u32()) {
println!(" Clock frequency: {} Hz", clock_freq);
}
}
解析设备树到自定义结构
struct DeviceInfo {
name: String,
address: u64,
size: u64,
interrupts: Vec<u32>,
}
fn parse_device(fdt: &Fdt, path: &str) -> Option<DeviceInfo> {
let node = fdt.find_node(path)?;
let reg = node.reg()?.next()?;
let mut interrupts = Vec::new();
if let Some(interrupts_prop) = node.property("interrupts") {
interrupts.extend(interrupts_prop.as_cells().iter().copied());
}
Some(DeviceInfo {
name: node.name.to_string(),
address: reg.starting_address,
size: reg.size.unwrap_or(0),
interrupts,
})
}
完整示例代码
use fdt::{Fdt, standard_nodes::MemoryRegion};
fn main() {
// 1. 加载设备树
let dtb = include_bytes!("path/to/your.dtb");
let fdt = Fdt::new(dtb).expect("Failed to parse device tree");
// 2. 遍历所有节点
println!("=== 遍历所有节点 ===");
let root = fdt.root();
for node in root.children() {
println!("节点: {}", node.name);
for prop in node.properties() {
println!(" 属性: {} = {:?}", prop.name, prop.value);
}
}
// 3. 查找特定节点
println!("\n=== 查找UART节点 ===");
if let Some(uart_node) = fdt.find_node("/soc/serial@40001000") {
println!("找到UART节点: {}", uart_node.name);
if let Some(reg) = uart_node.property("reg") {
println!("寄存器信息: {:?}", reg.value);
}
}
// 4. 处理内存信息
println!("\n=== 内存区域 ===");
for mem in fdt.memory().regions() {
println!("内存区域: {:#x} - {:#x}", mem.starting_address, mem.size);
}
// 5. 获取CPU信息
println!("\n=== CPU信息 ===");
for cpu in fdt.cpus() {
println!("CPU {}: {}", cpu.id, cpu.name);
if let Some(clock_freq) = cpu.property("clock-frequency").and_then(|p| p.as_u32()) {
println!(" 时钟频率: {} Hz", clock_freq);
}
}
// 6. 解析到自定义结构
println!("\n=== 自定义设备解析 ===");
if let Some(device) = parse_device(&fdt, "/soc/serial@40001000") {
println!("设备信息:");
println!(" 名称: {}", device.name);
println!(" 地址: {:#x}", device.address);
println!(" 大小: {:#x}", device.size);
println!(" 中断: {:?}", device.interrupts);
}
}
// 自定义设备信息结构
struct DeviceInfo {
name: String,
address: u64,
size: u64,
interrupts: Vec<u32>,
}
// 解析设备到自定义结构
fn parse_device(fdt: &Fdt, path: &str) -> Option<DeviceInfo> {
let node = fdt.find_node(path)?;
let reg = node.reg()?.next()?;
let mut interrupts = Vec::new();
if let Some(interrupts_prop) = node.property("interrupts") {
interrupts.extend(interrupts_prop.as_cells().iter().copied());
}
Some(DeviceInfo {
name: node.name.to_string(),
address: reg.starting_address,
size: reg.size.unwrap_or(0),
interrupts,
})
}
注意事项
- 设备树数据通常由系统提供,确保你有正确的设备树二进制(dtb)文件
- 处理属性时要考虑字节序问题,设备树通常使用大端序
- 某些属性可能有特定格式,需要参考设备树规范进行解析
fdt
库提供了安全、符合Rust习惯的方式来处理设备树数据,避免了直接操作原始指针带来的风险,同时保持了高性能。