device_tree_parser 0.4.0

High-performance Device Tree Blob (DTB) parser with zero-copy parsing and ergonomic APIs for embedded systems
Documentation
# Device Tree Parser

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.

## Features

- **Binary DTB Parsing**: Parse Device Tree Blob files with full structure validation
- **Memory Reservation Support**: Handle memory reservation blocks in DTB files
- **Property Interpolation**: Support for device tree property value parsing and interpolation
- **Address Translation (v0.4.0+)**: Full support for device tree address translation between bus domains
- **Ergonomic API (v0.3.0+)**: Modern Rust trait implementations for intuitive usage
  - `Index` traits for property and child access: `node["property"]`, `node[0]`
  - `IntoIterator` for natural iteration: `for child in &node`
  - `TryFrom` for type-safe value conversions: `u32::try_from(&value)`
  - `Display` for pretty-printing nodes and properties
- **Iterator Interface**: Convenient tree traversal with `NodeIterator`
- **No-std Compatible**: Works in embedded environments with heap allocation
- **Integration Tested**: Validated against real QEMU-generated DTB files

## Installation

Add this to your `Cargo.toml`:

```toml
[dependencies]
device_tree_parser = "0.4.0"
```

## Usage

### Basic DTB Parsing

```rust
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());
```

### Tree Traversal

```rust
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);
        }
    }
}
```

### Ergonomic API Features (v0.3.0+)

```rust
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 Tree Address Translation (v0.4.0+)

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:

```rust
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());
        }
    }
}
```

### Address Translation Features

- **Single-level translation**: `translate_address()` for direct parent-child translation
- **Multi-level translation**: `translate_address_recursive()` for complex bus hierarchies  
- **Automatic cell parsing**: Handles variable address/size cell configurations
- **Range validation**: Comprehensive bounds checking and overflow protection
- **Error handling**: Detailed error types for translation failures
- **Helper methods**: Convenient APIs for common translation scenarios
- **Integration tested**: Validated against real ARM SoC device trees

## Documentation

### 📚 Complete Documentation Suite

- **[Device Tree Introduction]DEVICE_TREE_INTRO.md** - New to device trees? Start here for a comprehensive introduction to concepts, terminology, and real-world examples.

- **[Device Tree Specification Reference]DEVICE_TREE_SPECIFICATION.md** - Detailed mapping of our implementation to the official Device Tree Specification, including compliance notes and specification references.

- **[Migration Guide]MIGRATION.md** - Upgrading from v0.1.x? Complete guide with before/after examples for the v0.2.0 zero-copy API changes.

- **[Performance & Benchmarks]BENCHMARKS.md** - Comprehensive benchmark documentation and performance analysis of the zero-copy implementation.

### 🔗 External References

- **[Device Tree Specification v0.4]https://github.com/devicetree-org/devicetree-specification** - Official specification
- **[Linux Kernel DT Documentation]https://www.kernel.org/doc/html/latest/devicetree/** - Real-world usage examples
- **[Device Tree Compiler (dtc)]https://git.kernel.org/pub/scm/utils/dtc/dtc.git** - Reference tools

## Building

### Prerequisites

This project uses:
- Rust 2024 edition
- Nix flake for reproducible development environment (optional)

### Build Commands

```bash
# Build the library
cargo build

# Build with release optimizations
cargo build --release

# Quick syntax checking
cargo check
```

### Development Environment (Nix)

If you have Nix installed, you can use the provided flake:

```bash
# Enter development shell
nix develop

# Or run commands directly
nix run .#cargo -- build
```

## Testing

### Unit Tests

```bash
# Run all tests
cargo test

# Run specific test
cargo test test_parser_creation

# Compile tests without running
cargo test --no-run
```

### Integration Tests

The project includes integration tests using real DTB files generated by QEMU:

```bash
# Run integration tests specifically
cargo test integration_tests

# Run tests with output
cargo test -- --nocapture
```

### Test Data

Test data is located in `test-data/` and includes:
- `virt.dtb`: QEMU virtual machine device tree for testing

## Benchmarks

The library includes comprehensive benchmarks to measure parsing performance:

```bash
# 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](BENCHMARKS.md) for detailed information on benchmark categories and interpretation.

## Code Quality

### Pre-commit Hook

A pre-commit hook is automatically set up to ensure code quality. It runs:
- `cargo fmt --check` to verify code formatting
- `cargo clippy` to catch common issues and enforce best practices

The hook automatically runs when you commit and will prevent commits if checks fail.

### Manual Code Quality Checks

```bash
# Format code
cargo fmt

# Run lints (if clippy is available)
cargo clippy --all-targets --all-features

# Check formatting without modifying files
cargo fmt --check
```

## Architecture

The library is structured as follows:

- `src/lib.rs` - Main library interface and public API
- `src/dtb/` - Device Tree Blob parsing implementation
  - `header.rs` - DTB header parsing and validation
  - `parser.rs` - Core DTB parsing logic
  - `tokens.rs` - DTB token structure parsing
  - `tree.rs` - Device tree node and property structures
  - `memory.rs` - Memory reservation block handling
  - `error.rs` - Error types and handling
- `src/parser.rs` - General parsing utilities
- `src/integration_tests.rs` - Real-world DTB parsing tests

## API Reference

### Main Types

- `DeviceTreeParser` - Main parser interface
- `DtbHeader` - Device tree blob header
- `DeviceTreeNode` - Individual device tree nodes
- `Property` - Device tree properties
- `PropertyValue` - Typed property values with ergonomic trait implementations
- `MemoryReservation` - Memory reservation entries
- `NodeIterator` - Iterator for tree traversal
- `AddressSpec` - Address/size cell specifications for device tree addressing
- `AddressRange` - Address translation range mapping between bus domains

### Ergonomic Traits (v0.3.0+)

- `Index<&str>` for `DeviceTreeNode` - Property access: `node["property_name"]`
- `Index<usize>` for `DeviceTreeNode` - Child access: `node[0]`
- `IntoIterator` for `&DeviceTreeNode` - Natural iteration: `for child in &node`
- `TryFrom<&PropertyValue>` for `u32`, `u64`, `Vec<u32>`, `&str`, `&[u8]` - Type-safe conversions
- `Display` for `DeviceTreeNode` and `Property` - Pretty-printing
- `Default` for creating empty instances

### Error Handling

The library uses `DtbError` for comprehensive error reporting during parsing operations.

## No-std Support

This library is `no_std` compatible and only requires `alloc` for heap allocation. It's suitable for embedded systems and bare-metal environments.

## Contributing

1. Ensure all tests pass: `cargo test`
2. Format code: `cargo fmt`
3. Run lints: `cargo clippy`
4. Follow the existing code style and patterns
5. Add tests for new functionality

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Changelog

See [CHANGELOG.md](CHANGELOG.md) for detailed version history and release notes.