1 unstable release
| 0.1.0 | Mar 14, 2026 |
|---|
#1401 in Embedded development
Used in ruvix-cli
190KB
4K
SLoC
ruvix-dtb
Device Tree Blob (FDT) parser for the RuVix Cognition Kernel.
Overview
This crate provides a zero-copy parser for Flattened Device Tree (FDT) blobs, enabling hardware discovery at boot time. It is designed as part of ADR-087 for the RuVix Cognition Kernel.
Features
- No-std compatible: Works in bare-metal environments
- Zero-copy parsing: References directly into the FDT blob
- No heap allocation: Fixed-size internal buffers
- Safe parsing: Validates all data before access
- FDT version 17: Compatible with standard device trees
Core Types
DeviceTree
Main parser and accessor for device tree data:
use ruvix_dtb::DeviceTree;
fn discover_hardware(blob: &[u8]) -> Result<(), ruvix_dtb::DtbError> {
let dt = DeviceTree::parse(blob)?;
// Get basic info
println!("Total size: {} bytes", dt.total_size());
println!("Boot CPU: {}", dt.boot_cpuid());
println!("Node count: {}", dt.node_count());
Ok(())
}
Node
Reference to a node in the tree:
use ruvix_dtb::{DeviceTree, Node};
fn inspect_node(dt: &DeviceTree, node: &Node) {
println!("Name: {}", node.name());
println!("Unit name: {}", node.unit_name());
if let Some(addr) = node.unit_address() {
println!("Unit address: {}", addr);
}
println!("Depth: {}", node.depth());
println!("Is root: {}", node.is_root());
}
Property
Access to node properties:
use ruvix_dtb::{DeviceTree, Property, PropertyValue};
fn read_properties(dt: &DeviceTree) -> Result<(), ruvix_dtb::DtbError> {
let root = dt.root().ok_or(ruvix_dtb::DtbError::NodeNotFound)?;
// Get string property
let model = dt.get_string(&root, "model")?;
println!("Model: {}", model);
// Get numeric property
if let Ok(cells) = dt.get_u32(&root, "#address-cells") {
println!("Address cells: {}", cells);
}
// Parse property dynamically
let prop = dt.get_property(&root, "compatible")?;
match prop.parse() {
PropertyValue::String(s) => println!("Compatible: {}", s),
PropertyValue::U32(v) => println!("Value: 0x{:x}", v),
_ => println!("Other type"),
}
Ok(())
}
RegEntry
Parsed memory region entry:
use ruvix_dtb::RegEntry;
let entry = RegEntry::new(0x8000_0000, 0x1000_0000);
assert_eq!(entry.address, 0x8000_0000);
assert_eq!(entry.size, 0x1000_0000);
assert_eq!(entry.end(), 0x9000_0000);
assert!(entry.contains(0x8000_0000));
Usage Examples
Finding Memory Regions
use ruvix_dtb::DeviceTree;
fn get_memory(blob: &[u8]) -> Result<Vec<(u64, u64)>, ruvix_dtb::DtbError> {
let dt = DeviceTree::parse(blob)?;
let mut regions = Vec::new();
if let Some(memory) = dt.find_node("/memory") {
let reg = dt.get_reg(&memory)?;
for entry in reg.iter() {
regions.push((entry.address, entry.size));
}
}
Ok(regions)
}
Finding Compatible Devices
use ruvix_dtb::DeviceTree;
fn find_uarts(blob: &[u8]) -> Result<(), ruvix_dtb::DtbError> {
let dt = DeviceTree::parse(blob)?;
for node in dt.find_compatible("ns16550a") {
println!("Found UART: {}", node.name());
if let Ok(reg) = dt.get_reg(&node) {
if let Some(entry) = reg.first() {
println!(" Address: 0x{:x}", entry.address);
}
}
}
Ok(())
}
Iterating Children
use ruvix_dtb::DeviceTree;
fn list_soc_devices(blob: &[u8]) -> Result<(), ruvix_dtb::DtbError> {
let dt = DeviceTree::parse(blob)?;
if let Some(soc) = dt.find_node("/soc") {
for child in dt.children(&soc) {
println!("Device: {}", child.name());
}
}
Ok(())
}
FDT Structure
A Flattened Device Tree consists of:
-
Header (40 bytes)
- Magic number:
0xd00dfeed - Total size, version, offsets
- Magic number:
-
Memory Reservation Block
- Reserved memory regions
-
Structure Block
- Tree of nodes and properties
- Tokens:
FDT_BEGIN_NODE,FDT_END_NODE,FDT_PROP,FDT_NOP,FDT_END
-
Strings Block
- Property name strings
Constants
| Constant | Value | Description |
|---|---|---|
FDT_MAGIC |
0xd00dfeed |
FDT magic number |
FDT_VERSION |
17 | Supported version |
MAX_TREE_DEPTH |
32 | Maximum tree depth |
MAX_PATH_LEN |
256 | Maximum path length |
MAX_PROPERTY_NAME_LEN |
64 | Maximum property name |
Error Handling
All parsing errors are returned as DtbError:
use ruvix_dtb::{DeviceTree, DtbError};
fn handle_errors(blob: &[u8]) {
match DeviceTree::parse(blob) {
Ok(dt) => println!("Parsed {} nodes", dt.node_count()),
Err(DtbError::InvalidMagic { found }) => {
println!("Not a DTB (magic: 0x{:08x})", found);
}
Err(DtbError::UnsupportedVersion { version }) => {
println!("Unsupported version: {}", version);
}
Err(e) => println!("Parse error: {}", e),
}
}
License
MIT OR Apache-2.0