blob: 0cc781ee497f52f0e209fa9742088a25e089a3d1 [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]
Pierre-Clément Tosib244d932022-11-24 16:45:53 +000019#![feature(let_else)] // Stabilized in 1.65.0
David Brazdil1baa9a92022-06-28 14:47:50 +010020
Andrew Walbran55ad01b2022-12-05 17:00:40 +000021mod iterators;
22
23pub use iterators::{CellIterator, MemRegIterator, Reg, RegIterator};
24
David Brazdil1baa9a92022-06-28 14:47:50 +010025use core::ffi::{c_int, c_void, CStr};
26use core::fmt;
27use core::mem;
David Brazdil1baa9a92022-06-28 14:47:50 +010028use core::result;
David Brazdil1baa9a92022-06-28 14:47:50 +010029
30/// Error type corresponding to libfdt error codes.
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub enum FdtError {
33 /// FDT_ERR_NOTFOUND
34 NotFound,
35 /// FDT_ERR_EXISTS
36 Exists,
37 /// FDT_ERR_NOSPACE
38 NoSpace,
39 /// FDT_ERR_BADOFFSET
40 BadOffset,
41 /// FDT_ERR_BADPATH
42 BadPath,
43 /// FDT_ERR_BADPHANDLE
44 BadPhandle,
45 /// FDT_ERR_BADSTATE
46 BadState,
47 /// FDT_ERR_TRUNCATED
48 Truncated,
49 /// FDT_ERR_BADMAGIC
50 BadMagic,
51 /// FDT_ERR_BADVERSION
52 BadVersion,
53 /// FDT_ERR_BADSTRUCTURE
54 BadStructure,
55 /// FDT_ERR_BADLAYOUT
56 BadLayout,
57 /// FDT_ERR_INTERNAL
58 Internal,
59 /// FDT_ERR_BADNCELLS
60 BadNCells,
61 /// FDT_ERR_BADVALUE
62 BadValue,
63 /// FDT_ERR_BADOVERLAY
64 BadOverlay,
65 /// FDT_ERR_NOPHANDLES
66 NoPhandles,
67 /// FDT_ERR_BADFLAGS
68 BadFlags,
69 /// FDT_ERR_ALIGNMENT
70 Alignment,
71 /// Unexpected error code
72 Unknown(i32),
73}
74
75impl fmt::Display for FdtError {
76 /// Prints error messages from libfdt.h documentation.
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 match self {
79 Self::NotFound => write!(f, "The requested node or property does not exist"),
80 Self::Exists => write!(f, "Attempted to create an existing node or property"),
81 Self::NoSpace => write!(f, "Insufficient buffer space to contain the expanded tree"),
82 Self::BadOffset => write!(f, "Structure block offset is out-of-bounds or invalid"),
83 Self::BadPath => write!(f, "Badly formatted path"),
84 Self::BadPhandle => write!(f, "Invalid phandle length or value"),
85 Self::BadState => write!(f, "Received incomplete device tree"),
86 Self::Truncated => write!(f, "Device tree or sub-block is improperly terminated"),
87 Self::BadMagic => write!(f, "Device tree header missing its magic number"),
88 Self::BadVersion => write!(f, "Device tree has a version which can't be handled"),
89 Self::BadStructure => write!(f, "Device tree has a corrupt structure block"),
90 Self::BadLayout => write!(f, "Device tree sub-blocks in unsupported order"),
91 Self::Internal => write!(f, "libfdt has failed an internal assertion"),
92 Self::BadNCells => write!(f, "Bad format or value of #address-cells or #size-cells"),
93 Self::BadValue => write!(f, "Unexpected property value"),
94 Self::BadOverlay => write!(f, "Overlay cannot be applied"),
95 Self::NoPhandles => write!(f, "Device tree doesn't have any phandle available anymore"),
96 Self::BadFlags => write!(f, "Invalid flag or invalid combination of flags"),
97 Self::Alignment => write!(f, "Device tree base address is not 8-byte aligned"),
98 Self::Unknown(e) => write!(f, "Unknown libfdt error '{e}'"),
99 }
100 }
101}
102
103/// Result type with FdtError enum.
104pub type Result<T> = result::Result<T, FdtError>;
105
106fn fdt_err(val: c_int) -> Result<c_int> {
107 if val >= 0 {
108 Ok(val)
109 } else {
110 Err(match -val as _ {
111 libfdt_bindgen::FDT_ERR_NOTFOUND => FdtError::NotFound,
112 libfdt_bindgen::FDT_ERR_EXISTS => FdtError::Exists,
113 libfdt_bindgen::FDT_ERR_NOSPACE => FdtError::NoSpace,
114 libfdt_bindgen::FDT_ERR_BADOFFSET => FdtError::BadOffset,
115 libfdt_bindgen::FDT_ERR_BADPATH => FdtError::BadPath,
116 libfdt_bindgen::FDT_ERR_BADPHANDLE => FdtError::BadPhandle,
117 libfdt_bindgen::FDT_ERR_BADSTATE => FdtError::BadState,
118 libfdt_bindgen::FDT_ERR_TRUNCATED => FdtError::Truncated,
119 libfdt_bindgen::FDT_ERR_BADMAGIC => FdtError::BadMagic,
120 libfdt_bindgen::FDT_ERR_BADVERSION => FdtError::BadVersion,
121 libfdt_bindgen::FDT_ERR_BADSTRUCTURE => FdtError::BadStructure,
122 libfdt_bindgen::FDT_ERR_BADLAYOUT => FdtError::BadLayout,
123 libfdt_bindgen::FDT_ERR_INTERNAL => FdtError::Internal,
124 libfdt_bindgen::FDT_ERR_BADNCELLS => FdtError::BadNCells,
125 libfdt_bindgen::FDT_ERR_BADVALUE => FdtError::BadValue,
126 libfdt_bindgen::FDT_ERR_BADOVERLAY => FdtError::BadOverlay,
127 libfdt_bindgen::FDT_ERR_NOPHANDLES => FdtError::NoPhandles,
128 libfdt_bindgen::FDT_ERR_BADFLAGS => FdtError::BadFlags,
129 libfdt_bindgen::FDT_ERR_ALIGNMENT => FdtError::Alignment,
130 _ => FdtError::Unknown(val),
131 })
132 }
133}
134
135fn fdt_err_expect_zero(val: c_int) -> Result<()> {
136 match fdt_err(val)? {
137 0 => Ok(()),
138 _ => Err(FdtError::Unknown(val)),
139 }
140}
141
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000142fn fdt_err_or_option(val: c_int) -> Result<Option<c_int>> {
143 match fdt_err(val) {
144 Ok(val) => Ok(Some(val)),
145 Err(FdtError::NotFound) => Ok(None),
146 Err(e) => Err(e),
147 }
148}
149
David Brazdil1baa9a92022-06-28 14:47:50 +0100150/// Value of a #address-cells property.
151#[derive(Copy, Clone, Debug)]
152enum AddrCells {
153 Single = 1,
154 Double = 2,
155}
156
157impl TryFrom<c_int> for AddrCells {
158 type Error = FdtError;
159
160 fn try_from(res: c_int) -> Result<Self> {
161 match fdt_err(res)? {
162 x if x == Self::Single as c_int => Ok(Self::Single),
163 x if x == Self::Double as c_int => Ok(Self::Double),
164 _ => Err(FdtError::BadNCells),
165 }
166 }
167}
168
169/// Value of a #size-cells property.
170#[derive(Copy, Clone, Debug)]
171enum SizeCells {
172 None = 0,
173 Single = 1,
174 Double = 2,
175}
176
177impl TryFrom<c_int> for SizeCells {
178 type Error = FdtError;
179
180 fn try_from(res: c_int) -> Result<Self> {
181 match fdt_err(res)? {
182 x if x == Self::None as c_int => Ok(Self::None),
183 x if x == Self::Single as c_int => Ok(Self::Single),
184 x if x == Self::Double as c_int => Ok(Self::Double),
185 _ => Err(FdtError::BadNCells),
186 }
187 }
188}
189
David Brazdil1baa9a92022-06-28 14:47:50 +0100190/// DT node.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000191#[derive(Clone, Copy)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100192pub struct FdtNode<'a> {
193 fdt: &'a Fdt,
194 offset: c_int,
195}
196
197impl<'a> FdtNode<'a> {
198 /// Find parent node.
199 pub fn parent(&self) -> Result<Self> {
200 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
201 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
202
203 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
204 }
205
206 /// Retrieve the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000207 pub fn device_type(&self) -> Result<Option<&CStr>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100208 self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
209 }
210
211 /// Retrieve the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000212 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
213 let reg = CStr::from_bytes_with_nul(b"reg\0").unwrap();
David Brazdil1baa9a92022-06-28 14:47:50 +0100214
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000215 if let Some(cells) = self.getprop_cells(reg)? {
216 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100217
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000218 let addr_cells = parent.address_cells()?;
219 let size_cells = parent.size_cells()?;
220
221 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
222 } else {
223 Ok(None)
224 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100225 }
226
227 /// Retrieve the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000228 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
229 let value = if let Some(bytes) = self.getprop(name)? {
230 Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?)
231 } else {
232 None
233 };
234 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100235 }
236
237 /// Retrieve the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000238 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
239 if let Some(cells) = self.getprop(name)? {
240 Ok(Some(CellIterator::new(cells)))
241 } else {
242 Ok(None)
243 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100244 }
245
246 /// Retrieve the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000247 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
248 let value = if let Some(bytes) = self.getprop(name)? {
249 Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
250 } else {
251 None
252 };
253 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100254 }
255
256 /// Retrieve the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000257 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
258 let value = if let Some(bytes) = self.getprop(name)? {
259 Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
260 } else {
261 None
262 };
263 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100264 }
265
266 /// Retrieve the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000267 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100268 let mut len: i32 = 0;
269 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
270 // function respects the passed number of characters.
271 let prop = unsafe {
272 libfdt_bindgen::fdt_getprop_namelen(
273 self.fdt.as_ptr(),
274 self.offset,
275 name.as_ptr(),
276 // *_namelen functions don't include the trailing nul terminator in 'len'.
277 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
278 &mut len as *mut i32,
279 )
280 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000281
282 let Some(len) = fdt_err_or_option(len)? else {
283 return Ok(None); // Property was not found.
284 };
285 let len = usize::try_from(len).map_err(|_| FdtError::Internal)?;
286
David Brazdil1baa9a92022-06-28 14:47:50 +0100287 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000288 // We expected an error code in len but still received a valid value?!
289 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100290 }
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000291
292 let offset =
David Brazdil1baa9a92022-06-28 14:47:50 +0100293 (prop as usize).checked_sub(self.fdt.as_ptr() as usize).ok_or(FdtError::Internal)?;
294
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000295 Ok(Some(self.fdt.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)?))
David Brazdil1baa9a92022-06-28 14:47:50 +0100296 }
297
298 /// Get reference to the containing device tree.
299 pub fn fdt(&self) -> &Fdt {
300 self.fdt
301 }
302
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000303 fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
304 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
305 let ret = unsafe {
306 libfdt_bindgen::fdt_node_offset_by_compatible(
307 self.fdt.as_ptr(),
308 self.offset,
309 compatible.as_ptr(),
310 )
311 };
312
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000313 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000314 }
315
David Brazdil1baa9a92022-06-28 14:47:50 +0100316 fn address_cells(&self) -> Result<AddrCells> {
317 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
318 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
319 .try_into()
320 .map_err(|_| FdtError::Internal)
321 }
322
323 fn size_cells(&self) -> Result<SizeCells> {
324 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
325 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
326 .try_into()
327 .map_err(|_| FdtError::Internal)
328 }
329}
330
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000331/// Mutable FDT node.
332pub struct FdtNodeMut<'a> {
333 fdt: &'a mut Fdt,
334 offset: c_int,
335}
336
337impl<'a> FdtNodeMut<'a> {
338 /// Append a property name-value (possibly empty) pair to the given node.
339 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
340 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
341 let ret = unsafe {
342 libfdt_bindgen::fdt_appendprop(
343 self.fdt.as_mut_ptr(),
344 self.offset,
345 name.as_ptr(),
346 value.as_ref().as_ptr().cast::<c_void>(),
347 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
348 )
349 };
350
351 fdt_err_expect_zero(ret)
352 }
353
354 /// Append a (address, size) pair property to the given node.
355 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
356 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
357 let ret = unsafe {
358 libfdt_bindgen::fdt_appendprop_addrrange(
359 self.fdt.as_mut_ptr(),
360 self.parent()?.offset,
361 self.offset,
362 name.as_ptr(),
363 addr,
364 size,
365 )
366 };
367
368 fdt_err_expect_zero(ret)
369 }
370
371 /// Get reference to the containing device tree.
372 pub fn fdt(&mut self) -> &mut Fdt {
373 self.fdt
374 }
375
376 /// Add a new subnode to the given node and return it as a FdtNodeMut on success.
377 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
378 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
379 let ret = unsafe {
380 libfdt_bindgen::fdt_add_subnode(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
381 };
382
383 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
384 }
385
386 fn parent(&'a self) -> Result<FdtNode<'a>> {
387 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
388 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
389
390 Ok(FdtNode { fdt: &*self.fdt, offset: fdt_err(ret)? })
391 }
392}
393
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000394/// Iterator over nodes sharing a same compatible string.
395pub struct CompatibleIterator<'a> {
396 node: FdtNode<'a>,
397 compatible: &'a CStr,
398}
399
400impl<'a> CompatibleIterator<'a> {
401 fn new(fdt: &'a Fdt, compatible: &'a CStr) -> Result<Self> {
402 let node = fdt.root()?;
403 Ok(Self { node, compatible })
404 }
405}
406
407impl<'a> Iterator for CompatibleIterator<'a> {
408 type Item = FdtNode<'a>;
409
410 fn next(&mut self) -> Option<Self::Item> {
411 let next = self.node.next_compatible(self.compatible).ok()?;
412
413 if let Some(node) = next {
414 self.node = node;
415 }
416
417 next
418 }
419}
420
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000421/// Wrapper around low-level libfdt functions.
David Brazdil1baa9a92022-06-28 14:47:50 +0100422#[repr(transparent)]
423pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000424 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100425}
426
427impl Fdt {
428 /// Wraps a slice containing a Flattened Device Tree.
429 ///
430 /// Fails if the FDT does not pass validation.
431 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
432 // SAFETY - The FDT will be validated before it is returned.
433 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
434 fdt.check_full()?;
435 Ok(fdt)
436 }
437
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000438 /// Wraps a mutable slice containing a Flattened Device Tree.
439 ///
440 /// Fails if the FDT does not pass validation.
441 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
442 // SAFETY - The FDT will be validated before it is returned.
443 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
444 fdt.check_full()?;
445 Ok(fdt)
446 }
447
David Brazdil1baa9a92022-06-28 14:47:50 +0100448 /// Wraps a slice containing a Flattened Device Tree.
449 ///
450 /// # Safety
451 ///
452 /// The returned FDT might be invalid, only use on slices containing a valid DT.
453 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
454 mem::transmute::<&[u8], &Self>(fdt)
455 }
456
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000457 /// Wraps a mutable slice containing a Flattened Device Tree.
458 ///
459 /// # Safety
460 ///
461 /// The returned FDT might be invalid, only use on slices containing a valid DT.
462 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
463 mem::transmute::<&mut [u8], &mut Self>(fdt)
464 }
465
466 /// Make the whole slice containing the DT available to libfdt.
467 pub fn unpack(&mut self) -> Result<()> {
468 // SAFETY - "Opens" the DT in-place (supported use-case) by updating its header and
469 // internal structures to make use of the whole self.fdt slice but performs no accesses
470 // outside of it and leaves the DT in a state that will be detected by other functions.
471 let ret = unsafe {
472 libfdt_bindgen::fdt_open_into(
473 self.as_ptr(),
474 self.as_mut_ptr(),
475 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
476 )
477 };
478 fdt_err_expect_zero(ret)
479 }
480
481 /// Pack the DT to take a minimum amount of memory.
482 ///
483 /// Doesn't shrink the underlying memory slice.
484 pub fn pack(&mut self) -> Result<()> {
485 // SAFETY - "Closes" the DT in-place by updating its header and relocating its structs.
486 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
487 fdt_err_expect_zero(ret)
488 }
489
David Brazdil1baa9a92022-06-28 14:47:50 +0100490 /// Return an iterator of memory banks specified the "/memory" node.
491 ///
492 /// NOTE: This does not support individual "/memory@XXXX" banks.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000493 pub fn memory(&self) -> Result<Option<MemRegIterator>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100494 let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
495 let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
496
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000497 if let Some(node) = self.node(memory)? {
498 if node.device_type()? != Some(device_type) {
499 return Err(FdtError::BadValue);
500 }
501 let reg = node.reg()?.ok_or(FdtError::BadValue)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100502
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000503 Ok(Some(MemRegIterator::new(reg)))
504 } else {
505 Ok(None)
506 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100507 }
508
509 /// Retrieve the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000510 pub fn chosen(&self) -> Result<Option<FdtNode>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100511 self.node(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
512 }
513
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000514 /// Get the root node of the tree.
515 pub fn root(&self) -> Result<FdtNode> {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000516 self.node(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000517 }
518
David Brazdil1baa9a92022-06-28 14:47:50 +0100519 /// Find a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000520 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
521 Ok(self.path_offset(path)?.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100522 }
523
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000524 /// Iterate over nodes with a given compatible string.
525 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
526 CompatibleIterator::new(self, compatible)
527 }
528
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000529 /// Get the mutable root node of the tree.
530 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
531 self.node_mut(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
532 }
533
534 /// Find a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000535 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
536 Ok(self.path_offset(path)?.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000537 }
538
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000539 fn path_offset(&self, path: &CStr) -> Result<Option<c_int>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100540 let len = path.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?;
541 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
542 // function respects the passed number of characters.
543 let ret = unsafe {
544 // *_namelen functions don't include the trailing nul terminator in 'len'.
545 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr(), len)
546 };
547
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000548 fdt_err_or_option(ret)
David Brazdil1baa9a92022-06-28 14:47:50 +0100549 }
550
551 fn check_full(&self) -> Result<()> {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000552 let len = self.buffer.len();
David Brazdil1baa9a92022-06-28 14:47:50 +0100553 // SAFETY - Only performs read accesses within the limits of the slice. If successful, this
554 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
555 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
556 // checking. The library doesn't maintain an internal state (such as pointers) between
557 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
558 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), len) };
559 fdt_err_expect_zero(ret)
560 }
561
562 fn as_ptr(&self) -> *const c_void {
563 self as *const _ as *const c_void
564 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000565
566 fn as_mut_ptr(&mut self) -> *mut c_void {
567 self as *mut _ as *mut c_void
568 }
569
570 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000571 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000572 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100573}