blob: 9d02c31e13272a57d2b67ba8d04c2855cf70ae1e [file] [log] [blame]
David Brazdil1baa9a92022-06-28 14:47:50 +01001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Wrapper around libfdt library. Provides parsing/generating functionality
16//! to a bare-metal environment.
17
18#![no_std]
19
Andrew Walbran55ad01b2022-12-05 17:00:40 +000020mod iterators;
21
Jaewan Kimfe06c852023-10-05 23:40:06 +090022pub use iterators::{
Jaewan Kimc9e14112023-12-04 17:05:27 +090023 AddressRange, CellIterator, CompatibleIterator, DescendantsIterator, MemRegIterator,
24 PropertyIterator, RangesIterator, Reg, RegIterator, SubnodeIterator,
Jaewan Kimfe06c852023-10-05 23:40:06 +090025};
Andrew Walbran55ad01b2022-12-05 17:00:40 +000026
David Brazdil1baa9a92022-06-28 14:47:50 +010027use core::ffi::{c_int, c_void, CStr};
28use core::fmt;
Alice Wang2422bdc2023-06-12 08:37:55 +000029use core::ops::Range;
Jaewan Kim5b057772023-10-19 01:02:17 +090030use core::ptr;
David Brazdil1baa9a92022-06-28 14:47:50 +010031use core::result;
Pierre-Clément Tosi1bf532b2023-11-13 11:06:20 +000032use cstr::cstr;
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +000033use zerocopy::AsBytes as _;
David Brazdil1baa9a92022-06-28 14:47:50 +010034
35/// Error type corresponding to libfdt error codes.
36#[derive(Clone, Copy, Debug, Eq, PartialEq)]
37pub enum FdtError {
38 /// FDT_ERR_NOTFOUND
39 NotFound,
40 /// FDT_ERR_EXISTS
41 Exists,
42 /// FDT_ERR_NOSPACE
43 NoSpace,
44 /// FDT_ERR_BADOFFSET
45 BadOffset,
46 /// FDT_ERR_BADPATH
47 BadPath,
48 /// FDT_ERR_BADPHANDLE
49 BadPhandle,
50 /// FDT_ERR_BADSTATE
51 BadState,
52 /// FDT_ERR_TRUNCATED
53 Truncated,
54 /// FDT_ERR_BADMAGIC
55 BadMagic,
56 /// FDT_ERR_BADVERSION
57 BadVersion,
58 /// FDT_ERR_BADSTRUCTURE
59 BadStructure,
60 /// FDT_ERR_BADLAYOUT
61 BadLayout,
62 /// FDT_ERR_INTERNAL
63 Internal,
64 /// FDT_ERR_BADNCELLS
65 BadNCells,
66 /// FDT_ERR_BADVALUE
67 BadValue,
68 /// FDT_ERR_BADOVERLAY
69 BadOverlay,
70 /// FDT_ERR_NOPHANDLES
71 NoPhandles,
72 /// FDT_ERR_BADFLAGS
73 BadFlags,
74 /// FDT_ERR_ALIGNMENT
75 Alignment,
76 /// Unexpected error code
77 Unknown(i32),
78}
79
80impl fmt::Display for FdtError {
81 /// Prints error messages from libfdt.h documentation.
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 match self {
84 Self::NotFound => write!(f, "The requested node or property does not exist"),
85 Self::Exists => write!(f, "Attempted to create an existing node or property"),
86 Self::NoSpace => write!(f, "Insufficient buffer space to contain the expanded tree"),
87 Self::BadOffset => write!(f, "Structure block offset is out-of-bounds or invalid"),
88 Self::BadPath => write!(f, "Badly formatted path"),
89 Self::BadPhandle => write!(f, "Invalid phandle length or value"),
90 Self::BadState => write!(f, "Received incomplete device tree"),
91 Self::Truncated => write!(f, "Device tree or sub-block is improperly terminated"),
92 Self::BadMagic => write!(f, "Device tree header missing its magic number"),
93 Self::BadVersion => write!(f, "Device tree has a version which can't be handled"),
94 Self::BadStructure => write!(f, "Device tree has a corrupt structure block"),
95 Self::BadLayout => write!(f, "Device tree sub-blocks in unsupported order"),
96 Self::Internal => write!(f, "libfdt has failed an internal assertion"),
97 Self::BadNCells => write!(f, "Bad format or value of #address-cells or #size-cells"),
98 Self::BadValue => write!(f, "Unexpected property value"),
99 Self::BadOverlay => write!(f, "Overlay cannot be applied"),
100 Self::NoPhandles => write!(f, "Device tree doesn't have any phandle available anymore"),
101 Self::BadFlags => write!(f, "Invalid flag or invalid combination of flags"),
102 Self::Alignment => write!(f, "Device tree base address is not 8-byte aligned"),
103 Self::Unknown(e) => write!(f, "Unknown libfdt error '{e}'"),
104 }
105 }
106}
107
108/// Result type with FdtError enum.
109pub type Result<T> = result::Result<T, FdtError>;
110
111fn fdt_err(val: c_int) -> Result<c_int> {
112 if val >= 0 {
113 Ok(val)
114 } else {
115 Err(match -val as _ {
116 libfdt_bindgen::FDT_ERR_NOTFOUND => FdtError::NotFound,
117 libfdt_bindgen::FDT_ERR_EXISTS => FdtError::Exists,
118 libfdt_bindgen::FDT_ERR_NOSPACE => FdtError::NoSpace,
119 libfdt_bindgen::FDT_ERR_BADOFFSET => FdtError::BadOffset,
120 libfdt_bindgen::FDT_ERR_BADPATH => FdtError::BadPath,
121 libfdt_bindgen::FDT_ERR_BADPHANDLE => FdtError::BadPhandle,
122 libfdt_bindgen::FDT_ERR_BADSTATE => FdtError::BadState,
123 libfdt_bindgen::FDT_ERR_TRUNCATED => FdtError::Truncated,
124 libfdt_bindgen::FDT_ERR_BADMAGIC => FdtError::BadMagic,
125 libfdt_bindgen::FDT_ERR_BADVERSION => FdtError::BadVersion,
126 libfdt_bindgen::FDT_ERR_BADSTRUCTURE => FdtError::BadStructure,
127 libfdt_bindgen::FDT_ERR_BADLAYOUT => FdtError::BadLayout,
128 libfdt_bindgen::FDT_ERR_INTERNAL => FdtError::Internal,
129 libfdt_bindgen::FDT_ERR_BADNCELLS => FdtError::BadNCells,
130 libfdt_bindgen::FDT_ERR_BADVALUE => FdtError::BadValue,
131 libfdt_bindgen::FDT_ERR_BADOVERLAY => FdtError::BadOverlay,
132 libfdt_bindgen::FDT_ERR_NOPHANDLES => FdtError::NoPhandles,
133 libfdt_bindgen::FDT_ERR_BADFLAGS => FdtError::BadFlags,
134 libfdt_bindgen::FDT_ERR_ALIGNMENT => FdtError::Alignment,
135 _ => FdtError::Unknown(val),
136 })
137 }
138}
139
140fn fdt_err_expect_zero(val: c_int) -> Result<()> {
141 match fdt_err(val)? {
142 0 => Ok(()),
143 _ => Err(FdtError::Unknown(val)),
144 }
145}
146
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000147fn fdt_err_or_option(val: c_int) -> Result<Option<c_int>> {
148 match fdt_err(val) {
149 Ok(val) => Ok(Some(val)),
150 Err(FdtError::NotFound) => Ok(None),
151 Err(e) => Err(e),
152 }
153}
154
David Brazdil1baa9a92022-06-28 14:47:50 +0100155/// Value of a #address-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000156#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100157enum AddrCells {
158 Single = 1,
159 Double = 2,
Andrew Walbranb39e6922022-12-05 17:01:20 +0000160 Triple = 3,
David Brazdil1baa9a92022-06-28 14:47:50 +0100161}
162
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000163impl TryFrom<usize> for AddrCells {
David Brazdil1baa9a92022-06-28 14:47:50 +0100164 type Error = FdtError;
165
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000166 fn try_from(value: usize) -> Result<Self> {
167 match value {
168 x if x == Self::Single as _ => Ok(Self::Single),
169 x if x == Self::Double as _ => Ok(Self::Double),
170 x if x == Self::Triple as _ => Ok(Self::Triple),
David Brazdil1baa9a92022-06-28 14:47:50 +0100171 _ => Err(FdtError::BadNCells),
172 }
173 }
174}
175
176/// Value of a #size-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000177#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100178enum SizeCells {
179 None = 0,
180 Single = 1,
181 Double = 2,
182}
183
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000184impl TryFrom<usize> for SizeCells {
David Brazdil1baa9a92022-06-28 14:47:50 +0100185 type Error = FdtError;
186
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000187 fn try_from(value: usize) -> Result<Self> {
188 match value {
189 x if x == Self::None as _ => Ok(Self::None),
190 x if x == Self::Single as _ => Ok(Self::Single),
191 x if x == Self::Double as _ => Ok(Self::Double),
David Brazdil1baa9a92022-06-28 14:47:50 +0100192 _ => Err(FdtError::BadNCells),
193 }
194 }
195}
196
Jaewan Kim72d10902023-10-12 21:59:26 +0900197/// DT property wrapper to abstract endianess changes
198#[repr(transparent)]
199#[derive(Debug)]
200struct FdtPropertyStruct(libfdt_bindgen::fdt_property);
201
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000202impl AsRef<FdtPropertyStruct> for libfdt_bindgen::fdt_property {
203 fn as_ref(&self) -> &FdtPropertyStruct {
204 let ptr = self as *const _ as *const _;
205 // SAFETY: Types have the same layout (transparent) so the valid reference remains valid.
206 unsafe { &*ptr }
207 }
208}
209
Jaewan Kim72d10902023-10-12 21:59:26 +0900210impl FdtPropertyStruct {
211 fn from_offset(fdt: &Fdt, offset: c_int) -> Result<&Self> {
212 let mut len = 0;
213 let prop =
214 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
215 unsafe { libfdt_bindgen::fdt_get_property_by_offset(fdt.as_ptr(), offset, &mut len) };
216 if prop.is_null() {
217 fdt_err(len)?;
218 return Err(FdtError::Internal); // shouldn't happen.
219 }
220 // SAFETY: prop is only returned when it points to valid libfdt_bindgen.
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000221 let prop = unsafe { &*prop };
222 Ok(prop.as_ref())
Jaewan Kim72d10902023-10-12 21:59:26 +0900223 }
224
225 fn name_offset(&self) -> c_int {
226 u32::from_be(self.0.nameoff).try_into().unwrap()
227 }
228
229 fn data_len(&self) -> usize {
230 u32::from_be(self.0.len).try_into().unwrap()
231 }
232
233 fn data_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000234 self.0.data.as_ptr().cast()
Jaewan Kim72d10902023-10-12 21:59:26 +0900235 }
236}
237
238/// DT property.
239#[derive(Clone, Copy, Debug)]
240pub struct FdtProperty<'a> {
241 fdt: &'a Fdt,
242 offset: c_int,
243 property: &'a FdtPropertyStruct,
244}
245
246impl<'a> FdtProperty<'a> {
247 fn new(fdt: &'a Fdt, offset: c_int) -> Result<Self> {
248 let property = FdtPropertyStruct::from_offset(fdt, offset)?;
249 Ok(Self { fdt, offset, property })
250 }
251
252 /// Returns the property name
253 pub fn name(&self) -> Result<&'a CStr> {
254 self.fdt.string(self.property.name_offset())
255 }
256
257 /// Returns the property value
258 pub fn value(&self) -> Result<&'a [u8]> {
259 self.fdt.get_from_ptr(self.property.data_ptr(), self.property.data_len())
260 }
261
262 fn next_property(&self) -> Result<Option<Self>> {
263 let ret =
264 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
265 unsafe { libfdt_bindgen::fdt_next_property_offset(self.fdt.as_ptr(), self.offset) };
266
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000267 if let Some(offset) = fdt_err_or_option(ret)? {
268 Ok(Some(Self::new(self.fdt, offset)?))
269 } else {
270 Ok(None)
271 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900272 }
273}
274
David Brazdil1baa9a92022-06-28 14:47:50 +0100275/// DT node.
Alice Wang9d4df702023-05-25 14:14:12 +0000276#[derive(Clone, Copy, Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100277pub struct FdtNode<'a> {
278 fdt: &'a Fdt,
279 offset: c_int,
280}
281
282impl<'a> FdtNode<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900283 /// Returns parent node.
David Brazdil1baa9a92022-06-28 14:47:50 +0100284 pub fn parent(&self) -> Result<Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000285 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
David Brazdil1baa9a92022-06-28 14:47:50 +0100286 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000287 let offset = fdt_err(ret)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100288
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000289 Ok(Self { fdt: self.fdt, offset })
David Brazdil1baa9a92022-06-28 14:47:50 +0100290 }
291
Jaewan Kim5b057772023-10-19 01:02:17 +0900292 /// Returns supernode with depth. Note that root is at depth 0.
293 pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
294 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
295 let ret = unsafe {
296 libfdt_bindgen::fdt_supernode_atdepth_offset(
297 self.fdt.as_ptr(),
298 self.offset,
299 depth.try_into().unwrap(),
300 ptr::null_mut(),
301 )
302 };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000303 let offset = fdt_err(ret)?;
Jaewan Kim5b057772023-10-19 01:02:17 +0900304
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000305 Ok(Self { fdt: self.fdt, offset })
Jaewan Kim5b057772023-10-19 01:02:17 +0900306 }
307
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900308 /// Returns the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000309 pub fn device_type(&self) -> Result<Option<&CStr>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900310 self.getprop_str(cstr!("device_type"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100311 }
312
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900313 /// Returns the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000314 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000315 if let Some(cells) = self.getprop_cells(cstr!("reg"))? {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000316 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100317
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000318 let addr_cells = parent.address_cells()?;
319 let size_cells = parent.size_cells()?;
320
321 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
322 } else {
323 Ok(None)
324 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100325 }
326
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900327 /// Returns the standard ranges property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000328 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000329 if let Some(cells) = self.getprop_cells(cstr!("ranges"))? {
Andrew Walbranb39e6922022-12-05 17:01:20 +0000330 let parent = self.parent()?;
331 let addr_cells = self.address_cells()?;
332 let parent_addr_cells = parent.address_cells()?;
333 let size_cells = self.size_cells()?;
334 Ok(Some(RangesIterator::<A, P, S>::new(
335 cells,
336 addr_cells,
337 parent_addr_cells,
338 size_cells,
339 )))
340 } else {
341 Ok(None)
342 }
343 }
344
Jaewan Kimaa638702023-09-19 13:34:01 +0900345 /// Returns the node name.
346 pub fn name(&self) -> Result<&'a CStr> {
347 let mut len: c_int = 0;
348 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor). On success, the
349 // function returns valid null terminating string and otherwise returned values are dropped.
350 let name = unsafe { libfdt_bindgen::fdt_get_name(self.fdt.as_ptr(), self.offset, &mut len) }
351 as *const c_void;
352 let len = usize::try_from(fdt_err(len)?).unwrap();
353 let name = self.fdt.get_from_ptr(name, len + 1)?;
354 CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
355 }
356
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900357 /// Returns the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000358 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000359 if let Some(bytes) = self.getprop(name)? {
360 Ok(Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000361 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000362 Ok(None)
363 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100364 }
365
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900366 /// Returns the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000367 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
368 if let Some(cells) = self.getprop(name)? {
369 Ok(Some(CellIterator::new(cells)))
370 } else {
371 Ok(None)
372 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100373 }
374
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900375 /// Returns the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000376 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000377 if let Some(bytes) = self.getprop(name)? {
378 Ok(Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000379 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000380 Ok(None)
381 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100382 }
383
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900384 /// Returns the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000385 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000386 if let Some(bytes) = self.getprop(name)? {
387 Ok(Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000388 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000389 Ok(None)
390 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100391 }
392
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900393 /// Returns the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000394 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900395 if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
Jaewan Kimaa638702023-09-19 13:34:01 +0900396 Ok(Some(self.fdt.get_from_ptr(prop, len)?))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900397 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000398 Ok(None)
Jiyong Park9c63cd12023-03-21 17:53:07 +0900399 }
400 }
401
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900402 /// Returns the pointer and size of the property named `name`, in a node at offset `offset`, in
Jiyong Park9c63cd12023-03-21 17:53:07 +0900403 /// a device tree `fdt`. The pointer is guaranteed to be non-null, in which case error returns.
404 fn getprop_internal(
405 fdt: &'a Fdt,
406 offset: c_int,
407 name: &CStr,
408 ) -> Result<Option<(*const c_void, usize)>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100409 let mut len: i32 = 0;
Andrew Walbran84b9a232023-07-05 14:01:40 +0000410 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +0100411 // function respects the passed number of characters.
412 let prop = unsafe {
413 libfdt_bindgen::fdt_getprop_namelen(
Jiyong Park9c63cd12023-03-21 17:53:07 +0900414 fdt.as_ptr(),
415 offset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100416 name.as_ptr(),
417 // *_namelen functions don't include the trailing nul terminator in 'len'.
418 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
419 &mut len as *mut i32,
420 )
421 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000422
423 let Some(len) = fdt_err_or_option(len)? else {
424 return Ok(None); // Property was not found.
425 };
Jaewan Kimaa638702023-09-19 13:34:01 +0900426 let len = usize::try_from(len).unwrap();
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000427
David Brazdil1baa9a92022-06-28 14:47:50 +0100428 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000429 // We expected an error code in len but still received a valid value?!
430 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100431 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900432 Ok(Some((prop.cast::<c_void>(), len)))
David Brazdil1baa9a92022-06-28 14:47:50 +0100433 }
434
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900435 /// Returns reference to the containing device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100436 pub fn fdt(&self) -> &Fdt {
437 self.fdt
438 }
439
Alice Wang474c0ee2023-09-14 12:52:33 +0000440 /// Returns the compatible node of the given name that is next after this node.
441 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000442 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000443 let ret = unsafe {
444 libfdt_bindgen::fdt_node_offset_by_compatible(
445 self.fdt.as_ptr(),
446 self.offset,
447 compatible.as_ptr(),
448 )
449 };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000450 let offset = fdt_err_or_option(ret)?;
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000451
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000452 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000453 }
454
Alice Wang474c0ee2023-09-14 12:52:33 +0000455 /// Returns the first range of `reg` in this node.
456 pub fn first_reg(&self) -> Result<Reg<u64>> {
457 self.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
458 }
459
David Brazdil1baa9a92022-06-28 14:47:50 +0100460 fn address_cells(&self) -> Result<AddrCells> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000461 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000462 let ret = unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) };
463
464 usize::try_from(ret).map_err(|_| FdtError::Internal)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100465 }
466
467 fn size_cells(&self) -> Result<SizeCells> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000468 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000469 let ret = unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) };
470
471 usize::try_from(ret).map_err(|_| FdtError::Internal)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100472 }
Jaewan Kimbc828d72023-09-19 15:52:08 +0900473
474 /// Returns an iterator of subnodes
Jaewan Kim4a34b0d2024-01-19 13:17:47 +0900475 pub fn subnodes(&self) -> Result<SubnodeIterator<'a>> {
Jaewan Kimbc828d72023-09-19 15:52:08 +0900476 SubnodeIterator::new(self)
477 }
478
479 fn first_subnode(&self) -> Result<Option<Self>> {
480 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
481 let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000482 let offset = fdt_err_or_option(ret)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900483
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000484 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900485 }
486
487 fn next_subnode(&self) -> Result<Option<Self>> {
488 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
489 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000490 let offset = fdt_err_or_option(ret)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900491
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000492 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900493 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900494
Jaewan Kimc9e14112023-12-04 17:05:27 +0900495 /// Returns an iterator of descendants
Jaewan Kim1eab7232024-01-04 09:46:16 +0900496 pub fn descendants(&self) -> DescendantsIterator<'a> {
Jaewan Kimc9e14112023-12-04 17:05:27 +0900497 DescendantsIterator::new(self)
498 }
499
500 fn next_node(&self, depth: usize) -> Result<Option<(Self, usize)>> {
501 let mut next_depth: c_int = depth.try_into().unwrap();
502 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
503 let ret = unsafe {
504 libfdt_bindgen::fdt_next_node(self.fdt.as_ptr(), self.offset, &mut next_depth)
505 };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000506 let Ok(depth) = usize::try_from(next_depth) else {
Jaewan Kimc9e14112023-12-04 17:05:27 +0900507 return Ok(None);
508 };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000509 if let Some(offset) = fdt_err_or_option(ret)? {
510 Ok(Some((Self { fdt: self.fdt, offset }, depth)))
511 } else {
512 Ok(None)
513 }
Jaewan Kimc9e14112023-12-04 17:05:27 +0900514 }
515
Jaewan Kim72d10902023-10-12 21:59:26 +0900516 /// Returns an iterator of properties
517 pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
518 PropertyIterator::new(self)
519 }
520
521 fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
522 let ret =
523 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
524 unsafe { libfdt_bindgen::fdt_first_property_offset(self.fdt.as_ptr(), self.offset) };
525
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000526 if let Some(offset) = fdt_err_or_option(ret)? {
527 Ok(Some(FdtProperty::new(self.fdt, offset)?))
528 } else {
529 Ok(None)
530 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900531 }
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900532
533 /// Returns the phandle
534 pub fn get_phandle(&self) -> Result<Option<Phandle>> {
535 // This rewrites the fdt_get_phandle() because it doesn't return error code.
536 if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
537 Ok(Some(prop.try_into()?))
538 } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
539 Ok(Some(prop.try_into()?))
540 } else {
541 Ok(None)
542 }
543 }
Jaewan Kim52026012023-12-13 13:49:28 +0900544
545 /// Returns the subnode of the given name. The name doesn't need to be nul-terminated.
546 pub fn subnode(&self, name: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000547 let name = name.to_bytes();
548 let offset = self.subnode_offset(name)?;
549
Jaewan Kim52026012023-12-13 13:49:28 +0900550 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
551 }
552
553 /// Returns the subnode of the given name bytes
554 pub fn subnode_with_name_bytes(&self, name: &[u8]) -> Result<Option<Self>> {
555 let offset = self.subnode_offset(name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000556
Jaewan Kim52026012023-12-13 13:49:28 +0900557 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
558 }
559
560 fn subnode_offset(&self, name: &[u8]) -> Result<Option<c_int>> {
561 let namelen = name.len().try_into().unwrap();
562 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
563 let ret = unsafe {
564 libfdt_bindgen::fdt_subnode_offset_namelen(
565 self.fdt.as_ptr(),
566 self.offset,
567 name.as_ptr().cast::<_>(),
568 namelen,
569 )
570 };
571 fdt_err_or_option(ret)
572 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100573}
574
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000575impl<'a> PartialEq for FdtNode<'a> {
576 fn eq(&self, other: &Self) -> bool {
577 self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
578 }
579}
580
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900581/// Phandle of a FDT node
582#[repr(transparent)]
Jaewan Kim55f438c2023-11-15 01:24:36 +0900583#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900584pub struct Phandle(u32);
585
586impl Phandle {
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000587 /// Minimum valid value for device tree phandles.
588 pub const MIN: Self = Self(1);
589 /// Maximum valid value for device tree phandles.
590 pub const MAX: Self = Self(libfdt_bindgen::FDT_MAX_PHANDLE);
591
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900592 /// Creates a new Phandle
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000593 pub const fn new(value: u32) -> Option<Self> {
594 if Self::MIN.0 <= value && value <= Self::MAX.0 {
595 Some(Self(value))
596 } else {
597 None
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900598 }
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900599 }
600}
601
602impl From<Phandle> for u32 {
603 fn from(phandle: Phandle) -> u32 {
604 phandle.0
605 }
606}
607
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000608impl TryFrom<u32> for Phandle {
609 type Error = FdtError;
610
611 fn try_from(value: u32) -> Result<Self> {
612 Self::new(value).ok_or(FdtError::BadPhandle)
613 }
614}
615
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000616/// Mutable FDT node.
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000617#[derive(Debug)]
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000618pub struct FdtNodeMut<'a> {
619 fdt: &'a mut Fdt,
620 offset: c_int,
621}
622
623impl<'a> FdtNodeMut<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900624 /// Appends a property name-value (possibly empty) pair to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000625 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000626 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000627 let ret = unsafe {
628 libfdt_bindgen::fdt_appendprop(
629 self.fdt.as_mut_ptr(),
630 self.offset,
631 name.as_ptr(),
632 value.as_ref().as_ptr().cast::<c_void>(),
633 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
634 )
635 };
636
637 fdt_err_expect_zero(ret)
638 }
639
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900640 /// Appends a (address, size) pair property to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000641 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000642 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000643 let ret = unsafe {
644 libfdt_bindgen::fdt_appendprop_addrrange(
645 self.fdt.as_mut_ptr(),
646 self.parent()?.offset,
647 self.offset,
648 name.as_ptr(),
649 addr,
650 size,
651 )
652 };
653
654 fdt_err_expect_zero(ret)
655 }
656
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900657 /// Sets a property name-value pair to the given node.
658 ///
659 /// This may create a new prop or replace existing value.
Jaewan Kimba8929b2023-01-13 11:13:29 +0900660 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000661 // SAFETY: New value size is constrained to the DT totalsize
Jaewan Kimba8929b2023-01-13 11:13:29 +0900662 // (validated by underlying libfdt).
663 let ret = unsafe {
664 libfdt_bindgen::fdt_setprop(
665 self.fdt.as_mut_ptr(),
666 self.offset,
667 name.as_ptr(),
668 value.as_ptr().cast::<c_void>(),
669 value.len().try_into().map_err(|_| FdtError::BadValue)?,
670 )
671 };
672
673 fdt_err_expect_zero(ret)
674 }
675
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900676 /// Sets the value of the given property with the given value, and ensure that the given
677 /// value has the same length as the current value length.
678 ///
679 /// This can only be used to replace existing value.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900680 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000681 // SAFETY: fdt size is not altered
Jiyong Park9c63cd12023-03-21 17:53:07 +0900682 let ret = unsafe {
683 libfdt_bindgen::fdt_setprop_inplace(
684 self.fdt.as_mut_ptr(),
685 self.offset,
686 name.as_ptr(),
687 value.as_ptr().cast::<c_void>(),
688 value.len().try_into().map_err(|_| FdtError::BadValue)?,
689 )
690 };
691
692 fdt_err_expect_zero(ret)
693 }
694
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900695 /// Sets the value of the given (address, size) pair property with the given value, and
696 /// ensure that the given value has the same length as the current value length.
697 ///
698 /// This can only be used to replace existing value.
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000699 pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
700 let pair = [addr.to_be(), size.to_be()];
701 self.setprop_inplace(name, pair.as_bytes())
702 }
703
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900704 /// Sets a flag-like empty property.
705 ///
706 /// This may create a new prop or replace existing value.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000707 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
708 self.setprop(name, &[])
709 }
710
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900711 /// Deletes the given property.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000712 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000713 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000714 // library locates the node's property. Removing the property may shift the offsets of
715 // other nodes and properties but the borrow checker should prevent this function from
716 // being called when FdtNode instances are in use.
717 let ret = unsafe {
718 libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
719 };
720
721 fdt_err_expect_zero(ret)
722 }
723
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900724 /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000725 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000726 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000727 // library locates the node's property.
728 let ret = unsafe {
729 libfdt_bindgen::fdt_nop_property(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
730 };
731
732 fdt_err_expect_zero(ret)
733 }
734
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900735 /// Trims the size of the given property to new_size.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900736 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
737 let (prop, len) =
738 FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
739 if len == new_size {
740 return Ok(());
741 }
742 if new_size > len {
743 return Err(FdtError::NoSpace);
744 }
745
Andrew Walbran84b9a232023-07-05 14:01:40 +0000746 // SAFETY: new_size is smaller than the old size
Jiyong Park9c63cd12023-03-21 17:53:07 +0900747 let ret = unsafe {
748 libfdt_bindgen::fdt_setprop(
749 self.fdt.as_mut_ptr(),
750 self.offset,
751 name.as_ptr(),
752 prop.cast::<c_void>(),
753 new_size.try_into().map_err(|_| FdtError::BadValue)?,
754 )
755 };
756
757 fdt_err_expect_zero(ret)
758 }
759
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900760 /// Returns reference to the containing device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000761 pub fn fdt(&mut self) -> &mut Fdt {
762 self.fdt
763 }
764
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900765 /// Returns immutable FdtNode of this node.
766 pub fn as_node(&self) -> FdtNode {
767 FdtNode { fdt: self.fdt, offset: self.offset }
768 }
769
Jaewan Kime6363422024-01-19 14:00:00 +0900770 /// Adds new subnodes to the given node.
771 pub fn add_subnodes(&mut self, names: &[&CStr]) -> Result<()> {
772 for name in names {
773 self.add_subnode_offset(name.to_bytes())?;
774 }
775 Ok(())
776 }
777
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900778 /// Adds a new subnode to the given node and return it as a FdtNodeMut on success.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000779 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000780 let name = name.to_bytes();
781 let offset = self.add_subnode_offset(name)?;
782
Jaewan Kim5ab13582023-10-20 20:56:27 +0900783 Ok(Self { fdt: self.fdt, offset })
784 }
785
786 /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
787 /// on success.
788 pub fn add_subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000789 let name = &name.to_bytes()[..namelen];
790 let offset = self.add_subnode_offset(name)?;
791
Jaewan Kim5ab13582023-10-20 20:56:27 +0900792 Ok(Self { fdt: self.fdt, offset })
793 }
794
795 fn add_subnode_offset(&mut self, name: &[u8]) -> Result<c_int> {
796 let namelen = name.len().try_into().unwrap();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000797 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000798 let ret = unsafe {
Jaewan Kim5ab13582023-10-20 20:56:27 +0900799 libfdt_bindgen::fdt_add_subnode_namelen(
800 self.fdt.as_mut_ptr(),
801 self.offset,
802 name.as_ptr().cast::<_>(),
803 namelen,
804 )
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000805 };
Jaewan Kim5ab13582023-10-20 20:56:27 +0900806 fdt_err(ret)
807 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000808
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900809 /// Returns the first subnode of this
810 pub fn first_subnode(&'a mut self) -> Result<Option<Self>> {
811 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
812 let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000813 let offset = fdt_err_or_option(ret)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900814
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000815 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900816 }
817
818 /// Returns the next subnode that shares the same parent with this
819 pub fn next_subnode(self) -> Result<Option<Self>> {
820 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
821 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000822 let offset = fdt_err_or_option(ret)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900823
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000824 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900825 }
826
827 /// Deletes the current node and returns the next subnode
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000828 pub fn delete_and_next_subnode(self) -> Result<Option<Self>> {
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900829 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
830 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
831
832 let next_offset = fdt_err_or_option(ret)?;
833
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000834 self.delete_and_next(next_offset)
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900835 }
836
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900837 fn next_node_offset(&self, depth: usize) -> Result<Option<(c_int, usize)>> {
838 let mut next_depth: c_int = depth.try_into().or(Err(FdtError::BadValue))?;
839 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
840 let ret = unsafe {
841 libfdt_bindgen::fdt_next_node(self.fdt.as_ptr(), self.offset, &mut next_depth)
842 };
843 let Ok(next_depth) = usize::try_from(next_depth) else {
844 return Ok(None);
845 };
846 Ok(fdt_err_or_option(ret)?.map(|offset| (offset, next_depth)))
847 }
848
849 /// Returns the next node
850 pub fn next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000851 let next = self.next_node_offset(depth)?;
852
853 Ok(next.map(|(offset, depth)| (Self { fdt: self.fdt, offset }, depth)))
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900854 }
855
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000856 fn next_node_skip_subnodes(&mut self, depth: usize) -> Result<Option<(c_int, usize)>> {
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900857 let mut iter = self.next_node_offset(depth)?;
858 while let Some((descendant_offset, descendant_depth)) = iter {
859 if descendant_depth <= depth {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000860 return Ok(Some((descendant_offset, descendant_depth)));
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900861 }
862 let descendant = FdtNodeMut { fdt: self.fdt, offset: descendant_offset };
863 iter = descendant.next_node_offset(descendant_depth)?;
864 }
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000865
866 Ok(None)
867 }
868
869 /// Deletes this and returns the next node
870 pub fn delete_and_next_node(mut self, depth: usize) -> Result<Option<(Self, usize)>> {
871 let next_node = self.next_node_skip_subnodes(depth)?;
872 if let Some((offset, depth)) = next_node {
873 let next_node = self.delete_and_next(Some(offset))?.unwrap();
874 Ok(Some((next_node, depth)))
875 } else {
876 Ok(None)
877 }
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900878 }
879
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000880 fn parent(&'a self) -> Result<FdtNode<'a>> {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000881 self.as_node().parent()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000882 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900883
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900884 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900885 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000886 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900887 let ret = unsafe {
888 libfdt_bindgen::fdt_node_offset_by_compatible(
889 self.fdt.as_ptr(),
890 self.offset,
891 compatible.as_ptr(),
892 )
893 };
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000894 let offset = fdt_err_or_option(ret)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900895
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000896 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900897 }
898
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900899 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
900 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900901 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
902 // The reason is that libfdt ensures that the node from where the search for the next
903 // compatible node is started is always a valid one -- except for the special case of offset =
904 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
905 // next compatible node from it.
906 //
907 // We can't do in the opposite direction either. If we call next_compatible to find the next
908 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
909 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
910 // DT).
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000911 pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000912 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900913 let ret = unsafe {
914 libfdt_bindgen::fdt_node_offset_by_compatible(
915 self.fdt.as_ptr(),
916 self.offset,
917 compatible.as_ptr(),
918 )
919 };
920 let next_offset = fdt_err_or_option(ret)?;
921
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000922 self.delete_and_next(next_offset)
923 }
924
925 fn delete_and_next(mut self, next_offset: Option<c_int>) -> Result<Option<Self>> {
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900926 if Some(self.offset) == next_offset {
927 return Err(FdtError::Internal);
928 }
929
930 // SAFETY: nop_self() only touches bytes of the self and its properties and subnodes, and
931 // doesn't alter any other blob in the tree. self.fdt and next_offset would remain valid.
932 unsafe { self.nop_self()? };
Jiyong Park9c63cd12023-03-21 17:53:07 +0900933
934 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
935 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900936
937 /// Deletes this node effectively from DT, by setting it with FDT_NOP
938 pub fn nop(mut self) -> Result<()> {
939 // SAFETY: This consumes self, so invalid node wouldn't be used any further
940 unsafe { self.nop_self() }
941 }
942
943 /// Deletes this node effectively from DT, by setting it with FDT_NOP.
944 /// This only changes bytes of the node and its properties and subnodes, and doesn't alter or
945 /// move any other part of the tree.
946 /// SAFETY: This node is no longer valid.
947 unsafe fn nop_self(&mut self) -> Result<()> {
948 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
949 let ret = unsafe { libfdt_bindgen::fdt_nop_node(self.fdt.as_mut_ptr(), self.offset) };
950
951 fdt_err_expect_zero(ret)
952 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000953}
954
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000955/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000956#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100957#[repr(transparent)]
958pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000959 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100960}
961
962impl Fdt {
963 /// Wraps a slice containing a Flattened Device Tree.
964 ///
965 /// Fails if the FDT does not pass validation.
966 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000967 // SAFETY: The FDT will be validated before it is returned.
David Brazdil1baa9a92022-06-28 14:47:50 +0100968 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
969 fdt.check_full()?;
970 Ok(fdt)
971 }
972
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000973 /// Wraps a mutable slice containing a Flattened Device Tree.
974 ///
975 /// Fails if the FDT does not pass validation.
976 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000977 // SAFETY: The FDT will be validated before it is returned.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000978 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
979 fdt.check_full()?;
980 Ok(fdt)
981 }
982
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900983 /// Creates an empty Flattened Device Tree with a mutable slice.
984 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000985 // SAFETY: fdt_create_empty_tree() only write within the specified length,
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900986 // and returns error if buffer was insufficient.
987 // There will be no memory write outside of the given fdt.
988 let ret = unsafe {
989 libfdt_bindgen::fdt_create_empty_tree(
990 fdt.as_mut_ptr().cast::<c_void>(),
991 fdt.len() as i32,
992 )
993 };
994 fdt_err_expect_zero(ret)?;
995
Andrew Walbran84b9a232023-07-05 14:01:40 +0000996 // SAFETY: The FDT will be validated before it is returned.
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900997 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
998 fdt.check_full()?;
999
1000 Ok(fdt)
1001 }
1002
David Brazdil1baa9a92022-06-28 14:47:50 +01001003 /// Wraps a slice containing a Flattened Device Tree.
1004 ///
1005 /// # Safety
1006 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +00001007 /// It is undefined to call this function on a slice that does not contain a valid device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +01001008 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +00001009 let self_ptr = fdt as *const _ as *const _;
1010 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
1011 unsafe { &*self_ptr }
David Brazdil1baa9a92022-06-28 14:47:50 +01001012 }
1013
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001014 /// Wraps a mutable slice containing a Flattened Device Tree.
1015 ///
1016 /// # Safety
1017 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +00001018 /// It is undefined to call this function on a slice that does not contain a valid device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001019 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +00001020 let self_mut_ptr = fdt as *mut _ as *mut _;
1021 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
1022 unsafe { &mut *self_mut_ptr }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001023 }
1024
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +00001025 /// Updates this FDT from another FDT.
1026 pub fn clone_from(&mut self, other: &Self) -> Result<()> {
1027 let new_len = other.buffer.len();
1028 if self.buffer.len() < new_len {
1029 return Err(FdtError::NoSpace);
Jiyong Parke9d87e82023-03-21 19:28:40 +09001030 }
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +00001031
1032 let zeroed_len = self.totalsize().checked_sub(new_len);
1033 let (cloned, zeroed) = self.buffer.split_at_mut(new_len);
1034
1035 cloned.clone_from_slice(&other.buffer);
1036 if let Some(len) = zeroed_len {
1037 zeroed[..len].fill(0);
1038 }
1039
1040 Ok(())
Jiyong Parke9d87e82023-03-21 19:28:40 +09001041 }
1042
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001043 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001044 pub fn unpack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001045 // SAFETY: "Opens" the DT in-place (supported use-case) by updating its header and
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001046 // internal structures to make use of the whole self.fdt slice but performs no accesses
1047 // outside of it and leaves the DT in a state that will be detected by other functions.
1048 let ret = unsafe {
1049 libfdt_bindgen::fdt_open_into(
1050 self.as_ptr(),
1051 self.as_mut_ptr(),
1052 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
1053 )
1054 };
1055 fdt_err_expect_zero(ret)
1056 }
1057
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001058 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001059 ///
1060 /// Doesn't shrink the underlying memory slice.
1061 pub fn pack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001062 // SAFETY: "Closes" the DT in-place by updating its header and relocating its structs.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001063 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
1064 fdt_err_expect_zero(ret)
1065 }
1066
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +00001067 /// Applies a DT overlay on the base DT.
1068 ///
1069 /// # Safety
1070 ///
1071 /// On failure, the library corrupts the DT and overlay so both must be discarded.
1072 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001073 let ret =
1074 // SAFETY: Both pointers are valid because they come from references, and fdt_overlay_apply
1075 // doesn't keep them after it returns. It may corrupt their contents if there is an error,
1076 // but that's our caller's responsibility.
1077 unsafe { libfdt_bindgen::fdt_overlay_apply(self.as_mut_ptr(), overlay.as_mut_ptr()) };
1078 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +00001079 Ok(self)
1080 }
1081
Alice Wang2422bdc2023-06-12 08:37:55 +00001082 /// Returns an iterator of memory banks specified the "/memory" node.
1083 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +01001084 ///
1085 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +00001086 pub fn memory(&self) -> Result<MemRegIterator> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +00001087 let node = self.node(cstr!("/memory"))?.ok_or(FdtError::NotFound)?;
1088 if node.device_type()? != Some(cstr!("memory")) {
Alice Wang2422bdc2023-06-12 08:37:55 +00001089 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001090 }
Alice Wang2422bdc2023-06-12 08:37:55 +00001091 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
1092 }
1093
1094 /// Returns the first memory range in the `/memory` node.
1095 pub fn first_memory_range(&self) -> Result<Range<usize>> {
1096 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +01001097 }
1098
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001099 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001100 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001101 self.node(cstr!("/chosen"))
David Brazdil1baa9a92022-06-28 14:47:50 +01001102 }
1103
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001104 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +00001105 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001106 self.node_mut(cstr!("/chosen"))
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +00001107 }
1108
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001109 /// Returns the root node of the tree.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001110 pub fn root(&self) -> Result<FdtNode> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001111 self.node(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001112 }
1113
Jaewan Kimf163d762023-11-01 13:12:50 +09001114 /// Returns the standard /__symbols__ node.
1115 pub fn symbols(&self) -> Result<Option<FdtNode>> {
1116 self.node(cstr!("/__symbols__"))
1117 }
1118
1119 /// Returns the standard /__symbols__ node as mutable
1120 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
1121 self.node_mut(cstr!("/__symbols__"))
1122 }
1123
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001124 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001125 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +00001126 let offset = self.path_offset(path.to_bytes())?;
1127
1128 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +01001129 }
1130
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001131 /// Iterate over nodes with a given compatible string.
1132 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
1133 CompatibleIterator::new(self, compatible)
1134 }
1135
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001136 /// Returns max phandle in the tree.
1137 pub fn max_phandle(&self) -> Result<Phandle> {
1138 let mut phandle: u32 = 0;
1139 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
1140 let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(self.as_ptr(), &mut phandle) };
1141
1142 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosieba27792023-10-30 12:04:12 +00001143 phandle.try_into()
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001144 }
1145
1146 /// Returns a node with the phandle
1147 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Jaewan Kimc63246d2023-11-09 15:41:01 +09001148 let offset = self.node_offset_with_phandle(phandle)?;
1149 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
1150 }
1151
1152 /// Returns a mutable node with the phandle
1153 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
1154 let offset = self.node_offset_with_phandle(phandle)?;
1155 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
1156 }
1157
1158 fn node_offset_with_phandle(&self, phandle: Phandle) -> Result<Option<c_int>> {
1159 // SAFETY: Accesses are constrained to the DT totalsize.
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001160 let ret = unsafe { libfdt_bindgen::fdt_node_offset_by_phandle(self.as_ptr(), phandle.0) };
Jaewan Kimc63246d2023-11-09 15:41:01 +09001161 fdt_err_or_option(ret)
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001162 }
1163
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001164 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001165 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001166 self.node_mut(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001167 }
1168
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001169 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001170 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +00001171 let offset = self.path_offset(path.to_bytes())?;
1172
1173 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001174 }
1175
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001176 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001177 pub fn as_slice(&self) -> &[u8] {
1178 &self.buffer[..self.totalsize()]
1179 }
1180
Jaewan Kimbab42592023-10-13 15:47:19 +09001181 fn path_offset(&self, path: &[u8]) -> Result<Option<c_int>> {
1182 let len = path.len().try_into().map_err(|_| FdtError::BadPath)?;
Andrew Walbran84b9a232023-07-05 14:01:40 +00001183 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +01001184 // function respects the passed number of characters.
1185 let ret = unsafe {
1186 // *_namelen functions don't include the trailing nul terminator in 'len'.
Jaewan Kimbab42592023-10-13 15:47:19 +09001187 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr().cast::<_>(), len)
David Brazdil1baa9a92022-06-28 14:47:50 +01001188 };
1189
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001190 fdt_err_or_option(ret)
David Brazdil1baa9a92022-06-28 14:47:50 +01001191 }
1192
1193 fn check_full(&self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001194 // SAFETY: Only performs read accesses within the limits of the slice. If successful, this
David Brazdil1baa9a92022-06-28 14:47:50 +01001195 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
1196 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
1197 // checking. The library doesn't maintain an internal state (such as pointers) between
1198 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
Pierre-Clément Tosi02017da2023-09-26 17:57:04 +01001199 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), self.capacity()) };
David Brazdil1baa9a92022-06-28 14:47:50 +01001200 fdt_err_expect_zero(ret)
1201 }
1202
Jaewan Kimaa638702023-09-19 13:34:01 +09001203 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
1204 let ptr = ptr as usize;
1205 let offset = ptr.checked_sub(self.as_ptr() as usize).ok_or(FdtError::Internal)?;
1206 self.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)
1207 }
1208
Jaewan Kim72d10902023-10-12 21:59:26 +09001209 fn string(&self, offset: c_int) -> Result<&CStr> {
1210 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
1211 let res = unsafe { libfdt_bindgen::fdt_string(self.as_ptr(), offset) };
1212 if res.is_null() {
1213 return Err(FdtError::Internal);
1214 }
1215
1216 // SAFETY: Non-null return from fdt_string() is valid null-terminating string within FDT.
1217 Ok(unsafe { CStr::from_ptr(res) })
1218 }
1219
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001220 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +00001221 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +00001222 self.buffer.as_ptr().cast()
David Brazdil1baa9a92022-06-28 14:47:50 +01001223 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001224
1225 fn as_mut_ptr(&mut self) -> *mut c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001226 self.buffer.as_mut_ptr().cast::<_>()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001227 }
1228
1229 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +00001230 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001231 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001232
1233 fn header(&self) -> &libfdt_bindgen::fdt_header {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +00001234 let p = self.as_ptr().cast();
Andrew Walbran84b9a232023-07-05 14:01:40 +00001235 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001236 unsafe { &*p }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001237 }
1238
1239 fn totalsize(&self) -> usize {
1240 u32::from_be(self.header().totalsize) as usize
1241 }
David Brazdil1baa9a92022-06-28 14:47:50 +01001242}