libfdt: Move phandle functions and 0-cost Phandle
Move Phandle to its own module, intended to contain all the zero-cost
abstractions used by our Rust-safe wrapper around libfdt in place of the
c_ints expected by the C code.
Move the functions dealing with phandles to the LibFdt* traits.
Reduce the unsafe blocks to the strict minimum (i.e. the FFI calls).
Test: m pvmfw
Test: atest liblibfdt.integration_test
Change-Id: I548c7436f94bd7a902943eaea5bf1f0195e52366
diff --git a/libs/libfdt/src/ctypes.rs b/libs/libfdt/src/ctypes.rs
new file mode 100644
index 0000000..640d447
--- /dev/null
+++ b/libs/libfdt/src/ctypes.rs
@@ -0,0 +1,52 @@
+// Copyright 2024, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Safe zero-cost wrappers around integer values used by libfdt.
+
+use crate::{FdtError, Result};
+
+/// Wrapper guaranteed to contain a valid phandle.
+#[repr(transparent)]
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
+pub struct Phandle(u32);
+
+impl Phandle {
+ /// Minimum valid value for device tree phandles.
+ pub const MIN: Self = Self(1);
+ /// Maximum valid value for device tree phandles.
+ pub const MAX: Self = Self(libfdt_bindgen::FDT_MAX_PHANDLE);
+
+ /// Creates a new Phandle
+ pub const fn new(value: u32) -> Option<Self> {
+ if Self::MIN.0 <= value && value <= Self::MAX.0 {
+ Some(Self(value))
+ } else {
+ None
+ }
+ }
+}
+
+impl From<Phandle> for u32 {
+ fn from(phandle: Phandle) -> u32 {
+ phandle.0
+ }
+}
+
+impl TryFrom<u32> for Phandle {
+ type Error = FdtError;
+
+ fn try_from(value: u32) -> Result<Self> {
+ Self::new(value).ok_or(FdtError::BadPhandle)
+ }
+}
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index 0249d0d..d5013ca 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -17,10 +17,12 @@
#![no_std]
+mod ctypes;
mod iterators;
mod libfdt;
mod result;
+pub use ctypes::Phandle;
pub use iterators::{
AddressRange, CellIterator, CompatibleIterator, DescendantsIterator, MemRegIterator,
PropertyIterator, RangesIterator, Reg, RegIterator, SubnodeIterator,
@@ -410,41 +412,6 @@
}
}
-/// Phandle of a FDT node
-#[repr(transparent)]
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
-pub struct Phandle(u32);
-
-impl Phandle {
- /// Minimum valid value for device tree phandles.
- pub const MIN: Self = Self(1);
- /// Maximum valid value for device tree phandles.
- pub const MAX: Self = Self(libfdt_bindgen::FDT_MAX_PHANDLE);
-
- /// Creates a new Phandle
- pub const fn new(value: u32) -> Option<Self> {
- if Self::MIN.0 <= value && value <= Self::MAX.0 {
- Some(Self(value))
- } else {
- None
- }
- }
-}
-
-impl From<Phandle> for u32 {
- fn from(phandle: Phandle) -> u32 {
- phandle.0
- }
-}
-
-impl TryFrom<u32> for Phandle {
- type Error = FdtError;
-
- fn try_from(value: u32) -> Result<Self> {
- Self::new(value).ok_or(FdtError::BadPhandle)
- }
-}
-
/// Mutable FDT node.
#[derive(Debug)]
pub struct FdtNodeMut<'a> {
@@ -896,30 +863,21 @@
/// Returns max phandle in the tree.
pub fn max_phandle(&self) -> Result<Phandle> {
- let mut phandle: u32 = 0;
- // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
- let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(self.as_ptr(), &mut phandle) };
-
- fdt_err_expect_zero(ret)?;
- phandle.try_into()
+ self.find_max_phandle()
}
/// Returns a node with the phandle
pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
- let offset = self.node_offset_with_phandle(phandle)?;
+ let offset = self.node_offset_by_phandle(phandle)?;
+
Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
}
/// Returns a mutable node with the phandle
pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
- let offset = self.node_offset_with_phandle(phandle)?;
- Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
- }
+ let offset = self.node_offset_by_phandle(phandle)?;
- fn node_offset_with_phandle(&self, phandle: Phandle) -> Result<Option<c_int>> {
- // SAFETY: Accesses are constrained to the DT totalsize.
- let ret = unsafe { libfdt_bindgen::fdt_node_offset_by_phandle(self.as_ptr(), phandle.0) };
- fdt_err_or_option(ret)
+ Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
}
/// Returns the mutable root node of the tree.
diff --git a/libs/libfdt/src/libfdt.rs b/libs/libfdt/src/libfdt.rs
index 7e3b65a..0614a5e 100644
--- a/libs/libfdt/src/libfdt.rs
+++ b/libs/libfdt/src/libfdt.rs
@@ -21,7 +21,7 @@
use core::ffi::{c_int, CStr};
use core::ptr;
-use crate::{fdt_err, fdt_err_expect_zero, fdt_err_or_option, FdtError, Result};
+use crate::{fdt_err, fdt_err_expect_zero, fdt_err_or_option, FdtError, Phandle, Result};
// Function names are the C function names without the `fdt_` prefix.
@@ -78,6 +78,16 @@
fdt_err_or_option(ret)
}
+ /// Safe wrapper around `fdt_node_offset_by_phandle()` (C function).
+ fn node_offset_by_phandle(&self, phandle: Phandle) -> Result<Option<c_int>> {
+ let fdt = self.as_fdt_slice().as_ptr().cast();
+ let phandle = phandle.into();
+ // SAFETY: Accesses are constrained to the DT totalsize.
+ let ret = unsafe { libfdt_bindgen::fdt_node_offset_by_phandle(fdt, phandle) };
+
+ fdt_err_or_option(ret)
+ }
+
/// Safe wrapper around `fdt_node_offset_by_compatible()` (C function).
fn node_offset_by_compatible(&self, prev: c_int, compatible: &CStr) -> Result<Option<c_int>> {
let fdt = self.as_fdt_slice().as_ptr().cast();
@@ -175,6 +185,18 @@
Ok(fdt_err(ret)?.try_into().unwrap())
}
+
+ /// 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();
+ let mut phandle = 0;
+ // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+ let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(fdt, &mut phandle) };
+
+ fdt_err_expect_zero(ret)?;
+
+ phandle.try_into()
+ }
}
/// Wrapper for the read-write libfdt.h functions.