libfdt: Add phandle APIs
This CL adds following APIs
- Fdt::max_phandle(): Returns the max phandle
- Fdt::node_with_phandle(): Returns the node with phandle
Bug: 277993056
Test: atest liblibfdt.integration_test
Change-Id: I155242718b09897e832834a621f9e244ed2d9807
diff --git a/libs/libfdt/Android.bp b/libs/libfdt/Android.bp
index 0a05471..b889ee5 100644
--- a/libs/libfdt/Android.bp
+++ b/libs/libfdt/Android.bp
@@ -57,6 +57,7 @@
":fdt_test_tree_multiple_memory_ranges_dtb",
":fdt_test_tree_empty_memory_range_dtb",
":fdt_test_tree_no_memory_node_dtb",
+ ":fdt_test_tree_phandle_dtb",
],
prefer_rlib: true,
rustlibs: [
@@ -91,3 +92,10 @@
srcs: ["tests/data/test_tree_no_memory_node.dts"],
out: ["data/test_tree_no_memory_node.dtb"],
}
+
+genrule {
+ name: "fdt_test_tree_phandle_dtb",
+ defaults: ["dts_to_dtb"],
+ srcs: ["tests/data/test_tree_phandle.dts"],
+ out: ["data/test_tree_phandle.dtb"],
+}
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 5a7bd14..2a547e8 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -499,6 +499,27 @@
}
}
+/// Phandle of a FDT node
+#[repr(transparent)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct Phandle(u32);
+
+impl Phandle {
+ /// Creates a new Phandle
+ pub fn new(value: u32) -> Result<Self> {
+ if value == 0 || value > libfdt_bindgen::FDT_MAX_PHANDLE {
+ return Err(FdtError::BadPhandle);
+ }
+ Ok(Self(value))
+ }
+}
+
+impl From<Phandle> for u32 {
+ fn from(phandle: Phandle) -> u32 {
+ phandle.0
+ }
+}
+
/// Mutable FDT node.
pub struct FdtNodeMut<'a> {
fdt: &'a mut Fdt,
@@ -879,6 +900,23 @@
CompatibleIterator::new(self, compatible)
}
+ /// Returns max phandle in the tree.
+ pub fn max_phandle(&self) -> Result<Phandle> {
+ let mut phandle: u32 = 0;
+ // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+ let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(self.as_ptr(), &mut phandle) };
+
+ fdt_err_expect_zero(ret)?;
+ Phandle::new(phandle)
+ }
+
+ /// Returns a node with the phandle
+ pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
+ // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+ let ret = unsafe { libfdt_bindgen::fdt_node_offset_by_phandle(self.as_ptr(), phandle.0) };
+ Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self, offset }))
+ }
+
/// Returns the mutable root node of the tree.
pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
self.node_mut(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index ccbf9a5..5484185 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -16,7 +16,7 @@
//! Integration tests of the library libfdt.
-use libfdt::{Fdt, FdtError};
+use libfdt::{Fdt, FdtError, Phandle};
use std::ffi::CStr;
use std::fs;
use std::ops::Range;
@@ -32,6 +32,7 @@
"data/test_tree_multiple_memory_ranges.dtb";
const TEST_TREE_WITH_EMPTY_MEMORY_RANGE_PATH: &str = "data/test_tree_empty_memory_range.dtb";
const TEST_TREE_WITH_NO_MEMORY_NODE_PATH: &str = "data/test_tree_no_memory_node.dtb";
+const TEST_TREE_PHANDLE_PATH: &str = "data/test_tree_phandle.dtb";
#[test]
fn retrieving_memory_from_fdt_with_one_memory_range_succeeds() {
@@ -138,3 +139,33 @@
assert_eq!(supernode.name().unwrap().to_str().unwrap(), *expect);
}
}
+
+#[test]
+fn phandle_new() {
+ let phandle_u32 = 0x55;
+ let phandle = Phandle::new(phandle_u32).unwrap();
+
+ assert_eq!(u32::from(phandle), phandle_u32);
+}
+
+#[test]
+fn max_phandle() {
+ let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
+ let fdt = Fdt::from_slice(&data).unwrap();
+
+ assert_eq!(fdt.max_phandle().unwrap(), Phandle::new(0xFF).unwrap());
+}
+
+#[test]
+fn node_with_phandle() {
+ let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
+ let fdt = Fdt::from_slice(&data).unwrap();
+
+ // Test linux,phandle
+ let node = fdt.node_with_phandle(Phandle::new(0xFF).unwrap()).unwrap().unwrap();
+ assert_eq!(node.name().unwrap().to_str().unwrap(), "node_zz");
+
+ // Test phandle
+ let node = fdt.node_with_phandle(Phandle::new(0x22).unwrap()).unwrap().unwrap();
+ assert_eq!(node.name().unwrap().to_str().unwrap(), "node_abc");
+}
diff --git a/libs/libfdt/tests/data/test_tree_phandle.dts b/libs/libfdt/tests/data/test_tree_phandle.dts
new file mode 100644
index 0000000..0438241
--- /dev/null
+++ b/libs/libfdt/tests/data/test_tree_phandle.dts
@@ -0,0 +1,35 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+ node_a {
+ phandle = <0x1>;
+ node_ab {
+ node_abc {
+ linux,phandle = <0x22>;
+ };
+ };
+ };
+
+ node_b {
+ };
+
+ node_c {
+ };
+
+ node_z {
+ node_za {
+ };
+
+ node_zb {
+
+ };
+
+ node_zz {
+ phandle = <0xFF>;
+
+ node_zzz {
+ };
+ };
+ };
+};
\ No newline at end of file