fdt-edit

Crates.iofdt-edit
lib.rsfdt-edit
version0.1.5
created_at2025-12-07 09:58:51.806405+00
updated_at2025-12-19 04:53:44.368903+00
descriptionA high-level library for creating, editing, and encoding Flattened Device Tree (FDT) structures
homepagehttps://github.com/drivercraft/fdt-parser
repositoryhttps://github.com/drivercraft/fdt-parser
max_upload_size
id1971372
size130,442
周睿 (ZR233)

documentation

https://docs.rs/fdt-edit

README

fdt-edit

A high-level Rust library for creating, editing, and encoding Flattened Device Tree (FDT) structures.

Overview

fdt-edit is a feature-rich device tree manipulation library built on top of fdt-raw. It provides comprehensive functionality for creating new device trees from scratch, modifying existing device trees, and encoding the edited device trees into standard DTB format.

Features

  • Complete device tree editing: Full CRUD operations for nodes and properties
  • Type-safe node operations: Specialized node types (clocks, memory, PCI, interrupt controllers, etc.)
  • Efficient encoder: Converts in-memory device tree structures to standard DTB format
  • phandle management: Automatic phandle allocation and reference management
  • Memory reservation support: Complete memory reservation region operations
  • no_std compatible: Suitable for embedded environments

Core Components

Fdt Structure

An editable device tree container that:

  • Parses from raw DTB data
  • Creates new empty device trees
  • Manages phandle cache
  • Encodes to DTB format

Node System

Supports multiple specialized node types:

  • Clock nodes: Clock sources and clock consumers
  • Memory nodes: Memory region definitions
  • PCI nodes: PCI buses and devices
  • Interrupt controllers: Interrupt mapping and management
  • Generic nodes: Customizable node types

Property System

  • Type-safe properties: Support for various data types
  • Automatic property management: Intelligent property CRUD operations
  • Formatted display: Friendly node and property display

Quick Start

use fdt_edit::Fdt;

// Parse existing DTB from bytes
let raw_data = include_bytes!("path/to/device-tree.dtb");
let fdt = Fdt::from_bytes(&raw_data)?;

// Access nodes by path
let node = fdt.get_by_path("/chosen");
if let Some(chosen) = node {
    println!("Found chosen node: {}", chosen.name());
}

// Encode back to DTB format
let dtb_data = fdt.encode();
std::fs::write("output.dtb", dtb_data.as_bytes())?;

Node Traversal and Searching

use fdt_edit::{Fdt, NodeKind};

let fdt = Fdt::from_bytes(&dtb_data)?;

// Iterate through all nodes
for node in fdt.all_nodes() {
    println!("Node: {} at path {}", node.name(), node.path());

    // Match specialized node types
    match node.as_ref() {
        NodeKind::Memory(mem) => {
            println!("  Memory node with regions:");
            for region in mem.regions() {
                println!("    address=0x{:x}, size=0x{:x}", region.address, region.size);
            }
        }
        NodeKind::Clock(clock) => {
            println!("  Clock node: {} (#clock-cells={})", clock.name(), clock.clock_cells);
        }
        NodeKind::Pci(pci) => {
            if let Some(range) = pci.bus_range() {
                println!("  PCI bus range: {:?}", range);
            }
        }
        _ => {
            println!("  Generic node");
        }
    }
}

// Find nodes by path pattern
let virtio_nodes: Vec<_> = fdt.find_by_path("/virtio_mmio").collect();
println!("Found {} virtio_mmio nodes", virtio_nodes.len());

Node Modification and Creation

use fdt_edit::{Fdt, Node};

let mut fdt = Fdt::from_bytes(&dtb_data)?;

// Create new node manually
let mut new_node = Node::new("test-device@12340000");
// Add properties (API in development)
// new_node.add_property("compatible", &["vendor,test-device"]);
// new_node.add_property("reg", &[0x12340000u64, 0x1000u64]);

// Add to root node
fdt.root.add_child(new_node);

// Remove existing node
if fdt.get_by_path("/psci").is_some() {
    let removed = fdt.remove_node("/psci")?;
    println!("Removed psci node: {}", removed.unwrap().name());
}

// Save the modified device tree
let modified_dtb = fdt.encode();
std::fs::write("modified.dtb", modified_dtb.as_bytes())?;

Specialized Node Access

use fdt_edit::{Fdt, NodeKind};

let fdt = Fdt::from_bytes(&dtb_data)?;

// Find and work with memory nodes
for node in fdt.all_nodes() {
    if let NodeKind::Memory(mem) = node.as_ref() {
        let regions = mem.regions();
        if !regions.is_empty() {
            println!("Memory node '{}' has {} regions:", mem.name(), regions.len());
            for (i, region) in regions.iter().enumerate() {
                println!("  Region {}: 0x{:x}-0x{:x}", i, region.address, region.address + region.size);
            }
        }
    }
}

// Find clock nodes
let mut clock_count = 0;
for node in fdt.all_nodes() {
    if let NodeKind::Clock(clock) = node.as_ref() {
        clock_count += 1;
        println!("Clock {}: cells={}, output-names={:?}",
                 clock.name(),
                 clock.clock_cells,
                 clock.clock_output_names);
    }
}

Display as Device Tree Source

use fdt_edit::Fdt;

let fdt = Fdt::from_bytes(&dtb_data)?;

// Display as DTS format (including memory reservations)
println!("{}", fdt);
// Output will show:
// /dts-v1/;
// /memreserve/ 0x80000000 0x100000;
// / {
//     #address-cells = <0x2>;
//     #size-cells = <0x2>;
//     compatible = "qemu,arm64";
//     ...
// };

Current Status

This library is under active development. Currently supported features:

  • ✅ Parse DTB files into editable structures
  • ✅ Encode device trees back to DTB format
  • ✅ Display device trees in DTS format
  • ✅ Access to memory reservations
  • 🚧 Node editing APIs (in development)

Dependencies

  • fdt-raw - Low-level FDT parsing library
  • log = "0.4" - Logging support
  • enum_dispatch = "0.3.13" - Enum dispatch optimization

Dev Dependencies

  • dtb-file - Test data
  • env_logger = "0.11" - Logger implementation

Testing

The library includes comprehensive tests that verify round-trip compatibility:

cargo test

The main test (test_parse_and_rebuild) ensures that:

  1. A DTB file can be parsed successfully
  2. The parsed structure can be encoded back to DTB
  3. The original and rebuilt DTB files produce identical DTS output when using dtc

License

This project is licensed under open source licenses. Please see the LICENSE file in the project root for specific license types.

Contributing

Issues and Pull Requests are welcome. Please ensure:

  1. Code follows the project's formatting standards (cargo fmt)
  2. All tests pass (cargo test)
  3. Clippy checks pass (cargo clippy)
  4. New features include appropriate test cases

Related Projects

Examples

More usage examples can be found in the source code test files, particularly in tests/edit.rs.

Commit count: 0

cargo fmt