libfdt: Add FdtNode::supernode_at_depth()
This is helpful to locate special node (e.g. __overlay__).
Bug: 277993056
Test: atest liblibfdt.integration_test
Change-Id: I833e586437f0e5934a448dddf80d1bd947c3bd4f
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 03a1f8e..5a7bd14 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -29,6 +29,7 @@
use core::fmt;
use core::mem;
use core::ops::Range;
+use core::ptr;
use core::result;
use zerocopy::AsBytes as _;
@@ -279,6 +280,21 @@
Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
}
+ /// Returns supernode with depth. Note that root is at depth 0.
+ pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
+ // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+ let ret = unsafe {
+ libfdt_bindgen::fdt_supernode_atdepth_offset(
+ self.fdt.as_ptr(),
+ self.offset,
+ depth.try_into().unwrap(),
+ ptr::null_mut(),
+ )
+ };
+
+ Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
+ }
+
/// Returns the standard (deprecated) device_type <string> property.
pub fn device_type(&self) -> Result<Option<&CStr>> {
self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index 9be1bf9..ccbf9a5 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -21,6 +21,12 @@
use std::fs;
use std::ops::Range;
+macro_rules! cstr {
+ ($str:literal) => {{
+ CStr::from_bytes_with_nul(concat!($str, "\0").as_bytes()).unwrap()
+ }};
+}
+
const TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH: &str = "data/test_tree_one_memory_range.dtb";
const TEST_TREE_WITH_MULTIPLE_MEMORY_RANGES_PATH: &str =
"data/test_tree_multiple_memory_ranges.dtb";
@@ -83,7 +89,7 @@
let chosen = fdt.chosen().unwrap().unwrap();
assert_eq!(chosen.name().unwrap().to_str().unwrap(), "chosen");
- let nested_node_path = CStr::from_bytes_with_nul(b"/cpus/PowerPC,970@0\0").unwrap();
+ let nested_node_path = cstr!("/cpus/PowerPC,970@0");
let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
assert_eq!(nested_node.name().unwrap().to_str().unwrap(), "PowerPC,970@0");
}
@@ -119,3 +125,16 @@
assert_eq!(prop.value().unwrap(), value);
}
}
+
+#[test]
+fn node_supernode_at_depth() {
+ let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
+ let fdt = Fdt::from_slice(&data).unwrap();
+ let node = fdt.node(cstr!("/cpus/PowerPC,970@1")).unwrap().unwrap();
+ let expected = &["", "cpus", "PowerPC,970@1"];
+
+ for (depth, expect) in expected.iter().enumerate() {
+ let supernode = node.supernode_at_depth(depth).unwrap();
+ assert_eq!(supernode.name().unwrap().to_str().unwrap(), *expect);
+ }
+}