[fdt] Add function to get the first range in /memory node of fdt

and test it. This function will be reused later in both pvmfw and
rialto.

Test: atest liblibfdt.integration_test
Test: atest vmbase_example.integration_test
Test: m pvmfw_img
Bug: 284462758
Change-Id: Ic547530f911281c2db14b9a59b7e2470be10361f
diff --git a/libs/libfdt/Android.bp b/libs/libfdt/Android.bp
index 55cb01b..2a6e75f 100644
--- a/libs/libfdt/Android.bp
+++ b/libs/libfdt/Android.bp
@@ -51,7 +51,10 @@
     srcs: ["tests/*.rs"],
     test_suites: ["general-tests"],
     data: [
-        ":fdt_data_test_tree1_dtb",
+        ":fdt_test_tree_one_memory_range_dtb",
+        ":fdt_test_tree_multiple_memory_ranges_dtb",
+        ":fdt_test_tree_empty_memory_range_dtb",
+        ":fdt_test_tree_no_memory_node_dtb",
     ],
     prefer_rlib: true,
     rustlibs: [
@@ -60,9 +63,29 @@
 }
 
 genrule {
-    name: "fdt_data_test_tree1_dtb",
-    tools: ["dtc"],
-    srcs: ["tests/data/test_tree1.dts"],
-    out: ["data/test_tree1.dtb"],
-    cmd: "$(location dtc) -O dtb -I dts -o $(out) $(in)",
+    name: "fdt_test_tree_one_memory_range_dtb",
+    defaults: ["test_avf_dts_to_dtb"],
+    srcs: ["tests/data/test_tree_one_memory_range.dts"],
+    out: ["data/test_tree_one_memory_range.dtb"],
+}
+
+genrule {
+    name: "fdt_test_tree_multiple_memory_ranges_dtb",
+    defaults: ["test_avf_dts_to_dtb"],
+    srcs: ["tests/data/test_tree_multiple_memory_ranges.dts"],
+    out: ["data/test_tree_multiple_memory_ranges.dtb"],
+}
+
+genrule {
+    name: "fdt_test_tree_empty_memory_range_dtb",
+    defaults: ["test_avf_dts_to_dtb"],
+    srcs: ["tests/data/test_tree_empty_memory_range.dts"],
+    out: ["data/test_tree_empty_memory_range.dtb"],
+}
+
+genrule {
+    name: "fdt_test_tree_no_memory_node_dtb",
+    defaults: ["test_avf_dts_to_dtb"],
+    srcs: ["tests/data/test_tree_no_memory_node.dts"],
+    out: ["data/test_tree_no_memory_node.dtb"],
 }
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 91214b3..8e0bb65 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -25,6 +25,7 @@
 use core::ffi::{c_int, c_void, CStr};
 use core::fmt;
 use core::mem;
+use core::ops::Range;
 use core::result;
 use zerocopy::AsBytes as _;
 
@@ -716,23 +717,24 @@
         Ok(self)
     }
 
-    /// Return an iterator of memory banks specified the "/memory" node.
+    /// Returns an iterator of memory banks specified the "/memory" node.
+    /// Throws an error when the "/memory" is not found in the device tree.
     ///
     /// NOTE: This does not support individual "/memory@XXXX" banks.
