blob: c61876d2801625266bb936aaf03e02352e889f7e [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
163impl TryFrom<c_int> for AddrCells {
164 type Error = FdtError;
165
166 fn try_from(res: c_int) -> Result<Self> {
167 match fdt_err(res)? {
168 x if x == Self::Single as c_int => Ok(Self::Single),
169 x if x == Self::Double as c_int => Ok(Self::Double),
Andrew Walbranb39e6922022-12-05 17:01:20 +0000170 x if x == Self::Triple as c_int => 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
184impl TryFrom<c_int> for SizeCells {
185 type Error = FdtError;
186
187 fn try_from(res: c_int) -> Result<Self> {
188 match fdt_err(res)? {
189 x if x == Self::None as c_int => Ok(Self::None),
190 x if x == Self::Single as c_int => Ok(Self::Single),
191 x if x == Self::Double as c_int => Ok(Self::Double),
192 _ => 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 {
234 self.0.data.as_ptr().cast::<_>()
235 }
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
267 fdt_err_or_option(ret)?.map(|offset| Self::new(self.fdt, offset)).transpose()
268 }
269}
270
David Brazdil1baa9a92022-06-28 14:47:50 +0100271/// DT node.
Alice Wang9d4df702023-05-25 14:14:12 +0000272#[derive(Clone, Copy, Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100273pub struct FdtNode<'a> {
274 fdt: &'a Fdt,
275 offset: c_int,
276}
277
278impl<'a> FdtNode<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900279 /// Returns parent node.
David Brazdil1baa9a92022-06-28 14:47:50 +0100280 pub fn parent(&self) -> Result<Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000281 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
David Brazdil1baa9a92022-06-28 14:47:50 +0100282 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
283
284 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
285 }
286
Jaewan Kim5b057772023-10-19 01:02:17 +0900287 /// Returns supernode with depth. Note that root is at depth 0.
288 pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
289 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
290 let ret = unsafe {
291 libfdt_bindgen::fdt_supernode_atdepth_offset(
292 self.fdt.as_ptr(),
293 self.offset,
294 depth.try_into().unwrap(),
295 ptr::null_mut(),
296 )
297 };
298
299 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
300 }
301
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900302 /// Returns the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000303 pub fn device_type(&self) -> Result<Option<&CStr>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900304 self.getprop_str(cstr!("device_type"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100305 }
306
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900307 /// Returns the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000308 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900309 let reg = cstr!("reg");
David Brazdil1baa9a92022-06-28 14:47:50 +0100310
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000311 if let Some(cells) = self.getprop_cells(reg)? {
312 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100313
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000314 let addr_cells = parent.address_cells()?;
315 let size_cells = parent.size_cells()?;
316
317 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
318 } else {
319 Ok(None)
320 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100321 }
322
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900323 /// Returns the standard ranges property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000324 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900325 let ranges = cstr!("ranges");
Andrew Walbranb39e6922022-12-05 17:01:20 +0000326 if let Some(cells) = self.getprop_cells(ranges)? {
327 let parent = self.parent()?;
328 let addr_cells = self.address_cells()?;
329 let parent_addr_cells = parent.address_cells()?;
330 let size_cells = self.size_cells()?;
331 Ok(Some(RangesIterator::<A, P, S>::new(
332 cells,
333 addr_cells,
334 parent_addr_cells,
335 size_cells,
336 )))
337 } else {
338 Ok(None)
339 }
340 }
341
Jaewan Kimaa638702023-09-19 13:34:01 +0900342 /// Returns the node name.
343 pub fn name(&self) -> Result<&'a CStr> {
344 let mut len: c_int = 0;
345 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor). On success, the
346 // function returns valid null terminating string and otherwise returned values are dropped.
347 let name = unsafe { libfdt_bindgen::fdt_get_name(self.fdt.as_ptr(), self.offset, &mut len) }
348 as *const c_void;
349 let len = usize::try_from(fdt_err(len)?).unwrap();
350 let name = self.fdt.get_from_ptr(name, len + 1)?;
351 CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
352 }
353
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900354 /// Returns the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000355 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
356 let value = if let Some(bytes) = self.getprop(name)? {
357 Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?)
358 } else {
359 None
360 };
361 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100362 }
363
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900364 /// Returns the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000365 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
366 if let Some(cells) = self.getprop(name)? {
367 Ok(Some(CellIterator::new(cells)))
368 } else {
369 Ok(None)
370 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100371 }
372
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900373 /// Returns the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000374 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
375 let value = if let Some(bytes) = self.getprop(name)? {
376 Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
377 } else {
378 None
379 };
380 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100381 }
382
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900383 /// Returns the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000384 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
385 let value = if let Some(bytes) = self.getprop(name)? {
386 Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
387 } else {
388 None
389 };
390 Ok(value)
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 {
398 Ok(None) // property was not found
399 }
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 };
450
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000451 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000452 }
453
Alice Wang474c0ee2023-09-14 12:52:33 +0000454 /// Returns the first range of `reg` in this node.
455 pub fn first_reg(&self) -> Result<Reg<u64>> {
456 self.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
457 }
458
David Brazdil1baa9a92022-06-28 14:47:50 +0100459 fn address_cells(&self) -> Result<AddrCells> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000460 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
David Brazdil1baa9a92022-06-28 14:47:50 +0100461 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
462 .try_into()
463 .map_err(|_| FdtError::Internal)
464 }
465
466 fn size_cells(&self) -> Result<SizeCells> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000467 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
David Brazdil1baa9a92022-06-28 14:47:50 +0100468 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
469 .try_into()
470 .map_err(|_| FdtError::Internal)
471 }
Jaewan Kimbc828d72023-09-19 15:52:08 +0900472
473 /// Returns an iterator of subnodes
Jaewan Kim4a34b0d2024-01-19 13:17:47 +0900474 pub fn subnodes(&self) -> Result<SubnodeIterator<'a>> {
Jaewan Kimbc828d72023-09-19 15:52:08 +0900475 SubnodeIterator::new(self)
476 }
477
478 fn first_subnode(&self) -> Result<Option<Self>> {
479 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
480 let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
481
482 Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
483 }
484
485 fn next_subnode(&self) -> Result<Option<Self>> {
486 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
487 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
488
489 Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
490 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900491
Jaewan Kimc9e14112023-12-04 17:05:27 +0900492 /// Returns an iterator of descendants
Jaewan Kim1eab7232024-01-04 09:46:16 +0900493 pub fn descendants(&self) -> DescendantsIterator<'a> {
Jaewan Kimc9e14112023-12-04 17:05:27 +0900494 DescendantsIterator::new(self)
495 }
496
497 fn next_node(&self, depth: usize) -> Result<Option<(Self, usize)>> {
498 let mut next_depth: c_int = depth.try_into().unwrap();
499 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
500 let ret = unsafe {
501 libfdt_bindgen::fdt_next_node(self.fdt.as_ptr(), self.offset, &mut next_depth)
502 };
503 let Ok(next_depth) = usize::try_from(next_depth) else {
504 return Ok(None);
505 };
506 Ok(fdt_err_or_option(ret)?.map(|offset| (FdtNode { fdt: self.fdt, offset }, next_depth)))
507 }
508
Jaewan Kim72d10902023-10-12 21:59:26 +0900509 /// Returns an iterator of properties
510 pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
511 PropertyIterator::new(self)
512 }
513
514 fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
515 let ret =
516 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
517 unsafe { libfdt_bindgen::fdt_first_property_offset(self.fdt.as_ptr(), self.offset) };
518
519 fdt_err_or_option(ret)?.map(|offset| FdtProperty::new(self.fdt, offset)).transpose()
520 }
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900521
522 /// Returns the phandle
523 pub fn get_phandle(&self) -> Result<Option<Phandle>> {
524 // This rewrites the fdt_get_phandle() because it doesn't return error code.
525 if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
526 Ok(Some(prop.try_into()?))
527 } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
528 Ok(Some(prop.try_into()?))
529 } else {
530 Ok(None)
531 }
532 }
Jaewan Kim52026012023-12-13 13:49:28 +0900533
534 /// Returns the subnode of the given name. The name doesn't need to be nul-terminated.
535 pub fn subnode(&self, name: &CStr) -> Result<Option<Self>> {
536 let offset = self.subnode_offset(name.to_bytes())?;
537 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
538 }
539
540 /// Returns the subnode of the given name bytes
541 pub fn subnode_with_name_bytes(&self, name: &[u8]) -> Result<Option<Self>> {
542 let offset = self.subnode_offset(name)?;
543 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
544 }
545
546 fn subnode_offset(&self, name: &[u8]) -> Result<Option<c_int>> {
547 let namelen = name.len().try_into().unwrap();
548 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
549 let ret = unsafe {
550 libfdt_bindgen::fdt_subnode_offset_namelen(
551 self.fdt.as_ptr(),
552 self.offset,
553 name.as_ptr().cast::<_>(),
554 namelen,
555 )
556 };
557 fdt_err_or_option(ret)
558 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100559}
560
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000561impl<'a> PartialEq for FdtNode<'a> {
562 fn eq(&self, other: &Self) -> bool {
563 self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
564 }
565}
566
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900567/// Phandle of a FDT node
568#[repr(transparent)]
Jaewan Kim55f438c2023-11-15 01:24:36 +0900569#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900570pub struct Phandle(u32);
571
572impl Phandle {
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000573 /// Minimum valid value for device tree phandles.
574 pub const MIN: Self = Self(1);
575 /// Maximum valid value for device tree phandles.
576 pub const MAX: Self = Self(libfdt_bindgen::FDT_MAX_PHANDLE);
577
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900578 /// Creates a new Phandle
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000579 pub const fn new(value: u32) -> Option<Self> {
580 if Self::MIN.0 <= value && value <= Self::MAX.0 {
581 Some(Self(value))
582 } else {
583 None
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900584 }
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900585 }
586}
587
588impl From<Phandle> for u32 {
589 fn from(phandle: Phandle) -> u32 {
590 phandle.0
591 }
592}
593
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000594impl TryFrom<u32> for Phandle {
595 type Error = FdtError;
596
597 fn try_from(value: u32) -> Result<Self> {
598 Self::new(value).ok_or(FdtError::BadPhandle)
599 }
600}
601
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000602/// Mutable FDT node.
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000603#[derive(Debug)]
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000604pub struct FdtNodeMut<'a> {
605 fdt: &'a mut Fdt,
606 offset: c_int,
607}
608
609impl<'a> FdtNodeMut<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900610 /// Appends a property name-value (possibly empty) pair to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000611 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000612 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000613 let ret = unsafe {
614 libfdt_bindgen::fdt_appendprop(
615 self.fdt.as_mut_ptr(),
616 self.offset,
617 name.as_ptr(),
618 value.as_ref().as_ptr().cast::<c_void>(),
619 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
620 )
621 };
622
623 fdt_err_expect_zero(ret)
624 }
625
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900626 /// Appends a (address, size) pair property to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000627 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000628 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000629 let ret = unsafe {
630 libfdt_bindgen::fdt_appendprop_addrrange(
631 self.fdt.as_mut_ptr(),
632 self.parent()?.offset,
633 self.offset,
634 name.as_ptr(),
635 addr,
636 size,
637 )
638 };
639
640 fdt_err_expect_zero(ret)
641 }
642
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900643 /// Sets a property name-value pair to the given node.
644 ///
645 /// This may create a new prop or replace existing value.
Jaewan Kimba8929b2023-01-13 11:13:29 +0900646 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000647 // SAFETY: New value size is constrained to the DT totalsize
Jaewan Kimba8929b2023-01-13 11:13:29 +0900648 // (validated by underlying libfdt).
649 let ret = unsafe {
650 libfdt_bindgen::fdt_setprop(
651 self.fdt.as_mut_ptr(),
652 self.offset,
653 name.as_ptr(),
654 value.as_ptr().cast::<c_void>(),
655 value.len().try_into().map_err(|_| FdtError::BadValue)?,
656 )
657 };
658
659 fdt_err_expect_zero(ret)
660 }
661
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900662 /// Sets the value of the given property with the given value, and ensure that the given
663 /// value has the same length as the current value length.
664 ///
665 /// This can only be used to replace existing value.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900666 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000667 // SAFETY: fdt size is not altered
Jiyong Park9c63cd12023-03-21 17:53:07 +0900668 let ret = unsafe {
669 libfdt_bindgen::fdt_setprop_inplace(
670 self.fdt.as_mut_ptr(),
671 self.offset,
672 name.as_ptr(),
673 value.as_ptr().cast::<c_void>(),
674 value.len().try_into().map_err(|_| FdtError::BadValue)?,
675 )
676 };
677
678 fdt_err_expect_zero(ret)
679 }
680
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900681 /// Sets the value of the given (address, size) pair property with the given value, and
682 /// ensure that the given value has the same length as the current value length.
683 ///
684 /// This can only be used to replace existing value.
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000685 pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
686 let pair = [addr.to_be(), size.to_be()];
687 self.setprop_inplace(name, pair.as_bytes())
688 }
689
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900690 /// Sets a flag-like empty property.
691 ///
692 /// This may create a new prop or replace existing value.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000693 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
694 self.setprop(name, &[])
695 }
696
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900697 /// Deletes the given property.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000698 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000699 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000700 // library locates the node's property. Removing the property may shift the offsets of
701 // other nodes and properties but the borrow checker should prevent this function from
702 // being called when FdtNode instances are in use.
703 let ret = unsafe {
704 libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
705 };
706
707 fdt_err_expect_zero(ret)
708 }
709
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900710 /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000711 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000712 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000713 // library locates the node's property.
714 let ret = unsafe {
715 libfdt_bindgen::fdt_nop_property(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
716 };
717
718 fdt_err_expect_zero(ret)
719 }
720
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900721 /// Trims the size of the given property to new_size.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900722 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
723 let (prop, len) =
724 FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
725 if len == new_size {
726 return Ok(());
727 }
728 if new_size > len {
729 return Err(FdtError::NoSpace);
730 }
731
Andrew Walbran84b9a232023-07-05 14:01:40 +0000732 // SAFETY: new_size is smaller than the old size
Jiyong Park9c63cd12023-03-21 17:53:07 +0900733 let ret = unsafe {
734 libfdt_bindgen::fdt_setprop(
735 self.fdt.as_mut_ptr(),
736 self.offset,
737 name.as_ptr(),
738 prop.cast::<c_void>(),
739 new_size.try_into().map_err(|_| FdtError::BadValue)?,
740 )
741 };
742
743 fdt_err_expect_zero(ret)
744 }
745
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900746 /// Returns reference to the containing device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000747 pub fn fdt(&mut self) -> &mut Fdt {
748 self.fdt
749 }
750
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900751 /// Returns immutable FdtNode of this node.
752 pub fn as_node(&self) -> FdtNode {
753 FdtNode { fdt: self.fdt, offset: self.offset }
754 }
755
Jaewan Kime6363422024-01-19 14:00:00 +0900756 /// Adds new subnodes to the given node.
757 pub fn add_subnodes(&mut self, names: &[&CStr]) -> Result<()> {
758 for name in names {
759 self.add_subnode_offset(name.to_bytes())?;
760 }
761 Ok(())
762 }
763
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900764 /// 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 +0000765 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
Jaewan Kim5ab13582023-10-20 20:56:27 +0900766 let offset = self.add_subnode_offset(name.to_bytes())?;
767 Ok(Self { fdt: self.fdt, offset })
768 }
769
770 /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
771 /// on success.
772 pub fn add_subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Self> {
773 let offset = { self.add_subnode_offset(&name.to_bytes()[..namelen])? };
774 Ok(Self { fdt: self.fdt, offset })
775 }
776
777 fn add_subnode_offset(&mut self, name: &[u8]) -> Result<c_int> {
778 let namelen = name.len().try_into().unwrap();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000779 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000780 let ret = unsafe {
Jaewan Kim5ab13582023-10-20 20:56:27 +0900781 libfdt_bindgen::fdt_add_subnode_namelen(
782 self.fdt.as_mut_ptr(),
783 self.offset,
784 name.as_ptr().cast::<_>(),
785 namelen,
786 )
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000787 };
Jaewan Kim5ab13582023-10-20 20:56:27 +0900788 fdt_err(ret)
789 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000790
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900791 /// Returns the first subnode of this
792 pub fn first_subnode(&'a mut self) -> Result<Option<Self>> {
793 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
794 let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
795
796 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
797 }
798
799 /// Returns the next subnode that shares the same parent with this
800 pub fn next_subnode(self) -> Result<Option<Self>> {
801 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
802 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
803
804 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
805 }
806
807 /// Deletes the current node and returns the next subnode
808 pub fn delete_and_next_subnode(mut self) -> Result<Option<Self>> {
809 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
810 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
811
812 let next_offset = fdt_err_or_option(ret)?;
813
814 if Some(self.offset) == next_offset {
815 return Err(FdtError::Internal);
816 }
817
818 // SAFETY: nop_self() only touches bytes of the self and its properties and subnodes, and
819 // doesn't alter any other blob in the tree. self.fdt and next_offset would remain valid.
820 unsafe { self.nop_self()? };
821
822 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
823 }
824
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900825 fn next_node_offset(&self, depth: usize) -> Result<Option<(c_int, usize)>> {
826 let mut next_depth: c_int = depth.try_into().or(Err(FdtError::BadValue))?;
827 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
828 let ret = unsafe {
829 libfdt_bindgen::fdt_next_node(self.fdt.as_ptr(), self.offset, &mut next_depth)
830 };
831 let Ok(next_depth) = usize::try_from(next_depth) else {
832 return Ok(None);
833 };
834 Ok(fdt_err_or_option(ret)?.map(|offset| (offset, next_depth)))
835 }
836
837 /// Returns the next node
838 pub fn next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
839 Ok(self
840 .next_node_offset(depth)?
841 .map(|(offset, next_depth)| (FdtNodeMut { fdt: self.fdt, offset }, next_depth)))
842 }
843
844 /// Deletes this and returns the next node
845 pub fn delete_and_next_node(mut self, depth: usize) -> Result<Option<(Self, usize)>> {
846 // Skip all would-be-removed descendants.
847 let mut iter = self.next_node_offset(depth)?;
848 while let Some((descendant_offset, descendant_depth)) = iter {
849 if descendant_depth <= depth {
850 break;
851 }
852 let descendant = FdtNodeMut { fdt: self.fdt, offset: descendant_offset };
853 iter = descendant.next_node_offset(descendant_depth)?;
854 }
855 // SAFETY: This consumes self, so invalid node wouldn't be used any further
856 unsafe { self.nop_self()? };
857 Ok(iter.map(|(offset, next_depth)| (FdtNodeMut { fdt: self.fdt, offset }, next_depth)))
858 }
859
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000860 fn parent(&'a self) -> Result<FdtNode<'a>> {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000861 self.as_node().parent()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000862 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900863
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900864 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900865 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000866 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900867 let ret = unsafe {
868 libfdt_bindgen::fdt_node_offset_by_compatible(
869 self.fdt.as_ptr(),
870 self.offset,
871 compatible.as_ptr(),
872 )
873 };
874
875 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
876 }
877
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900878 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
879 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900880 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
881 // The reason is that libfdt ensures that the node from where the search for the next
882 // compatible node is started is always a valid one -- except for the special case of offset =
883 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
884 // next compatible node from it.
885 //
886 // We can't do in the opposite direction either. If we call next_compatible to find the next
887 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
888 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
889 // DT).
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900890 pub fn delete_and_next_compatible(mut self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000891 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900892 let ret = unsafe {
893 libfdt_bindgen::fdt_node_offset_by_compatible(
894 self.fdt.as_ptr(),
895 self.offset,
896 compatible.as_ptr(),
897 )
898 };
899 let next_offset = fdt_err_or_option(ret)?;
900
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900901 if Some(self.offset) == next_offset {
902 return Err(FdtError::Internal);
903 }
904
905 // SAFETY: nop_self() only touches bytes of the self and its properties and subnodes, and
906 // doesn't alter any other blob in the tree. self.fdt and next_offset would remain valid.
907 unsafe { self.nop_self()? };
Jiyong Park9c63cd12023-03-21 17:53:07 +0900908
909 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
910 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900911
912 /// Deletes this node effectively from DT, by setting it with FDT_NOP
913 pub fn nop(mut self) -> Result<()> {
914 // SAFETY: This consumes self, so invalid node wouldn't be used any further
915 unsafe { self.nop_self() }
916 }
917
918 /// Deletes this node effectively from DT, by setting it with FDT_NOP.
919 /// This only changes bytes of the node and its properties and subnodes, and doesn't alter or
920 /// move any other part of the tree.
921 /// SAFETY: This node is no longer valid.
922 unsafe fn nop_self(&mut self) -> Result<()> {
923 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
924 let ret = unsafe { libfdt_bindgen::fdt_nop_node(self.fdt.as_mut_ptr(), self.offset) };
925
926 fdt_err_expect_zero(ret)
927 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000928}
929
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000930/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000931#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100932#[repr(transparent)]
933pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000934 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100935}
936
937impl Fdt {
938 /// Wraps a slice containing a Flattened Device Tree.
939 ///
940 /// Fails if the FDT does not pass validation.
941 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000942 // SAFETY: The FDT will be validated before it is returned.
David Brazdil1baa9a92022-06-28 14:47:50 +0100943 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
944 fdt.check_full()?;
945 Ok(fdt)
946 }
947
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000948 /// Wraps a mutable slice containing a Flattened Device Tree.
949 ///
950 /// Fails if the FDT does not pass validation.
951 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000952 // SAFETY: The FDT will be validated before it is returned.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000953 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
954 fdt.check_full()?;
955 Ok(fdt)
956 }
957
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900958 /// Creates an empty Flattened Device Tree with a mutable slice.
959 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000960 // SAFETY: fdt_create_empty_tree() only write within the specified length,
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900961 // and returns error if buffer was insufficient.
962 // There will be no memory write outside of the given fdt.
963 let ret = unsafe {
964 libfdt_bindgen::fdt_create_empty_tree(
965 fdt.as_mut_ptr().cast::<c_void>(),
966 fdt.len() as i32,
967 )
968 };
969 fdt_err_expect_zero(ret)?;
970
Andrew Walbran84b9a232023-07-05 14:01:40 +0000971 // SAFETY: The FDT will be validated before it is returned.
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900972 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
973 fdt.check_full()?;
974
975 Ok(fdt)
976 }
977
David Brazdil1baa9a92022-06-28 14:47:50 +0100978 /// Wraps a slice containing a Flattened Device Tree.
979 ///
980 /// # Safety
981 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000982 /// 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 +0100983 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000984 let self_ptr = fdt as *const _ as *const _;
985 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
986 unsafe { &*self_ptr }
David Brazdil1baa9a92022-06-28 14:47:50 +0100987 }
988
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000989 /// Wraps a mutable slice containing a Flattened Device Tree.
990 ///
991 /// # Safety
992 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000993 /// 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 +0000994 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000995 let self_mut_ptr = fdt as *mut _ as *mut _;
996 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
997 unsafe { &mut *self_mut_ptr }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000998 }
999
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +00001000 /// Updates this FDT from another FDT.
1001 pub fn clone_from(&mut self, other: &Self) -> Result<()> {
1002 let new_len = other.buffer.len();
1003 if self.buffer.len() < new_len {
1004 return Err(FdtError::NoSpace);
Jiyong Parke9d87e82023-03-21 19:28:40 +09001005 }
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +00001006
1007 let zeroed_len = self.totalsize().checked_sub(new_len);
1008 let (cloned, zeroed) = self.buffer.split_at_mut(new_len);
1009
1010 cloned.clone_from_slice(&other.buffer);
1011 if let Some(len) = zeroed_len {
1012 zeroed[..len].fill(0);
1013 }
1014
1015 Ok(())
Jiyong Parke9d87e82023-03-21 19:28:40 +09001016 }
1017
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001018 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001019 pub fn unpack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001020 // SAFETY: "Opens" the DT in-place (supported use-case) by updating its header and
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001021 // internal structures to make use of the whole self.fdt slice but performs no accesses
1022 // outside of it and leaves the DT in a state that will be detected by other functions.
1023 let ret = unsafe {
1024 libfdt_bindgen::fdt_open_into(
1025 self.as_ptr(),
1026 self.as_mut_ptr(),
1027 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
1028 )
1029 };
1030 fdt_err_expect_zero(ret)
1031 }
1032
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001033 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001034 ///
1035 /// Doesn't shrink the underlying memory slice.
1036 pub fn pack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001037 // SAFETY: "Closes" the DT in-place by updating its header and relocating its structs.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001038 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
1039 fdt_err_expect_zero(ret)
1040 }
1041
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +00001042 /// Applies a DT overlay on the base DT.
1043 ///
1044 /// # Safety
1045 ///
1046 /// On failure, the library corrupts the DT and overlay so both must be discarded.
1047 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001048 let ret =
1049 // SAFETY: Both pointers are valid because they come from references, and fdt_overlay_apply
1050 // doesn't keep them after it returns. It may corrupt their contents if there is an error,
1051 // but that's our caller's responsibility.
1052 unsafe { libfdt_bindgen::fdt_overlay_apply(self.as_mut_ptr(), overlay.as_mut_ptr()) };
1053 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +00001054 Ok(self)
1055 }
1056
Alice Wang2422bdc2023-06-12 08:37:55 +00001057 /// Returns an iterator of memory banks specified the "/memory" node.
1058 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +01001059 ///
1060 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +00001061 pub fn memory(&self) -> Result<MemRegIterator> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001062 let memory_node_name = cstr!("/memory");
1063 let memory_device_type = cstr!("memory");
David Brazdil1baa9a92022-06-28 14:47:50 +01001064
Alice Wang2422bdc2023-06-12 08:37:55 +00001065 let node = self.node(memory_node_name)?.ok_or(FdtError::NotFound)?;
1066 if node.device_type()? != Some(memory_device_type) {
1067 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001068 }
Alice Wang2422bdc2023-06-12 08:37:55 +00001069 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
1070 }
1071
1072 /// Returns the first memory range in the `/memory` node.
1073 pub fn first_memory_range(&self) -> Result<Range<usize>> {
1074 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +01001075 }
1076
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001077 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001078 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001079 self.node(cstr!("/chosen"))
David Brazdil1baa9a92022-06-28 14:47:50 +01001080 }
1081
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001082 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +00001083 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001084 self.node_mut(cstr!("/chosen"))
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +00001085 }
1086
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001087 /// Returns the root node of the tree.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001088 pub fn root(&self) -> Result<FdtNode> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001089 self.node(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001090 }
1091
Jaewan Kimf163d762023-11-01 13:12:50 +09001092 /// Returns the standard /__symbols__ node.
1093 pub fn symbols(&self) -> Result<Option<FdtNode>> {
1094 self.node(cstr!("/__symbols__"))
1095 }
1096
1097 /// Returns the standard /__symbols__ node as mutable
1098 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
1099 self.node_mut(cstr!("/__symbols__"))
1100 }
1101
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001102 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001103 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Jaewan Kimbab42592023-10-13 15:47:19 +09001104 Ok(self.path_offset(path.to_bytes())?.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +01001105 }
1106
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001107 /// Iterate over nodes with a given compatible string.
1108 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
1109 CompatibleIterator::new(self, compatible)
1110 }
1111
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001112 /// Returns max phandle in the tree.
1113 pub fn max_phandle(&self) -> Result<Phandle> {
1114 let mut phandle: u32 = 0;
1115 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
1116 let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(self.as_ptr(), &mut phandle) };
1117
1118 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosieba27792023-10-30 12:04:12 +00001119 phandle.try_into()
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001120 }
1121
1122 /// Returns a node with the phandle
1123 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Jaewan Kimc63246d2023-11-09 15:41:01 +09001124 let offset = self.node_offset_with_phandle(phandle)?;
1125 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
1126 }
1127
1128 /// Returns a mutable node with the phandle
1129 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
1130 let offset = self.node_offset_with_phandle(phandle)?;
1131 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
1132 }
1133
1134 fn node_offset_with_phandle(&self, phandle: Phandle) -> Result<Option<c_int>> {
1135 // SAFETY: Accesses are constrained to the DT totalsize.
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001136 let ret = unsafe { libfdt_bindgen::fdt_node_offset_by_phandle(self.as_ptr(), phandle.0) };
Jaewan Kimc63246d2023-11-09 15:41:01 +09001137 fdt_err_or_option(ret)
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001138 }
1139
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001140 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001141 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001142 self.node_mut(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001143 }
1144
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001145 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001146 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Jaewan Kimbab42592023-10-13 15:47:19 +09001147 Ok(self.path_offset(path.to_bytes())?.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001148 }
1149
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001150 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001151 pub fn as_slice(&self) -> &[u8] {
1152 &self.buffer[..self.totalsize()]
1153 }
1154
Jaewan Kimbab42592023-10-13 15:47:19 +09001155 fn path_offset(&self, path: &[u8]) -> Result<Option<c_int>> {
1156 let len = path.len().try_into().map_err(|_| FdtError::BadPath)?;
Andrew Walbran84b9a232023-07-05 14:01:40 +00001157 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +01001158 // function respects the passed number of characters.
1159 let ret = unsafe {
1160 // *_namelen functions don't include the trailing nul terminator in 'len'.
Jaewan Kimbab42592023-10-13 15:47:19 +09001161 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr().cast::<_>(), len)
David Brazdil1baa9a92022-06-28 14:47:50 +01001162 };
1163
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001164 fdt_err_or_option(ret)
David Brazdil1baa9a92022-06-28 14:47:50 +01001165 }
1166
1167 fn check_full(&self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001168 // SAFETY: Only performs read accesses within the limits of the slice. If successful, this
David Brazdil1baa9a92022-06-28 14:47:50 +01001169 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
1170 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
1171 // checking. The library doesn't maintain an internal state (such as pointers) between
1172 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
Pierre-Clément Tosi02017da2023-09-26 17:57:04 +01001173 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), self.capacity()) };
David Brazdil1baa9a92022-06-28 14:47:50 +01001174 fdt_err_expect_zero(ret)
1175 }
1176
Jaewan Kimaa638702023-09-19 13:34:01 +09001177 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
1178 let ptr = ptr as usize;
1179 let offset = ptr.checked_sub(self.as_ptr() as usize).ok_or(FdtError::Internal)?;
1180 self.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)
1181 }
1182
Jaewan Kim72d10902023-10-12 21:59:26 +09001183 fn string(&self, offset: c_int) -> Result<&CStr> {
1184 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
1185 let res = unsafe { libfdt_bindgen::fdt_string(self.as_ptr(), offset) };
1186 if res.is_null() {
1187 return Err(FdtError::Internal);
1188 }
1189
1190 // SAFETY: Non-null return from fdt_string() is valid null-terminating string within FDT.
1191 Ok(unsafe { CStr::from_ptr(res) })
1192 }
1193
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001194 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +00001195 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001196 self.buffer.as_ptr().cast::<_>()
David Brazdil1baa9a92022-06-28 14:47:50 +01001197 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001198
1199 fn as_mut_ptr(&mut self) -> *mut c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001200 self.buffer.as_mut_ptr().cast::<_>()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001201 }
1202
1203 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +00001204 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001205 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001206
1207 fn header(&self) -> &libfdt_bindgen::fdt_header {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001208 let p = self.as_ptr().cast::<_>();
Andrew Walbran84b9a232023-07-05 14:01:40 +00001209 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001210 unsafe { &*p }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001211 }
1212
1213 fn totalsize(&self) -> usize {
1214 u32::from_be(self.header().totalsize) as usize
1215 }
David Brazdil1baa9a92022-06-28 14:47:50 +01001216}