| Crates.io | device_tree_parser |
| lib.rs | device_tree_parser |
| version | 0.4.0 |
| created_at | 2025-06-30 20:48:51.602158+00 |
| updated_at | 2025-07-01 00:45:33.731707+00 |
| description | High-performance Device Tree Blob (DTB) parser with zero-copy parsing and ergonomic APIs for embedded systems |
| homepage | https://github.com/iainh/device_tree_parser |
| repository | https://github.com/iainh/device_tree_parser |
| max_upload_size | |
| id | 1732356 |
| size | 1,319,823 |
A Rust library for parsing device tree files, supporting both binary Device Tree Blob (DTB) format and device tree source files. This library is designed for embedded systems and provides no_std compatibility with alloc support.
Index traits for property and child access: node["property"], node[0]IntoIterator for natural iteration: for child in &nodeTryFrom for type-safe value conversions: u32::try_from(&value)Display for pretty-printing nodes and propertiesNodeIteratorAdd this to your Cargo.toml:
[dependencies]
device_tree_parser = "0.4.0"
use device_tree_parser::{DeviceTreeParser, DtbHeader};
// Load your DTB data
let dtb_data = std::fs::read("path/to/your.dtb")?;
// Create a parser
let parser = DeviceTreeParser::new(&dtb_data);
// Parse the header
let (_remaining, header) = DtbHeader::parse(&dtb_data)?;
println!("DTB Version: {}", header.version());
use device_tree_parser::{DeviceTreeParser, NodeIterator};
let dtb_data = std::fs::read("your.dtb")?;
let parser = DeviceTreeParser::new(&dtb_data);
// Parse the device tree
let tree = parser.parse_tree()?;
// Iterate through child nodes using ergonomic IntoIterator trait
for child in &tree {
println!("Node: {}", child.name);
// Access properties using Index trait
if child.has_property("reg") {
println!(" Register: {}", child["reg"].value);
}
// Type-safe property value conversion using TryFrom
if let Some(prop) = child.find_property("reg") {
if let Ok(values) = Vec::<u32>::try_from(&prop.value) {
println!(" Register values: {:?}", values);
}
}
}
use std::convert::TryFrom;
use device_tree_parser::DeviceTreeParser;
let dtb_data = std::fs::read("your.dtb")?;
let parser = DeviceTreeParser::new(&dtb_data);
let tree = parser.parse_tree()?;
// Property access using Index trait
let model = &tree["model"]; // Instead of tree.find_property("model")
// Child access using Index trait
let first_child = &tree[0]; // Access first child node
// Natural iteration over children
for child in &tree {
println!("Child: {}", child.name);
}
// Type-safe conversions using TryFrom
if let Some(prop) = tree.find_property("reg") {
let address: u32 = u32::try_from(&prop.value)?;
let byte_data: &[u8] = <&[u8]>::try_from(&prop.value)?;
let string_val: &str = <&str>::try_from(&prop.value)?;
}
Device trees often contain complex bus hierarchies where device addresses need to be translated to CPU-visible addresses. This library provides comprehensive address translation support:
use device_tree_parser::{DeviceTreeParser, DtbError};
let dtb_data = std::fs::read("your.dtb")?;
let parser = DeviceTreeParser::new(&dtb_data);
let tree = parser.parse_tree()?;
// Enhanced MMIO region discovery with address translation
let raw_regions = parser.discover_mmio_regions_translated(false)?; // Device addresses
let cpu_regions = parser.discover_mmio_regions_translated(true)?; // CPU addresses
for ((device_addr, size), (cpu_addr, _)) in raw_regions.iter().zip(cpu_regions.iter()) {
println!("Device 0x{:x} -> CPU 0x{:x} (size: {} bytes)",
device_addr, cpu_addr, size);
}
// Find a specific device and translate its registers
let uart_nodes = tree.find_compatible_nodes("arm,pl011");
for uart in uart_nodes {
// Get CPU-visible MMIO regions for this UART
let mmio_regions = uart.mmio_regions(None)?;
for (addr, size) in mmio_regions {
println!("UART MMIO: 0x{:x} - 0x{:x}", addr, addr + size - 1);
}
// Manual address translation for specific addresses
if uart.has_property("ranges") {
// Try translating a specific device address
let device_addr = 0x1000;
match uart.translate_address(device_addr, None, 2) {
Ok(cpu_addr) => println!("Device 0x{:x} -> CPU 0x{:x}", device_addr, cpu_addr),
Err(e) => println!("Translation failed: {}", e),
}
// For complex hierarchies, use recursive translation
match uart.translate_address_recursive(device_addr, 2, 10) {
Ok(cpu_addr) => println!("Recursive: 0x{:x} -> 0x{:x}", device_addr, cpu_addr),
Err(e) => println!("Recursive translation failed: {}", e),
}
}
}
// Parse address/size cell specifications
for node in tree.iter_nodes() {
if node.has_property("ranges") {
let address_cells = node.address_cells()?;
let size_cells = node.size_cells()?;
println!("Node '{}': {}+{} address cells",
node.name, address_cells, size_cells);
// Parse the ranges property
let ranges = node.ranges(None, address_cells)?;
for range in ranges {
println!(" Range: 0x{:x} -> 0x{:x} (size: 0x{:x})",
range.child_address(), range.parent_address(), range.size());
}
}
}
translate_address() for direct parent-child translationtranslate_address_recursive() for complex bus hierarchiesDevice Tree Introduction - New to device trees? Start here for a comprehensive introduction to concepts, terminology, and real-world examples.
Device Tree Specification Reference - Detailed mapping of our implementation to the official Device Tree Specification, including compliance notes and specification references.
Migration Guide - Upgrading from v0.1.x? Complete guide with before/after examples for the v0.2.0 zero-copy API changes.
Performance & Benchmarks - Comprehensive benchmark documentation and performance analysis of the zero-copy implementation.
This project uses:
# Build the library
cargo build
# Build with release optimizations
cargo build --release
# Quick syntax checking
cargo check
If you have Nix installed, you can use the provided flake:
# Enter development shell
nix develop
# Or run commands directly
nix run .#cargo -- build
# Run all tests
cargo test
# Run specific test
cargo test test_parser_creation
# Compile tests without running
cargo test --no-run
The project includes integration tests using real DTB files generated by QEMU:
# Run integration tests specifically
cargo test integration_tests
# Run tests with output
cargo test -- --nocapture
Test data is located in test-data/ and includes:
virt.dtb: QEMU virtual machine device tree for testingThe library includes comprehensive benchmarks to measure parsing performance:
# Run all benchmarks
cargo bench
# Quick benchmarks (faster, less accurate)
./bench.sh quick
# Specific benchmark categories
./bench.sh parsing # Core parsing performance
./bench.sh properties # Property access performance
./bench.sh api # High-level API performance
# View HTML reports
./bench.sh report
See BENCHMARKS.md for detailed information on benchmark categories and interpretation.
A pre-commit hook is automatically set up to ensure code quality. It runs:
cargo fmt --check to verify code formattingcargo clippy to catch common issues and enforce best practicesThe hook automatically runs when you commit and will prevent commits if checks fail.
# Format code
cargo fmt
# Run lints (if clippy is available)
cargo clippy --all-targets --all-features
# Check formatting without modifying files
cargo fmt --check
The library is structured as follows:
src/lib.rs - Main library interface and public APIsrc/dtb/ - Device Tree Blob parsing implementation
header.rs - DTB header parsing and validationparser.rs - Core DTB parsing logictokens.rs - DTB token structure parsingtree.rs - Device tree node and property structuresmemory.rs - Memory reservation block handlingerror.rs - Error types and handlingsrc/parser.rs - General parsing utilitiessrc/integration_tests.rs - Real-world DTB parsing testsDeviceTreeParser - Main parser interfaceDtbHeader - Device tree blob headerDeviceTreeNode - Individual device tree nodesProperty - Device tree propertiesPropertyValue - Typed property values with ergonomic trait implementationsMemoryReservation - Memory reservation entriesNodeIterator - Iterator for tree traversalAddressSpec - Address/size cell specifications for device tree addressingAddressRange - Address translation range mapping between bus domainsIndex<&str> for DeviceTreeNode - Property access: node["property_name"]Index<usize> for DeviceTreeNode - Child access: node[0]IntoIterator for &DeviceTreeNode - Natural iteration: for child in &nodeTryFrom<&PropertyValue> for u32, u64, Vec<u32>, &str, &[u8] - Type-safe conversionsDisplay for DeviceTreeNode and Property - Pretty-printingDefault for creating empty instancesThe library uses DtbError for comprehensive error reporting during parsing operations.
This library is no_std compatible and only requires alloc for heap allocation. It's suitable for embedded systems and bare-metal environments.
cargo testcargo fmtcargo clippyThis project is licensed under the MIT License - see the LICENSE file for details.
See CHANGELOG.md for detailed version history and release notes.