libfdt: Add setprop_placeholder & Improve trimprop

Add a wrapper for the previously unsupported fdt_setprop_placeholder().

As fdt_setprop() internally calls fdt_setprop_placeholder()+memcpy(),
the previous implementation of trimprop() was effectively resulting in

    fdt_setprop_placeholder(..., len, ...);
    memcpy(data, data, len);

for which it needed to use getprop_internal() to play some tricks around
the borrow checker to make that memcpy have no effect. Instead, simply
implement it by calling fdt_setprop_placeholder() directly, making the C
calls more efficient and the Rust code simpler and safer.

Test: m pvmfw
Test: atest liblibfdt.integration_test
Change-Id: I4b847dd51c230d4c6c9b6b2efd6c45087544c955
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index d81c0c1..299b1d3 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -528,27 +528,13 @@
 
     /// Trims the size of the given property to new_size.
     pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
-        let (prop, len) =
-            FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
-        if len == new_size {
-            return Ok(());
-        }
-        if new_size > len {
-            return Err(FdtError::NoSpace);
-        }
+        let prop = self.as_node().getprop(name)?.ok_or(FdtError::NotFound)?;
 
-        // SAFETY: new_size is smaller than the old size
-        let ret = unsafe {
-            libfdt_bindgen::fdt_setprop(
-                self.fdt.as_mut_ptr(),
-                self.offset,
-                name.as_ptr(),
-                prop.cast::<c_void>(),
-                new_size.try_into().map_err(|_| FdtError::BadValue)?,
-            )
-        };
-
-        fdt_err_expect_zero(ret)
+        match prop.len() {
+            x if x == new_size => Ok(()),
+            x if x < new_size => Err(FdtError::NoSpace),
+            _ => self.fdt.setprop_placeholder(self.offset, name, new_size).map(|_| ()),
+        }
     }
 
     /// Returns reference to the containing device tree.
diff --git a/libs/libfdt/src/libfdt.rs b/libs/libfdt/src/libfdt.rs
index a89738f..7fa217b 100644
--- a/libs/libfdt/src/libfdt.rs
+++ b/libs/libfdt/src/libfdt.rs
@@ -261,6 +261,21 @@
 
         fdt_err(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();
+        let name = name.as_ptr();
+        let len = size.try_into().unwrap();
+        let mut data = ptr::null_mut();
+        let ret =
+            // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
+            unsafe { libfdt_bindgen::fdt_setprop_placeholder(fdt, node, name, len, &mut data) };
+
+        fdt_err_expect_zero(ret)?;
+
+        get_mut_slice_at_ptr(self.as_fdt_slice_mut(), data.cast(), size).ok_or(FdtError::Internal)
+    }
 }
 
 pub(crate) fn get_slice_at_ptr(s: &[u8], p: *const u8, len: usize) -> Option<&[u8]> {
@@ -269,6 +284,12 @@
     s.get(offset..offset.checked_add(len)?)
 }
 
+fn get_mut_slice_at_ptr(s: &mut [u8], p: *mut u8, len: usize) -> Option<&mut [u8]> {
+    let offset = get_slice_ptr_offset(s, p)?;
+
+    s.get_mut(offset..offset.checked_add(len)?)
+}
+
 fn get_slice_from_ptr(s: &[u8], p: *const u8) -> Option<&[u8]> {
     s.get(get_slice_ptr_offset(s, p)?..)
 }