### Fdt::new Source: https://context7.com/drivercraft/fdt-parser/llms.txt Creates a new, empty editable FDT with a single root node. This is the starting point for building an FDT programmatically. ```APIDOC ## Fdt::new — Create an empty editable device tree Creates a new `Fdt` with a single empty root node. `boot_cpuid_phys` defaults to `0` and the memory reservation list is empty. Use this as the starting point when building a device tree programmatically. ```rust use fdt_edit::{Fdt, Node, Property}; let mut fdt = Fdt::new(); // Decorate the root let root_id = fdt.root_id(); fdt.node_mut(root_id).unwrap().set_property(Property::new( "#address-cells", 2u32.to_be_bytes().to_vec(), )); fdt.node_mut(root_id).unwrap().set_property(Property::new( "#size-cells", 1u32.to_be_bytes().to_vec(), )); fdt.node_mut(root_id).unwrap().set_property(Property::new( "model", b"my-board\0".to_vec(), )); assert_eq!(fdt.node_count(), 1); // only root so far println!("root id = {}", fdt.root_id()); // 0 ``` ``` -------------------------------- ### Create New DTB Source: https://context7.com/drivercraft/fdt-parser/llms.txt Initializes a new, empty Device Tree Blob (DTB). Use this when constructing a DTB from scratch, for example, in test fixtures. ```rust let mut fdt = Fdt::new(); ``` -------------------------------- ### Build a New Device Tree Programmatically in Rust Source: https://github.com/drivercraft/fdt-parser/blob/main/README.md This example shows how to construct a new Flattened Device Tree from scratch. It initializes an empty FDT, sets properties on the root node, and then adds a 'memory' node with its own properties. The resulting tree is then encoded into DTB bytes. ```rust use fdt_edit::{Fdt, Node, Property}; let mut fdt = Fdt::new(); let root_id = fdt.root_id(); fdt.node_mut(root_id).unwrap().set_property(Property::new( "#address-cells", 2u32.to_be_bytes().to_vec(), )); fdt.node_mut(root_id).unwrap().set_property(Property::new( "#size-cells", 1u32.to_be_bytes().to_vec(), )); let mut memory = Node::new("memory@80000000"); memory.set_property(Property::new("device_type", b"memory\0".to_vec())); memory.set_property(Property::new( "reg", vec![ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, ], )); fdt.add_node(root_id, memory); let dtb = fdt.encode(); assert!(dtb.len() >= 40); ``` -------------------------------- ### Handle Device Tree Properties with Typed Accessors Source: https://context7.com/drivercraft/fdt-parser/llms.txt Shows how to create and manipulate properties, including setting and getting values as big-endian integers (u32, u64), strings, and string lists. Also demonstrates iterating over u32 values for multi-cell properties. ```rust use fdt_edit::Property; // u32 / u64 let mut clk_freq = Property::new("clock-frequency", 200_000_000u32.to_be_bytes().to_vec()); println!("freq = {} Hz", clk_freq.get_u32().unwrap()); clk_freq.set_u32_ls(&[400_000_000u32]); assert_eq!(clk_freq.get_u32(), Some(400_000_000)); let mut reg64 = Property::new("reg", 0x0002_0000_0000u64.to_be_bytes().to_vec()); println!("addr = {:#018x}", reg64.get_u64().unwrap()); // Strings let mut compat = Property::new("compatible", Vec::new()); compat.set_string_ls(&["arm,pl011", "arm,primecell"]); let names: Vec<&str> = compat.as_str_iter().collect(); assert_eq!(names, ["arm,pl011", "arm,primecell"]); // Single string let mut model = Property::new("model", Vec::new()); model.set_string("my-board v2"); assert_eq!(model.as_str(), Some("my-board v2")); // u32 iterator (e.g. multi-cell reg) let cells = Property::new("reg", [0x00u8,0x00,0x10,0x00, 0x00,0x00,0x00,0x40].to_vec()); let vals: Vec = cells.get_u32_iter().collect(); assert_eq!(vals, [0x0000_1000, 0x0000_0040]); ``` -------------------------------- ### Create an empty editable device tree with Fdt::new Source: https://context7.com/drivercraft/fdt-parser/llms.txt Use `Fdt::new` to start building a device tree programmatically. This initializes an FDT with a single empty root node. You can then add properties to the root node. ```rust use fdt_edit::{Fdt, Node, Property}; let mut fdt = Fdt::new(); // Decorate the root let root_id = fdt.root_id(); fdt.node_mut(root_id).unwrap().set_property(Property::new( "#address-cells", 2u32.to_be_bytes().to_vec(), )); fdt.node_mut(root_id).unwrap().set_property(Property::new( "#size-cells", 1u32.to_be_bytes().to_vec(), )); fdt.node_mut(root_id).unwrap().set_property(Property::new( "model", b"my-board\0".to_vec(), )); assert_eq!(fdt.node_count(), 1); // only root so far println!("root id = {}", fdt.root_id()); // 0 ``` -------------------------------- ### Load, Modify, and Encode DTB Bytes in Rust Source: https://github.com/drivercraft/fdt-parser/blob/main/README.md This example demonstrates loading existing DTB bytes, modifying properties of the root node, adding a new 'soc' node if it doesn't exist, and then adding a 'uart' node with its properties. Finally, it encodes the modified tree back into DTB bytes. Ensure you replace the initial `dtb: &[u8] = &[];` with actual DTB data. ```rust use fdt_edit::{Fdt, Node, Property}; # fn main() -> Result<(), fdt_edit::FdtError> { let dtb: &[u8] = &[]; // replace with real DTB bytes let mut fdt = Fdt::from_bytes(dtb)?; let root_id = fdt.root_id(); fdt.node_mut(root_id) .unwrap() .set_property(Property::new("model", b"example-board\0".to_vec())); let soc_id = if let Some(node) = fdt.get_by_path("/soc") { node.id() } else { fdt.add_node(root_id, Node::new("soc")) }; let mut uart = Node::new("uart@1000"); uart.set_property(Property::new("compatible", b"ns16550a\0".to_vec())); uart.set_property(Property::new( "reg", vec![0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00], )); fdt.add_node(soc_id, uart); let encoded = fdt.encode(); assert!(!encoded.is_empty()); # Ok(()) # } ``` -------------------------------- ### Search Nodes by Compatible String Source: https://context7.com/drivercraft/fdt-parser/llms.txt Use `find_compatible` to get a `Vec` of all nodes matching any of the provided compatible strings. The search is a depth-first traversal. ```rust use fdt_edit::{Fdt, NodeType, PciSpace}; fn print_pci_ranges(fdt: &Fdt) { for node in fdt.find_compatible(&["pci-host-ecam-generic", "pci-host-cam-generic"]) { let NodeType::Pci(pci) = node else { continue }; println!("PCI node: {}", pci.path()); if let Some(ranges) = pci.ranges() { for r in &ranges { let kind = match r.space { PciSpace::IO => "IO", PciSpace::Memory32 => "MEM32", PciSpace::Memory64 => "MEM64", }; println!(" {kind}: bus={:#x} cpu={:#x} size={:#x} prefetch={}", r.bus_address, r.cpu_address, r.size, r.prefetchable); } } } } ``` -------------------------------- ### Iterate Over All Nodes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Use `all_nodes` to get a depth-first iterator over all nodes in the tree, yielding classified `NodeType` views. Useful for whole-tree inspection. ```rust use fdt_edit::{Fdt, NodeType}; fn summarise(fdt: &Fdt) { let (mut mem, mut clk, mut intc, mut pci, mut gen) = (0usize, 0, 0, 0, 0); for node in fdt.all_nodes() { match node { NodeType::Memory(_) => mem += 1, NodeType::Clock(_) => clk += 1, NodeType::InterruptController(_) => intc += 1, NodeType::Pci(_) => pci += 1, NodeType::Generic(_) => gen += 1, } } println!("mem={mem} clk={clk} intc={intc} pci={pci} generic={gen}"); } ``` -------------------------------- ### Inherited Interrupt Parent Lookup Source: https://context7.com/drivercraft/fdt-parser/llms.txt Demonstrates how `interrupt_parent()` walks up the tree to find the effective interrupt parent, unlike `Node::interrupt_parent()` which only returns the local value. This example requires `fdt_edit::{Fdt, Node, Property, Phandle}`. ```rust use fdt_edit::{Fdt, Node, Property, Phandle}; // Build a tree where only the root declares interrupt-parent let mut fdt = Fdt::new(); let root = fdt.root_id(); fdt.node_mut(root).unwrap().set_property(Property::new( "interrupt-parent", 0x01u32.to_be_bytes().to_vec(), )); let soc = fdt.add_node(root, Node::new("soc")); let uart = fdt.add_node(soc, Node::new("uart@10000")); let uart_view = fdt.get_by_path("/soc/uart@10000").unwrap(); // Local node has no interrupt-parent — inherited from root assert_eq!(uart_view.as_node().interrupt_parent(), None); assert_eq!(uart_view.interrupt_parent(), Some(Phandle::from(0x01))); ``` -------------------------------- ### Fdt::all_nodes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Returns a depth-first iterator that yields classified NodeType views for every node in the tree, starting from the root. Useful for whole-tree inspection, transformation, or serialisation. ```APIDOC ## `Fdt::all_nodes` — Depth-first iteration over all nodes Returns a depth-first iterator that yields classified `NodeType` views for every node in the tree, starting from the root. Useful for whole-tree inspection, transformation, or serialisation. ```rust use fdt_edit::{Fdt, NodeType}; fn summarise(fdt: &Fdt) { let (mut mem, mut clk, mut intc, mut pci, mut gen) = (0usize, 0, 0, 0, 0); for node in fdt.all_nodes() { match node { NodeType::Memory(_) => mem += 1, NodeType::Clock(_) => clk += 1, NodeType::InterruptController(_) => intc += 1, NodeType::Pci(_) => pci += 1, NodeType::Generic(_) => gen += 1, } } println!("mem={mem} clk={clk} intc={intc} pci={pci} generic={gen}"); } ``` ``` -------------------------------- ### Build A New Tree Programmatically Source: https://github.com/drivercraft/fdt-parser/blob/main/README.md Illustrates how to create a new Flattened Device Tree from scratch using the `fdt-edit` library. ```APIDOC ## Build A New Tree ### Description This example demonstrates how to construct a new device tree programmatically. It creates a root node, sets properties like `#address-cells` and `#size-cells`, and then adds a 'memory' node with its properties. ### Method Rust code for building a new FDT. ### Endpoint N/A (Rust library) ### Parameters N/A ### Request Example ```rust use fdt_edit::{Fdt, Node, Property}; let mut fdt = Fdt::new(); let root_id = fdt.root_id(); fdt.node_mut(root_id).unwrap().set_property(Property::new( "#address-cells", 2u32.to_be_bytes().to_vec(), )); fdt.node_mut(root_id).unwrap().set_property(Property::new( "#size-cells", 1u32.to_be_bytes().to_vec(), )); let mut memory = Node::new("memory@80000000"); memory.set_property(Property::new("device_type", b"memory\0".to_vec())); memory.set_property(Property::new( "reg", vec![0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00], )); fdt.add_node(root_id, memory); let dtb = fdt.encode(); assert!(dtb.len() >= 40); ``` ### Response N/A (Rust function return) ### Response Example N/A ``` -------------------------------- ### Query Typed Nodes by Compatible String Source: https://github.com/drivercraft/fdt-parser/blob/main/README.md Shows how to find and query nodes based on their 'compatible' string, with type-specific access to node properties. ```APIDOC ## Query Typed Nodes ### Description This example demonstrates how to find nodes that match a specific compatible string (e.g., `"pci-host-ecam-generic"`). It then shows how to cast the found node to a specific type (like `NodeType::Pci`) to access type-specific properties such as `bus_range` and `interrupt_cells`. ### Method Rust code for querying nodes by compatible string. ### Endpoint N/A (Rust library) ### Parameters N/A ### Request Example ```rust,no_run use fdt_edit::{Fdt, NodeType}; # fn main() -> Result<(), fdt_edit::FdtError> { # let dtb: &[u8] = &[]; // replace with real DTB bytes let fdt = Fdt::from_bytes(dtb)?; for node in fdt.find_compatible(&["pci-host-ecam-generic"]) { if let NodeType::Pci(pci) = node { let _bus_range = pci.bus_range(); let _interrupt_cells = pci.interrupt_cells(); } } # Ok(()) # } ``` ### Response N/A (Rust function return) ### Response Example N/A ``` -------------------------------- ### Parse FDT and Iterate Nodes/Properties Source: https://github.com/drivercraft/fdt-parser/blob/main/fdt-raw/README.md Demonstrates parsing FDT data from bytes and iterating through the root node's children and their properties. Also shows how to access memory reservation blocks. ```rust use fdt_raw::Fdt; // Parse FDT from byte data let fdt = Fdt::from_bytes(&dtb_data)?; // Iterate through root node's children for node in fdt.root().children() { println!("Node name: {}", node.name()?); // Iterate through node properties for prop in node.properties() { println!(" Property: {}", prop.name()?); } } // Access memory reservation block for reservation in fdt.memory_reservations() { println!("Reserved: 0x{:x} - 0x{:x}", reservation.address, reservation.address + reservation.size); } ``` -------------------------------- ### Load, Modify, Encode DTB Source: https://github.com/drivercraft/fdt-parser/blob/main/README.md Demonstrates how to load existing DTB data, modify nodes and properties, and then re-encode the tree back into DTB bytes. ```APIDOC ## Load, Modify, Encode ### Description This example shows how to load DTB data from bytes, modify the root node's model property, add a new 'soc' node if it doesn't exist, and then add a 'uart' node under 'soc'. Finally, it encodes the modified FDT back into bytes. ### Method Rust code demonstrating FDT manipulation. ### Endpoint N/A (Rust library) ### Parameters N/A ### Request Example ```rust,no_run use fdt_edit::{Fdt, Node, Property}; # fn main() -> Result<(), fdt_edit::FdtError> { let dtb: &[u8] = &[]; // replace with real DTB bytes let mut fdt = Fdt::from_bytes(dtb)?; let root_id = fdt.root_id(); fdt.node_mut(root_id) .unwrap() .set_property(Property::new("model", b"example-board\0".to_vec())); let soc_id = if let Some(node) = fdt.get_by_path("/soc") { node.id() } else { fdt.add_node(root_id, Node::new("soc")) }; let mut uart = Node::new("uart@1000"); uart.set_property(Property::new("compatible", b"ns16550a\0".to_vec())); uart.set_property(Property::new( "reg", vec![0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00], )); fdt.add_node(soc_id, uart); let encoded = fdt.encode(); assert!(!encoded.is_empty()); # Ok(()) # } ``` ### Response N/A (Rust function return) ### Response Example N/A ``` -------------------------------- ### Resolve FDT Aliases and Paths Source: https://context7.com/drivercraft/fdt-parser/llms.txt Demonstrates how to use `resolve_alias` to find a node's path via an alias in the `/aliases` node and `path_of` to reconstruct a node's absolute path. Requires the `fdt_edit` crate. ```rust use fdt_edit::{Fdt, Node, Property}; let mut fdt = Fdt::new(); let root = fdt.root_id(); let soc = fdt.add_node(root, Node::new("soc")); let uart = fdt.add_node(soc, Node::new("serial@10000")); // Register an alias let mut aliases = Node::new("aliases"); alias.set_property(Property::new("serial0", b"/soc/serial@10000\0".to_vec())); fdt.add_node(root, aliases); // path_of assert_eq!(fdt.path_of(uart), "/soc/serial@10000"); // resolve_alias assert_eq!(fdt.resolve_alias("serial0"), Some("/soc/serial@10000")); // get_by_path via alias let found = fdt.get_by_path("serial0"); assert!(found.is_some()); ``` -------------------------------- ### Manage FDT Memory Reservations Source: https://context7.com/drivercraft/fdt-parser/llms.txt Shows how to add memory reservations to an `Fdt` object and verify they are correctly encoded and parsed back. Requires the `fdt_edit` and `fdt_raw` crates. ```rust use fdt_edit::{Fdt, MemoryReservation}; use fdt_raw::MemoryReservation as RawRsv; let mut fdt = Fdt::new(); fdt.memory_reservations.push(MemoryReservation { address: 0x8000_0000, size: 0x0010_0000 }); fdt.memory_reservations.push(MemoryReservation { address: 0x9000_0000, size: 0x0020_0000 }); let dtb = fdt.encode(); let reparsed = Fdt::from_bytes(&dtb).unwrap(); assert_eq!(reparsed.memory_reservations.len(), 2); assert_eq!(reparsed.memory_reservations[0].address, 0x8000_0000); assert_eq!(reparsed.memory_reservations[1].size, 0x0020_0000); ``` -------------------------------- ### Manipulate Device Tree Nodes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Demonstrates adding, updating, reading, and removing properties within a mutable device tree node. Properties are cached for O(log n) lookup. ```rust use fdt_edit::{Node, Property}; let mut node = Node::new("serial@10000"); // Add / update properties node.set_property(Property::new("compatible", b"arm,pl011\0".to_vec())); node.set_property(Property::new("reg", [0x00u8,0x00,0x00,0x00, 0x00,0x00,0x10,0x00, 0x00,0x00,0x10,0x00].to_vec())); node.set_property(Property::new("status", b"okay\0".to_vec())); node.set_property(Property::new("phandle", 5u32.to_be_bytes().to_vec())); // Read helpers println!("name = {}", node.name()); println!("phandle = {:?}", node.phandle()); println!("status = {:?}", node.status()); println!("compatible = {:?}", node.compatible().map(|it| it.collect::>())); // Remove a property node.remove_property("status"); assert!(node.get_property("status").is_none()); // Property iteration for prop in node.properties() { println!(" {} ({} bytes)", prop.name(), prop.data.len()); } ``` -------------------------------- ### Run FDT Edit Tests Source: https://github.com/drivercraft/fdt-parser/blob/main/README.md Execute the test suite for the fdt-edit library to verify parsing, traversal, and encoding correctness. ```bash cargo test -p fdt-edit ``` -------------------------------- ### Add fdt-edit Dependency to Cargo.toml Source: https://github.com/drivercraft/fdt-parser/blob/main/README.md To use the fdt-edit crate, add the following line to your project's Cargo.toml file under [dependencies]. ```toml [dependencies] fdt-edit = "0.2.0" ``` -------------------------------- ### Parse from a raw bootloader pointer with Fdt::from_ptr Source: https://context7.com/drivercraft/fdt-parser/llms.txt Initialize an FDT from a raw pointer provided by a bootloader using `Fdt::from_ptr`. Ensure the pointer is valid and the memory region persists for the lifetime of the `Fdt` object. This function requires `unsafe` due to direct memory access. ```rust use fdt_edit::Fdt; /// # Safety /// `fdt_addr` must point to a valid, complete DTB in memory. unsafe fn init_from_bootloader(fdt_addr: usize) -> Fdt { let ptr = fdt_addr as *mut u8; Fdt::from_ptr(ptr).expect("invalid FDT from bootloader") } ``` -------------------------------- ### Inspect Clock Provider Nodes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Iterates through all nodes, identifying clock providers and printing their details, including clock cells, type (fixed or normal), frequency, accuracy, name, and output names. Requires `fdt_edit::{Fdt, NodeType, ClockType}`. ```rust use fdt_edit::{Fdt, NodeType, ClockType}; fn inspect_clocks(fdt: &Fdt) { for node in fdt.all_nodes() { if let NodeType::Clock(clk) = node { print!("Clock: {} cells={}", clk.path(), clk.clock_cells()); match clk.clock_type() { ClockType::Fixed(f) => { print!(" [fixed] freq={}Hz", f.frequency); if let Some(acc) = f.accuracy { print!(" acc={}ppb", acc); } if let Some(n) = &f.name { print!(" name={n}"); } } ClockType::Normal => print!(" [normal]"), } println!(); for (i, name) in clk.clock_output_names().iter().enumerate() { println!(" output[{i}] = {name}"); } } } } ``` -------------------------------- ### Low-Level DTB Parsing with fdt-raw Source: https://context7.com/drivercraft/fdt-parser/llms.txt Provides read-only, `no_std` access to a DTB byte slice using the `fdt-raw` crate. It demonstrates accessing header information, memory reservations, node paths, register data, chosen node properties, and address translation. ```rust use fdt_raw::Fdt; fn raw_scan(dtb: &[u8]) { let fdt = Fdt::from_bytes(dtb).expect("invalid DTB"); println!("version: {}", fdt.header().version); println!("total: {} bytes", fdt.header().totalsize); for rsv in fdt.memory_reservations() { println!("rsv addr={:#x} size={:#x}", rsv.address, rsv.size); } for node in fdt.all_nodes() { let path = node.path(); if let Some(reg) = node.reg() { for r in reg { println!("{path}: reg addr={:#x} size={:?}", r.address, r.size); } } } // Chosen node if let Some(chosen) = fdt.chosen() { println!("bootargs: {:?}", chosen.bootargs()); } // Address translation via ranges let cpu_addr = fdt.translate_address("/soc/pcie@900000000", 0x0); println!("translated = {:#x}", cpu_addr); } ``` -------------------------------- ### Traverse All Nodes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Iterates over all nodes within a Device Tree Blob (DTB). Useful for auditing hardware configurations or applying changes across the entire tree. ```rust for node in fdt.all_nodes() { ... } ``` -------------------------------- ### Parse an existing DTB blob with Fdt::from_bytes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Load an FDT from a byte slice using `Fdt::from_bytes`. This function validates the DTB and reconstructs the tree. It returns an error for malformed input. Useful for inspecting or modifying existing device trees. ```rust use fdt_edit::{Fdt, FdtError}; fn load_and_inspect(dtb_bytes: &[u8]) -> Result<(), FdtError> { let fdt = Fdt::from_bytes(dtb_bytes)?; println!("nodes : {}", fdt.node_count()); println!("cpu-id : {}", fdt.boot_cpuid_phys); println!("rsv blk : {} entries", fdt.memory_reservations.len()); // Inspect root let root = fdt.get_by_path("/").unwrap(); if let Some(model) = root.as_node().get_property("model") { println!("model = {:?}", model.as_str()); } Ok(()) } ``` -------------------------------- ### Dump Translated Register Properties Source: https://context7.com/drivercraft/fdt-parser/llms.txt Iterates through all nodes in the FDT, retrieves their `reg` properties, and prints the translated CPU physical addresses, bus addresses, and sizes. Requires the `fdt_edit` crate. ```rust use fdt_edit::{Fdt, NodeType}; fn dump_regs(fdt: &Fdt) { for node in fdt.all_nodes() { let regs = node.regs(); if regs.is_empty() { continue; } println!("{}:", node.path()); for r in regs { println!(" cpu_addr={:#018x} bus_addr={:#018x} size={:#x?}", r.address, r.child_bus_address, r.size); } } } ``` -------------------------------- ### Query Typed Nodes by Compatible String in Rust Source: https://github.com/drivercraft/fdt-parser/blob/main/README.md This snippet demonstrates how to query nodes within an FDT based on their 'compatible' string. It iterates through nodes matching specific compatible strings and, if a node is identified as a PCI device, extracts its bus range and interrupt cell count. This requires the FDT to be loaded first. ```rust use fdt_edit::{Fdt, NodeType}; # fn main() -> Result<(), fdt_edit::FdtError> { # let dtb: &[u8] = &[]; // replace with real DTB bytes let fdt = Fdt::from_bytes(dtb)?; for node in fdt.find_compatible(&["pci-host-ecam-generic"]) { if let NodeType::Pci(pci) = node { let _bus_range = pci.bus_range(); let _interrupt_cells = pci.interrupt_cells(); } } # Ok(()) # } ``` -------------------------------- ### Serialize DTB to Bytes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Encodes a modified Device Tree Blob (DTB) back into a binary format. This is typically the final step after parsing and making changes. ```rust let encoded_dtb = fdt.encode()?; ``` -------------------------------- ### Fdt::from_ptr Source: https://context7.com/drivercraft/fdt-parser/llms.txt Parses an FDT from a raw pointer provided by a bootloader. The caller must ensure the pointer is valid and the memory remains accessible. ```APIDOC ## Fdt::from_ptr — Parse from a raw bootloader pointer Parses an FDT handed off by a bootloader via a raw pointer. The caller must guarantee the pointer is valid and the memory region lives at least as long as the returned `Fdt`. ```rust use fdt_edit::Fdt; /// # Safety /// `fdt_addr` must point to a valid, complete DTB in memory. unsafe fn init_from_bootloader(fdt_addr: usize) -> Fdt { let ptr = fdt_addr as *mut u8; Fdt::from_ptr(ptr).expect("invalid FDT from bootloader") } ``` ``` -------------------------------- ### Summarize PCI Host Bridge Information Source: https://context7.com/drivercraft/fdt-parser/llms.txt Iterates through PCI host bridge nodes, printing their bus range and interrupt cell count. It also details address mappings from ranges and resolves interrupts for specific devices. ```rust use fdt_edit::{Fdt, NodeType, PciSpace}; fn pci_summary(fdt: &Fdt) { for node in fdt.find_compatible(&["pci-host-ecam-generic"]) { let NodeType::Pci(pci) = node else { continue }; println!("PCI: {} bus-range={:?} #interrupt-cells={}", pci.path(), pci.bus_range(), pci.interrupt_cells()); if let Some(ranges) = pci.ranges() { for r in &ranges { println!(" {:?} bus={:#x} cpu={:#x} len={:#x}", r.space, r.bus_address, r.cpu_address, r.size); } } // Resolve IRQ for bus=0 device=2 function=0 INTA (pin=1) if let Ok(info) = pci.child_interrupts(0, 2, 0, 1) { println!(" device 2 INTA -> irqs={:?}", info.irqs); } } } ``` -------------------------------- ### List Interrupt Controller Nodes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Iterates through all nodes and prints information for nodes identified as interrupt controllers. Requires the `fdt_edit::{Fdt, NodeType}` imports. ```rust use fdt_edit::{Fdt, NodeType}; fn list_intc(fdt: &Fdt) { for node in fdt.all_nodes() { if let NodeType::InterruptController(intc) = node { println!("IntC : {}", intc.path()); println!(" #interrupt-cells = {:?}", intc.interrupt_cells()); println!(" compatibles = {:?}", intc.compatibles()); } } } ``` -------------------------------- ### Parse DTB from Bytes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Parses an existing Device Tree Blob (DTB) from a byte slice. This is the initial step for reading and manipulating DTB data. ```rust let fdt = Fdt::from_bytes(dtb_bytes)?; ``` -------------------------------- ### Fdt::from_bytes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Parses a byte slice containing a valid DTB binary into an editable `Fdt` structure. It validates the FDT magic, reads the header, and reconstructs the node tree. ```APIDOC ## Fdt::from_bytes — Parse an existing DTB blob Parses a `&[u8]` slice containing a valid DTB binary into an editable `Fdt`. The function validates the FDT magic, reads the header, and reconstructs the full node tree in the arena. Returns `Err(FdtError)` on malformed input. ```rust use fdt_edit::{Fdt, FdtError}; fn load_and_inspect(dtb_bytes: &[u8]) -> Result<(), FdtError> { let fdt = Fdt::from_bytes(dtb_bytes)?; println!("nodes : {}", fdt.node_count()); println!("cpu-id : {}", fdt.boot_cpuid_phys); println!("rsv blk : {} entries", fdt.memory_reservations.len()); // Inspect root let root = fdt.get_by_path("/").unwrap(); if let Some(model) = root.as_node().get_property("model") { println!("model = {:?}", model.as_str()); } Ok(()) } ``` ``` -------------------------------- ### `Property` — Raw property with typed accessors Source: https://context7.com/drivercraft/fdt-parser/llms.txt `Property` holds a `name: String` and `data: Vec`. It provides big-endian integer decoders, string/string-list decoders, and matching setters, letting callers work in native Rust types without touching raw bytes. ```APIDOC ## `Property` — Raw property with typed accessors `Property` holds a `name: String` and `data: Vec`. It provides big-endian integer decoders, string/string-list decoders, and matching setters, letting callers work in native Rust types without touching raw bytes. ``` -------------------------------- ### `Node` — Mutable device tree node Source: https://context7.com/drivercraft/fdt-parser/llms.txt `Node` stores a name, an ordered property list, and an ordered child-ID list. Properties are accessible by name via a `BTreeMap` cache for O(log n) lookup. Key helper methods decode standard DT properties without requiring raw byte manipulation. ```APIDOC ## `Node` — Mutable device tree node `Node` stores a name, an ordered property list, and an ordered child-ID list. Properties are accessible by name via a `BTreeMap` cache for O(log n) lookup. Key helper methods decode standard DT properties without requiring raw byte manipulation. ``` -------------------------------- ### Parse DTB from Pointer Source: https://context7.com/drivercraft/fdt-parser/llms.txt Parses a Device Tree Blob (DTB) directly from a memory pointer. This is often used in bootloaders or environments where the DTB is already loaded into memory. ```rust let fdt = Fdt::from_ptr(dtb_ptr)?; ``` -------------------------------- ### Encode FDT to DTB Bytes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Serializes an Fdt structure into a compliant DTB binary. This includes building the header, memory reservation block, structure block, and string table. Returns FdtData that dereferences to &[u8]. ```rust use fdt_edit::{Fdt, Node, Property, MemoryReservation}; fn build_and_encode() -> Vec { let mut fdt = Fdt::new(); fdt.boot_cpuid_phys = 0; // Reserve firmware memory fdt.memory_reservations.push(MemoryReservation { address: 0x8000_0000, size: 0x0010_0000, // 1 MB }); let root = fdt.root_id(); fdt.node_mut(root).unwrap() .set_property(Property::new("#address-cells", 2u32.to_be_bytes().to_vec())); fdt.node_mut(root).unwrap() .set_property(Property::new("#size-cells", 1u32.to_be_bytes().to_vec())); let mut mem = Node::new("memory@80000000"); mem.set_property(Property::new("device_type", b"memory\0".to_vec())); mem.set_property(Property::new("reg", { let mut v = 0x8000_0000u64.to_be_bytes().to_vec(); v.extend_from_slice(&0x4000_0000u32.to_be_bytes()); // 1 GB v })); fdt.add_node(root, mem); let dtb = fdt.encode(); // Round-trip check let reparsed = Fdt::from_bytes(&dtb).unwrap(); assert_eq!(reparsed.node_count(), fdt.node_count()); dtb.to_vec() } ``` -------------------------------- ### Fdt::add_node Source: https://context7.com/drivercraft/fdt-parser/llms.txt Inserts a new `Node` as a child of a specified parent node. It updates the parent's child list and name cache, and registers any `phandle`. ```APIDOC ## Fdt::add_node — Insert a child node Inserts a `Node` as a child of `parent` (identified by `NodeId`), updates the parent's child list and name cache, registers any `phandle` property in the cache, and returns the new node's `NodeId`. ```rust use fdt_edit::{Fdt, Node, Property}; let mut fdt = Fdt::new(); let root_id = fdt.root_id(); // /soc let soc_id = fdt.add_node(root_id, Node::new("soc")); // /soc/uart@10000 let mut uart = Node::new("uart@10000"); uart.set_property(Property::new("compatible", b"ns16550a\0".to_vec())); uart.set_property(Property::new( "reg", [0x00u8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00].to_vec(), )); uart.set_property(Property::new("status", b"okay\0".to_vec())); let uart_id = fdt.add_node(soc_id, uart); assert_eq!(fdt.path_of(uart_id), "/soc/uart@10000"); assert_eq!(fdt.node_count(), 3); // root + soc + uart ``` ``` -------------------------------- ### `MemoryNodeView` — Memory node helpers Source: https://context7.com/drivercraft/fdt-parser/llms.txt Nodes classified as `NodeType::Memory` expose `regions()` for address-translated memory region parsing and `total_size()` for the aggregate byte count across all regions. ```APIDOC ## `MemoryNodeView` — Memory node helpers Nodes classified as `NodeType::Memory` expose `regions()` for address-translated memory region parsing and `total_size()` for the aggregate byte count across all regions. ``` -------------------------------- ### Lookup Typed Node by Path or Alias Source: https://context7.com/drivercraft/fdt-parser/llms.txt Use `get_by_path` to resolve an absolute path or an alias into a classified `NodeType`. Returns `None` if the path is not found. ```rust use fdt_edit::{Fdt, NodeType}; fn inspect_path(fdt: &Fdt, path: &str) { match fdt.get_by_path(path) { Some(NodeType::Memory(mem)) => { println!(ירת{path}: Memory, {} region(s), total={:#x} B", mem.regions().len(), mem.total_size()); } Some(NodeType::Clock(clk)) => { println!(ירת{path}: Clock, #clock-cells={}", clk.clock_cells()); } Some(NodeType::InterruptController(intc)) => { println!(ירת{path}: IntC, #interrupt-cells={:?}", intc.interrupt_cells()); } Some(NodeType::Pci(pci)) => { println!(ירת{path}: PCI, bus-range={:?}", pci.bus_range()); } Some(NodeType::Generic(g)) => { println!(ירת{path}: Generic, compatibles: {:?}", g.as_view().as_node().compatibles().collect::>()); } None => println!(ירת{path}: not found"), } } ``` -------------------------------- ### Delete a subtree with Fdt::remove_node and Fdt::remove_by_path Source: https://context7.com/drivercraft/fdt-parser/llms.txt Remove a node and its entire subtree using `Fdt::remove_node` (by parent ID and child name) or `Fdt::remove_by_path` (by absolute path). Both methods return the `NodeId` of the removed node or `None` if not found. This is useful for cleaning up device tree configurations. ```rust use fdt_edit::{Fdt, Node}; let mut fdt = Fdt::new(); let root_id = fdt.root_id(); let soc_id = fdt.add_node(root_id, Node::new("soc")); let _uart = fdt.add_node(soc_id, Node::new("uart@10000")); let _i2c = fdt.add_node(soc_id, Node::new("i2c@20000")); assert_eq!(fdt.node_count(), 4); // Remove by parent + name fdt.remove_node(soc_id, "uart@10000"); assert_eq!(fdt.node_count(), 3); // Remove by path (takes entire subtree) fdt.remove_by_path("/soc"); assert_eq!(fdt.node_count(), 1); // only root remains ``` -------------------------------- ### Decode Clock References from 'clocks' Property Source: https://context7.com/drivercraft/fdt-parser/llms.txt Parses the 'clocks' property for each node, resolving clock references and printing details like phandle, cells, specifier, select index, and name. It also attempts to find the provider node. Requires `fdt_edit::{Fdt, NodeType}`. ```rust use fdt_edit::{Fdt, NodeType}; fn print_clock_refs(fdt: &Fdt) { for node in fdt.all_nodes() { let refs = node.clocks(); if refs.is_empty() { continue; } println!("{}: {} clock reference(s)", node.path(), refs.len()); for cr in &refs { // cr.select() returns the clock output index for providers with cells > 0 println!(" phandle={:?} cells={} specifier={:?} select={:?} name={:?}", cr.phandle, cr.cells, cr.specifier, cr.select(), cr.name); if let Some(provider) = fdt.get_by_phandle(cr.phandle) { println!(" provider = {}", provider.path()); } } } } ``` -------------------------------- ### `Fdt::encode` — Serialise the tree back to DTB bytes Source: https://context7.com/drivercraft/fdt-parser/llms.txt Encodes the entire `Fdt` into a standards-compliant DTB binary. This function builds the header, memory reservation block, structure block, and string table from scratch and returns an `FdtData` value that dereferences to `&[u8]`. ```APIDOC ## `Fdt::encode` — Serialise the tree back to DTB bytes Encodes the entire `Fdt` into a standards-compliant DTB binary, building the header, memory reservation block, structure block, and string table from scratch. Returns an `FdtData` value that derefs to `&[u8]`. ``` -------------------------------- ### Insert a child node with Fdt::add_node Source: https://context7.com/drivercraft/fdt-parser/llms.txt Add a new node as a child to a parent node using `Fdt::add_node`. This function updates parent-child relationships, name caches, and phandle registrations. It returns the `NodeId` of the newly created node. Properties can be set on the new node before or after adding it. ```rust use fdt_edit::{Fdt, Node, Property}; let mut fdt = Fdt::new(); let root_id = fdt.root_id(); // /soc let soc_id = fdt.add_node(root_id, Node::new("soc")); // /soc/uart@10000 let mut uart = Node::new("uart@10000"); uart.set_property(Property::new("compatible", b"ns16550a\0".to_vec())); uart.set_property(Property::new( "reg", [0x00u8, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00].to_vec(), )); uart.set_property(Property::new("status", b"okay\0".to_vec())); let uart_id = fdt.add_node(soc_id, uart); assert_eq!(fdt.path_of(uart_id), "/soc/uart@10000"); assert_eq!(fdt.node_count(), 3); // root + soc + uart ``` -------------------------------- ### Lookup Typed Node by Phandle Source: https://context7.com/drivercraft/fdt-parser/llms.txt Use `get_by_phandle` to look up a node by its numeric phandle value. This is useful for following cross-references like `interrupt-parent`. ```rust use fdt_edit::{Fdt, FdtError, Phandle}; fn resolve_interrupt_controller(fdt: &Fdt, device_path: &str) -> Option { let node = fdt.get_by_path(device_path)?; let phandle = node.interrupt_parent()?; let controller = fdt.get_by_phandle(phandle)?; Some(controller.path()) } // Example: prints "/interrupt-controller@fe600000" // let path = resolve_interrupt_controller(&fdt, "/mmc@fe2e0000"); ``` -------------------------------- ### View Memory Regions in FDT Source: https://context7.com/drivercraft/fdt-parser/llms.txt Provides access to memory nodes, allowing iteration over address-translated memory regions and retrieval of the total byte size across all regions. Requires nodes to be classified as NodeType::Memory. ```rust use fdt_edit::{Fdt, NodeType}; fn print_memory(fdt: &Fdt) { for node in fdt.all_nodes() { if let NodeType::Memory(mem) = node { println!("Memory node: {}", mem.path()); for r in mem.regions() { println!(" addr={:#018x} size={:#010x}", r.address, r.size); } println!(" total = {:#x} bytes", mem.total_size()); } } } ``` -------------------------------- ### Fdt::get_by_path Source: https://context7.com/drivercraft/fdt-parser/llms.txt Resolves an absolute path or an alias from the /aliases node into a classified NodeType. Returns None if the path is not found. ```APIDOC ## `Fdt::get_by_path` — Typed node lookup by absolute path or alias Resolves an absolute path (e.g. `"/soc/uart@10000"`) or an alias from the `/aliases` node into a classified `NodeType<'_>`. Returns `None` if the path is not found. ```rust use fdt_edit::{Fdt, NodeType}; fn inspect_path(fdt: &Fdt, path: &str) { match fdt.get_by_path(path) { Some(NodeType::Memory(mem)) => { println!("{path}: Memory, {} region(s), total={:#x} B", mem.regions().len(), mem.total_size()); } Some(NodeType::Clock(clk)) => { println!("{path}: Clock, #clock-cells={}", clk.clock_cells()); } Some(NodeType::InterruptController(intc)) => { println!("{path}: IntC, #interrupt-cells={:?}", intc.interrupt_cells()); } Some(NodeType::Pci(pci)) => { println!("{path}: PCI, bus-range={:?}", pci.bus_range()); } Some(NodeType::Generic(g)) => { println!("{path}: Generic, compatibles: {:?}", g.as_view().as_node().compatibles().collect::>()); } None => println!("{path}: not found"), } } ``` ```