-    pub fn memory(&self) -> Result<Option<MemRegIterator>> {
-        let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
-        let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
+    pub fn memory(&self) -> Result<MemRegIterator> {
+        let memory_node_name = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
+        let memory_device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
 
-        if let Some(node) = self.node(memory)? {
-            if node.device_type()? != Some(device_type) {
-                return Err(FdtError::BadValue);
-            }
-            let reg = node.reg()?.ok_or(FdtError::BadValue)?;
-
-            Ok(Some(MemRegIterator::new(reg)))
-        } else {
-            Ok(None)
+        let node = self.node(memory_node_name)?.ok_or(FdtError::NotFound)?;
+        if node.device_type()? != Some(memory_device_type) {
+            return Err(FdtError::BadValue);
         }
+        node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
+    }
+
+    /// Returns the first memory range in the `/memory` node.
+    pub fn first_memory_range(&self) -> Result<Range<usize>> {
+        self.memory()?.next().ok_or(FdtError::NotFound)
     }
 
     /// Retrieve the standard /chosen node.
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index d0feb98..806e6c0 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -16,18 +16,57 @@
 
 //! Integration tests of the library libfdt.
 
-use libfdt::Fdt;
+use libfdt::{Fdt, FdtError};
 use std::fs;
 use std::ops::Range;
 
-const TEST_TREE1_PATH: &str = "data/test_tree1.dtb";
+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";
+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";
 
 #[test]
-fn parse_well_formed_fdt_successfully() {
-    let data = fs::read(TEST_TREE1_PATH).unwrap();
+fn retrieving_memory_from_fdt_with_one_memory_range_succeeds() {
+    let data = fs::read(TEST_TREE_WITH_ONE_MEMORY_RANGE_PATH).unwrap();
     let fdt = Fdt::from_slice(&data).unwrap();
 
     const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
-    let mut memory = fdt.memory().unwrap().unwrap();
+    let mut memory = fdt.memory().unwrap();
     assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
+    assert!(memory.next().is_none());
+    assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
+}
+
+#[test]
+fn retrieving_memory_from_fdt_with_multiple_memory_ranges_succeeds() {
+    let data = fs::read(TEST_TREE_WITH_MULTIPLE_MEMORY_RANGES_PATH).unwrap();
+    let fdt = Fdt::from_slice(&data).unwrap();
+
+    const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
+    const EXPECTED_SECOND_MEMORY_RANGE: Range<usize> = 512..1024;
+    let mut memory = fdt.memory().unwrap();
+    assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
+    assert_eq!(memory.next(), Some(EXPECTED_SECOND_MEMORY_RANGE));
+    assert!(memory.next().is_none());
+    assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
+}
+
+#[test]
+fn retrieving_first_memory_from_fdt_with_empty_memory_range_fails() {
+    let data = fs::read(TEST_TREE_WITH_EMPTY_MEMORY_RANGE_PATH).unwrap();
+    let fdt = Fdt::from_slice(&data).unwrap();
+
+    let mut memory = fdt.memory().unwrap();
+    assert!(memory.next().is_none());
+    assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
+}
+
+#[test]
+fn retrieving_memory_from_fdt_with_no_memory_node_fails() {
+    let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
+    let fdt = Fdt::from_slice(&data).unwrap();
+
+    assert_eq!(fdt.memory().unwrap_err(), FdtError::NotFound);
+    assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
 }
diff --git a/libs/libfdt/tests/data/test_tree_empty_memory_range.dts b/libs/libfdt/tests/data/test_tree_empty_memory_range.dts
new file mode 100644
index 0000000..c263ff3
--- /dev/null
+++ b/libs/libfdt/tests/data/test_tree_empty_memory_range.dts
@@ -0,0 +1,8 @@
+/include/ "test_tree_no_memory_node.dts"
+
+/ {
+	memory {
+		device_type = "memory";
+		reg = <>;
+	};
+};
diff --git a/libs/libfdt/tests/data/test_tree_multiple_memory_ranges.dts b/libs/libfdt/tests/data/test_tree_multiple_memory_ranges.dts
new file mode 100644
index 0000000..b2ded7f
--- /dev/null
+++ b/libs/libfdt/tests/data/test_tree_multiple_memory_ranges.dts
@@ -0,0 +1,8 @@
+/include/ "test_tree_no_memory_node.dts"
+
+/ {
+	memory {
+		device_type = "memory";
+		reg = <0x0 0x100 0x200 0x200>;
+	};
+};
diff --git a/libs/libfdt/tests/data/test_tree1.dts b/libs/libfdt/tests/data/test_tree_no_memory_node.dts
similarity index 89%
rename from libs/libfdt/tests/data/test_tree1.dts
rename to libs/libfdt/tests/data/test_tree_no_memory_node.dts
index 222b0b1..35e02cd 100644
--- a/libs/libfdt/tests/data/test_tree1.dts
+++ b/libs/libfdt/tests/data/test_tree_no_memory_node.dts
@@ -33,11 +33,6 @@
 		};
 	};
 
-	memory {
-		device_type = "memory";
-		reg = <0x0 0x100>;
-	};
-
 	chosen {
 	};
 };
diff --git a/libs/libfdt/tests/data/test_tree_one_memory_range.dts b/libs/libfdt/tests/data/test_tree_one_memory_range.dts
new file mode 100644
index 0000000..7f863b3
--- /dev/null
+++ b/libs/libfdt/tests/data/test_tree_one_memory_range.dts
@@ -0,0 +1,8 @@
+/include/ "test_tree_no_memory_node.dts"
+
+/ {
+	memory {
+		device_type = "memory";
+		reg = <0x0 0x100>;
+	};
+};
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 216ac9c..ab851a1 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -106,11 +106,6 @@
     node.setprop(cstr!("bootargs"), bootargs.to_bytes_with_nul())
 }
 
-/// Read the first range in /memory node in DT
-fn read_memory_range_from(fdt: &Fdt) -> libfdt::Result<Range<usize>> {
-    fdt.memory()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
-}
-
 /// Check if memory range is ok
 fn validate_memory_range(range: &Range<usize>) -> Result<(), RebootReason> {
     let base = range.start;
@@ -613,7 +608,7 @@
         RebootReason::InvalidFdt
     })?;
 
-    let memory_range = read_memory_range_from(fdt).map_err(|e| {
+    let memory_range = fdt.first_memory_range().map_err(|e| {
         error!("Failed to read memory range from DT: {e}");
         RebootReason::InvalidFdt
     })?;
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 873cc38..8478f98 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -3,21 +3,21 @@
 }
 
 genrule_defaults {
-    name: "test_avf_debug_policy_overlay",
+    name: "test_avf_dts_to_dtb",
     tools: ["dtc"],
     cmd: "$(location dtc) -I dts -O dtb $(in) -o $(out)",
 }
 
 genrule {
     name: "test_avf_debug_policy_with_adb",
-    defaults: ["test_avf_debug_policy_overlay"],
+    defaults: ["test_avf_dts_to_dtb"],
     srcs: ["assets/avf_debug_policy_with_adb.dts"],
     out: ["avf_debug_policy_with_adb.dtbo"],
 }
 
 genrule {
     name: "test_avf_debug_policy_without_adb",
-    defaults: ["test_avf_debug_policy_overlay"],
+    defaults: ["test_avf_dts_to_dtb"],
     srcs: ["assets/avf_debug_policy_without_adb.dts"],
     out: ["avf_debug_policy_without_adb.dtbo"],
 }
diff --git a/vmbase/example/src/main.rs b/vmbase/example/src/main.rs
index 90a0ec2..adda406 100644
--- a/vmbase/example/src/main.rs
+++ b/vmbase/example/src/main.rs
@@ -195,7 +195,7 @@
 }
 
 fn check_fdt(reader: &Fdt) {
-    for reg in reader.memory().unwrap().unwrap() {
+    for reg in reader.memory().unwrap() {
         info!("memory @ {reg:#x?}");
     }