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]> {