libfdt: Move FFI for DT properties to Libfdt*

Move all the functions dealing with DT properties to the new traits.

Reduce the unsafe blocks to the strict minimum (i.e. the FFI calls).

Test: m pvmfw
Test: atest liblibfdt.integration_test
Change-Id: I98698a7ae9b6874c329c8a7bf902b33c7e7a453d
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 299b1d3..ab3c83f 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -95,17 +95,7 @@
 
 impl FdtPropertyStruct {
     fn from_offset(fdt: &Fdt, offset: c_int) -> Result<&Self> {
-        let mut len = 0;
-        let prop =
-            // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
-            unsafe { libfdt_bindgen::fdt_get_property_by_offset(fdt.as_ptr(), offset, &mut len) };
-        if prop.is_null() {
-            fdt_err(len)?;
-            return Err(FdtError::Internal); // shouldn't happen.
-        }
-        // SAFETY: prop is only returned when it points to valid libfdt_bindgen.
-        let prop = unsafe { &*prop };
-        Ok(prop.as_ref())
+        Ok(fdt.get_property_by_offset(offset)?.as_ref())
     }
 
     fn name_offset(&self) -> c_int {
@@ -146,11 +136,7 @@
     }
 
     fn next_property(&self) -> Result<Option<Self>> {
-        let ret =
-            // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
-            unsafe { libfdt_bindgen::fdt_next_property_offset(self.fdt.as_ptr(), self.offset) };
-
-        if let Some(offset) = fdt_err_or_option(ret)? {
+        if let Some(offset) = self.fdt.next_property_offset(self.offset)? {
             Ok(Some(Self::new(self.fdt, offset)?))
         } else {
             Ok(None)
@@ -261,44 +247,7 @@
 
     /// Returns the value of a given property.
     pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
-        if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
-            Ok(Some(self.fdt.get_from_ptr(prop, len)?))
-        } else {
-            Ok(None)
-        }
-    }
-
-    /// Returns the pointer and size of the property named `name`, in a node at offset `offset`, in
-    /// a device tree `fdt`. The pointer is guaranteed to be non-null, in which case error returns.
-    fn getprop_internal(
-        fdt: &'a Fdt,
-        offset: c_int,
-        name: &CStr,
-    ) -> Result<Option<(*const c_void, usize)>> {
-        let mut len: i32 = 0;
-        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
-        // function respects the passed number of characters.
-        let prop = unsafe {
-            libfdt_bindgen::fdt_getprop_namelen(
-                fdt.as_ptr(),
-                offset,
-                name.as_ptr(),
-                // *_namelen functions don't include the trailing nul terminator in 'len'.
-                name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
-                &mut len as *mut i32,
-            )
-        } as *const u8;
-
-        let Some(len) = fdt_err_or_option(len)? else {
-            return Ok(None); // Property was not found.
-        };
-        let len = usize::try_from(len).unwrap();
-
-        if prop.is_null() {
-            // We expected an error code in len but still received a valid value?!
-            return Err(FdtError::Internal);
-        }
-        Ok(Some((prop.cast::<c_void>(), len)))
+        self.fdt.getprop_namelen(self.offset, name.to_bytes())
     }
 
     /// Returns reference to the containing device tree.
@@ -362,11 +311,7 @@
     }
 
     fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
-        let ret =
-            // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
-            unsafe { libfdt_bindgen::fdt_first_property_offset(self.fdt.as_ptr(), self.offset) };
-
-        if let Some(offset) = fdt_err_or_option(ret)? {
+        if let Some(offset) = self.fdt.first_property_offset(self.offset)? {
             Ok(Some(FdtProperty::new(self.fdt, offset)?))
         } else {
             Ok(None)
@@ -417,54 +362,20 @@
 impl<'a> FdtNodeMut<'a> {
     /// Appends a property name-value (possibly empty) pair to the given node.
     pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
-        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
-        let ret = unsafe {
-            libfdt_bindgen::fdt_appendprop(
-                self.fdt.as_mut_ptr(),
-                self.offset,
-                name.as_ptr(),
-                value.as_ref().as_ptr().cast::<c_void>(),
-                value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
-            )
-        };
-
-        fdt_err_expect_zero(ret)
+        self.fdt.appendprop(self.offset, name, value.as_ref())
     }
 
     /// Appends a (address, size) pair property to the given node.
     pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
-        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
-        let ret = unsafe {
-            libfdt_bindgen::fdt_appendprop_addrrange(
-                self.fdt.as_mut_ptr(),
-                self.parent()?.offset,
-                self.offset,
-                name.as_ptr(),
-                addr,
-                size,
-            )
-        };
-
-        fdt_err_expect_zero(ret)
+        let parent = self.parent()?.offset;
+        self.fdt.appendprop_addrrange(parent, self.offset, name, addr, size)
     }
 
     /// Sets a property name-value pair to the given node.
     ///
     /// This may create a new prop or replace existing value.
     pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
-        // SAFETY: New value size is constrained to the DT totalsize
-        //          (validated by underlying libfdt).
-        let ret = unsafe {
-            libfdt_bindgen::fdt_setprop(
-                self.fdt.as_mut_ptr(),
-                self.offset,
-                name.as_ptr(),
-                value.as_ptr().cast::<c_void>(),
-                value.len().try_into().map_err(|_| FdtError::BadValue)?,
-            )
-        };
-
-        fdt_err_expect_zero(ret)
+        self.fdt.setprop(self.offset, name, value)
     }
 
     /// Sets the value of the given property with the given value, and ensure that the given
@@ -472,18 +383,7 @@
     ///
     /// This can only be used to replace existing value.
     pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
-        // SAFETY: fdt size is not altered
-        let ret = unsafe {
-            libfdt_bindgen::fdt_setprop_inplace(
-                self.fdt.as_mut_ptr(),
-                self.offset,
-                name.as_ptr(),
-                value.as_ptr().cast::<c_void>(),
-                value.len().try_into().map_err(|_| FdtError::BadValue)?,
-            )
-        };
-
-        fdt_err_expect_zero(ret)
+        self.fdt.setprop_inplace(self.offset, name, value)
     }
 
     /// Sets the value of the given (address, size) pair property with the given value, and
