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
+    }
+}