libfdt: Introduce PropOffset & StringOffset
Similarly to NodeOffset, introduce new transparent c_int wrappers for
DT offsets pointing to properties and offsets in the DT string table,
allowing the compiler to detect mis-used values.
Test: m pvmfw
Test: atest liblibfdt.integration_test
Change-Id: Ie69e61ede25e2e03fe179a5f84fa63f010515cce
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index d153303..1961232 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -27,9 +27,9 @@
PropertyIterator, RangesIterator, Reg, RegIterator, SubnodeIterator,
};
pub use result::{FdtError, Result};
-pub use safe_types::{NodeOffset, Phandle};
+pub use safe_types::{NodeOffset, Phandle, PropOffset, StringOffset};
-use core::ffi::{c_int, c_void, CStr};
+use core::ffi::{c_void, CStr};
use core::ops::Range;
use cstr::cstr;
use libfdt::get_slice_at_ptr;
@@ -93,12 +93,12 @@
}
impl FdtPropertyStruct {
- fn from_offset(fdt: &Fdt, offset: c_int) -> Result<&Self> {
+ fn from_offset(fdt: &Fdt, offset: PropOffset) -> Result<&Self> {
Ok(fdt.get_property_by_offset(offset)?.as_ref())
}
- fn name_offset(&self) -> c_int {
- u32::from_be(self.0.nameoff).try_into().unwrap()
+ fn name_offset(&self) -> StringOffset {
+ StringOffset(u32::from_be(self.0.nameoff).try_into().unwrap())
}
fn data_len(&self) -> usize {
@@ -114,12 +114,12 @@
#[derive(Clone, Copy, Debug)]
pub struct FdtProperty<'a> {
fdt: &'a Fdt,
- offset: c_int,
+ offset: PropOffset,
property: &'a FdtPropertyStruct,
}
impl<'a> FdtProperty<'a> {
- fn new(fdt: &'a Fdt, offset: c_int) -> Result<Self> {
+ fn new(fdt: &'a Fdt, offset: PropOffset) -> Result<Self> {
let property = FdtPropertyStruct::from_offset(fdt, offset)?;
Ok(Self { fdt, offset, property })
}
diff --git a/libs/libfdt/src/libfdt.rs b/libs/libfdt/src/libfdt.rs
index b6487fb..1af9edf 100644
--- a/libs/libfdt/src/libfdt.rs
+++ b/libs/libfdt/src/libfdt.rs
@@ -18,12 +18,12 @@
//! user-friendly higher-level types, allowing the trait to be shared between different ones,
//! adapted to their use-cases (e.g. alloc-based userspace or statically allocated no_std).
-use core::ffi::{c_int, CStr};
+use core::ffi::CStr;
use core::mem;
use core::ptr;
use crate::result::FdtRawResult;
-use crate::{FdtError, NodeOffset, Phandle, Result};
+use crate::{FdtError, NodeOffset, Phandle, PropOffset, Result, StringOffset};
// Function names are the C function names without the `fdt_` prefix.
@@ -240,9 +240,10 @@
}
/// Safe wrapper around `fdt_get_property_by_offset()` (C function).
- fn get_property_by_offset(&self, offset: c_int) -> Result<&libfdt_bindgen::fdt_property> {
+ fn get_property_by_offset(&self, offset: PropOffset) -> Result<&libfdt_bindgen::fdt_property> {
let mut len = 0;
let fdt = self.as_fdt_slice().as_ptr().cast();
+ let offset = offset.into();
// SAFETY: Accesses (read-only) are constrained to the DT totalsize.
let prop = unsafe { libfdt_bindgen::fdt_get_property_by_offset(fdt, offset, &mut len) };
@@ -266,7 +267,7 @@
}
/// Safe wrapper around `fdt_first_property_offset()` (C function).
- fn first_property_offset(&self, node: NodeOffset) -> Result<Option<c_int>> {
+ fn first_property_offset(&self, node: NodeOffset) -> Result<Option<PropOffset>> {
let fdt = self.as_fdt_slice().as_ptr().cast();
let node = node.into();
// SAFETY: Accesses (read-only) are constrained to the DT totalsize.
@@ -276,8 +277,9 @@
}
/// Safe wrapper around `fdt_next_property_offset()` (C function).
- fn next_property_offset(&self, prev: c_int) -> Result<Option<c_int>> {
+ fn next_property_offset(&self, prev: PropOffset) -> Result<Option<PropOffset>> {
let fdt = self.as_fdt_slice().as_ptr().cast();
+ let prev = prev.into();
// SAFETY: Accesses (read-only) are constrained to the DT totalsize.
let ret = unsafe { libfdt_bindgen::fdt_next_property_offset(fdt, prev) };
@@ -297,8 +299,9 @@
}
/// Safe wrapper around `fdt_string()` (C function).
- fn string(&self, offset: c_int) -> Result<&CStr> {
+ fn string(&self, offset: StringOffset) -> Result<&CStr> {
let fdt = self.as_fdt_slice().as_ptr().cast();
+ let offset = offset.into();
// SAFETY: Accesses (read-only) are constrained to the DT totalsize.
let ptr = unsafe { libfdt_bindgen::fdt_string(fdt, offset) };
let bytes =
diff --git a/libs/libfdt/src/safe_types.rs b/libs/libfdt/src/safe_types.rs
index b89c771..5ec7f7c 100644
--- a/libs/libfdt/src/safe_types.rs
+++ b/libs/libfdt/src/safe_types.rs
@@ -99,3 +99,69 @@
offset.0
}
}
+
+/// Safe zero-cost wrapper around libfdt device tree property offsets.
+///
+/// This type should only be obtained from properly wrapped successful libfdt calls.
+#[repr(transparent)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub struct PropOffset(c_int);
+
+impl TryFrom<FdtRawResult> for PropOffset {
+ type Error = FdtError;
+
+ fn try_from(res: FdtRawResult) -> Result<Self> {
+ Ok(Self(res.try_into()?))
+ }
+}
+
+impl TryFrom<FdtRawResult> for Option<PropOffset> {
+ type Error = FdtError;
+
+ fn try_from(res: FdtRawResult) -> Result<Self> {
+ match res.try_into() {
+ Ok(n) => Ok(Some(n)),
+ Err(FdtError::NotFound) => Ok(None),
+ Err(e) => Err(e),
+ }
+ }
+}
+
+impl From<PropOffset> for c_int {
+ fn from(offset: PropOffset) -> Self {
+ offset.0
+ }
+}
+
+/// Safe zero-cost wrapper around libfdt device tree string offsets.
+///
+/// This type should only be obtained from properly wrapped successful libfdt calls.
+#[repr(transparent)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub struct StringOffset(pub c_int); // TODO(ptosi): Move fdt_property wrapper here and remove pub.
+
+impl TryFrom<FdtRawResult> for StringOffset {
+ type Error = FdtError;
+
+ fn try_from(res: FdtRawResult) -> Result<Self> {
+ Ok(Self(res.try_into()?))
+ }
+}
+
+impl TryFrom<FdtRawResult> for Option<StringOffset> {
+ type Error = FdtError;
+
+ fn try_from(res: FdtRawResult) -> Result<Self> {
+ match res.try_into() {
+ Ok(n) => Ok(Some(n)),
+ Err(FdtError::NotFound) => Ok(None),
+ Err(e) => Err(e),
+ }
+ }
+}
+
+impl From<StringOffset> for c_int {
+ fn from(offset: StringOffset) -> Self {
+ offset.0
+ }
+}