@@ -492,38 +392,24 @@
     /// This can only be used to replace existing value.
     pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
         let pair = [addr.to_be(), size.to_be()];
-        self.setprop_inplace(name, pair.as_bytes())
+        self.fdt.setprop_inplace(self.offset, name, pair.as_bytes())
     }
 
     /// Sets a flag-like empty property.
     ///
     /// This may create a new prop or replace existing value.
     pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
-        self.setprop(name, &[])
+        self.fdt.setprop(self.offset, name, &[])
     }
 
     /// Deletes the given property.
     pub fn delprop(&mut self, name: &CStr) -> Result<()> {
-        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
-        // library locates the node's property. Removing the property may shift the offsets of
-        // other nodes and properties but the borrow checker should prevent this function from
-        // being called when FdtNode instances are in use.
-        let ret = unsafe {
-            libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
-        };
-
-        fdt_err_expect_zero(ret)
+        self.fdt.delprop(self.offset, name)
     }
 
     /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
     pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
-        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
-        // library locates the node's property.
-        let ret = unsafe {
-            libfdt_bindgen::fdt_nop_property(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
-        };
-
-        fdt_err_expect_zero(ret)
+        self.fdt.nop_property(self.offset, name)
     }
 
     /// Trims the size of the given property to new_size.
diff --git a/libs/libfdt/src/libfdt.rs b/libs/libfdt/src/libfdt.rs
index 7fa217b..31b125a 100644
--- a/libs/libfdt/src/libfdt.rs
+++ b/libs/libfdt/src/libfdt.rs
@@ -198,6 +198,60 @@
         get_slice_at_ptr(self.as_fdt_slice(), name.cast(), len).ok_or(FdtError::Internal)
     }
 
+    /// Safe wrapper around `fdt_getprop_namelen()` (C function).
+    fn getprop_namelen(&self, node: c_int, name: &[u8]) -> Result<Option<&[u8]>> {
+        let fdt = self.as_fdt_slice().as_ptr().cast();
+        let namelen = name.len().try_into().map_err(|_| FdtError::BadPath)?;
+        let name = name.as_ptr().cast();
+        let mut len = 0;
+        let prop =
+            // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
+            // function respects the passed number of characters.
+            unsafe { libfdt_bindgen::fdt_getprop_namelen(fdt, node, name, namelen, &mut len) };
+
+        if let Some(len) = fdt_err_or_option(len)? {
+            let len = usize::try_from(len).unwrap();
+            let bytes = get_slice_at_ptr(self.as_fdt_slice(), prop.cast(), len);
+
+            Ok(Some(bytes.ok_or(FdtError::Internal)?))
+        } else {
+            Ok(None)
+        }
+    }
+
+    /// Safe wrapper around `fdt_get_property_by_offset()` (C function).
+    fn get_property_by_offset(&self, offset: c_int) -> Result<&libfdt_bindgen::fdt_property> {
+        let mut len = 0;
+        let fdt = self.as_fdt_slice().as_ptr().cast();
+        // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+        let prop = unsafe { libfdt_bindgen::fdt_get_property_by_offset(fdt, offset, &mut len) };
+        if prop.is_null() {
+            fdt_err(len)?;
+            return Err(FdtError::Internal); // shouldn't happen.
+        }
+
+        // SAFETY: prop is only returned when it points to valid libfdt_bindgen.
+        Ok(unsafe { &*prop })
+    }
+
+    /// Safe wrapper around `fdt_first_property_offset()` (C function).
+    fn first_property_offset(&self, node: c_int) -> Result<Option<c_int>> {
+        let fdt = self.as_fdt_slice().as_ptr().cast();
+        // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+        let ret = unsafe { libfdt_bindgen::fdt_first_property_offset(fdt, node) };
+
+        fdt_err_or_option(ret)
+    }
+
+    /// Safe wrapper around `fdt_next_property_offset()` (C function).
+    fn next_property_offset(&self, prev: c_int) -> Result<Option<c_int>> {
+        let fdt = self.as_fdt_slice().as_ptr().cast();
+        // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+        let ret = unsafe { libfdt_bindgen::fdt_next_property_offset(fdt, prev) };
+
+        fdt_err_or_option(ret)
+    }
+
     /// Safe wrapper around `fdt_find_max_phandle()` (C function).
     fn find_max_phandle(&self) -> Result<Phandle> {
         let fdt = self.as_fdt_slice().as_ptr().cast();
@@ -262,6 +316,19 @@
         fdt_err(ret)
     }
 
+    /// Safe wrapper around `fdt_setprop()` (C function).
+    fn setprop(&mut self, node: c_int, name: &CStr, value: &[u8]) -> Result<()> {
+        let fdt = self.as_fdt_slice_mut().as_mut_ptr().cast();
+        let name = name.as_ptr();
+        let len = value.len().try_into().map_err(|_| FdtError::BadValue)?;
+        let value = value.as_ptr().cast();
+        // SAFETY: New value size is constrained to the DT totalsize
+        //          (validated by underlying libfdt).
+        let ret = unsafe { libfdt_bindgen::fdt_setprop(fdt, node, name, value, len) };
+
+        fdt_err_expect_zero(ret)
+    }
+
     /// Safe wrapper around `fdt_setprop_placeholder()` (C function).
     fn setprop_placeholder(&mut self, node: c_int, name: &CStr, size: usize) -> Result<&mut [u8]> {
         let fdt = self.as_fdt_slice_mut().as_mut_ptr().cast();
@@ -276,6 +343,74 @@
 
         get_mut_slice_at_ptr(self.as_fdt_slice_mut(), data.cast(), size).ok_or(FdtError::Internal)
     }
+
+    /// Safe wrapper around `fdt_setprop_inplace()` (C function).
+    fn setprop_inplace(&mut self, node: c_int, name: &CStr, value: &[u8]) -> Result<()> {
+        let fdt = self.as_fdt_slice_mut().as_mut_ptr().cast();
+        let name = name.as_ptr();
+        let len = value.len().try_into().map_err(|_| FdtError::BadValue)?;
+        let value = value.as_ptr().cast();
+        // SAFETY: New value size is constrained to the DT totalsize
+        //          (validated by underlying libfdt).
+        let ret = unsafe { libfdt_bindgen::fdt_setprop_inplace(fdt, node, name, value, len) };
+
+        fdt_err_expect_zero(ret)
+    }
+
+    /// Safe wrapper around `fdt_appendprop()` (C function).
+    fn appendprop(&mut self, node: c_int, name: &CStr, value: &[u8]) -> Result<()> {
+        let fdt = self.as_fdt_slice_mut().as_mut_ptr().cast();
+        let name = name.as_ptr();
+        let len = value.len().try_into().map_err(|_| FdtError::BadValue)?;
+        let value = value.as_ptr().cast();
+        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
+        let ret = unsafe { libfdt_bindgen::fdt_appendprop(fdt, node, name, value, len) };
+
+        fdt_err_expect_zero(ret)
+    }
+
+    /// Safe wrapper around `fdt_appendprop_addrrange()` (C function).
+    fn appendprop_addrrange(
+        &mut self,
+        parent: c_int,
+        node: c_int,
+        name: &CStr,
+        addr: u64,
+        size: u64,
+    ) -> Result<()> {
+        let fdt = self.as_fdt_slice_mut().as_mut_ptr().cast();
+        let name = name.as_ptr();
+        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
+        let ret = unsafe {
+            libfdt_bindgen::fdt_appendprop_addrrange(fdt, parent, node, name, addr, size)
+        };
+
+        fdt_err_expect_zero(ret)
+    }
+
+    /// Safe wrapper around `fdt_delprop()` (C function).
+    fn delprop(&mut self, node: c_int, name: &CStr) -> Result<()> {
+        let fdt = self.as_fdt_slice_mut().as_mut_ptr().cast();
+        let name = name.as_ptr();
+        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
+        // library locates the node's property. Removing the property may shift the offsets of
+        // other nodes and properties but the borrow checker should prevent this function from
+        // being called when FdtNode instances are in use.
+        let ret = unsafe { libfdt_bindgen::fdt_delprop(fdt, node, name) };
+
+        fdt_err_expect_zero(ret)
+    }
+
+    /// Safe wrapper around `fdt_nop_property()` (C function).
+    fn nop_property(&mut self, node: c_int, name: &CStr) -> Result<()> {
+        let fdt = self.as_fdt_slice_mut().as_mut_ptr().cast();
+        let name = name.as_ptr();
+        // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
+        // library locates the node's property.
+        let ret = unsafe { libfdt_bindgen::fdt_nop_property(fdt, node, name) };
+
+        fdt_err_expect_zero(ret)
+    }
 }
 
 pub(crate) fn get_slice_at_ptr(s: &[u8], p: *const u8, len: usize) -> Option<&[u8]> {