blob: c38381b5e4d7f589b7be2be7d033d4ed124b7bd8 [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
20use core::ffi::{c_int, c_void, CStr};
21use core::fmt;
22use core::mem;
23use core::ops::Range;
24use core::result;
25use core::slice;
26
27/// Error type corresponding to libfdt error codes.
28#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29pub enum FdtError {
30 /// FDT_ERR_NOTFOUND
31 NotFound,
32 /// FDT_ERR_EXISTS
33 Exists,
34 /// FDT_ERR_NOSPACE
35 NoSpace,
36 /// FDT_ERR_BADOFFSET
37 BadOffset,
38 /// FDT_ERR_BADPATH
39 BadPath,
40 /// FDT_ERR_BADPHANDLE
41 BadPhandle,
42 /// FDT_ERR_BADSTATE
43 BadState,
44 /// FDT_ERR_TRUNCATED
45 Truncated,
46 /// FDT_ERR_BADMAGIC
47 BadMagic,
48 /// FDT_ERR_BADVERSION
49 BadVersion,
50 /// FDT_ERR_BADSTRUCTURE
51 BadStructure,
52 /// FDT_ERR_BADLAYOUT
53 BadLayout,
54 /// FDT_ERR_INTERNAL
55 Internal,
56 /// FDT_ERR_BADNCELLS
57 BadNCells,
58 /// FDT_ERR_BADVALUE
59 BadValue,
60 /// FDT_ERR_BADOVERLAY
61 BadOverlay,
62 /// FDT_ERR_NOPHANDLES
63 NoPhandles,
64 /// FDT_ERR_BADFLAGS
65 BadFlags,
66 /// FDT_ERR_ALIGNMENT
67 Alignment,
68 /// Unexpected error code
69 Unknown(i32),
70}
71
72impl fmt::Display for FdtError {
73 /// Prints error messages from libfdt.h documentation.
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 match self {
76 Self::NotFound => write!(f, "The requested node or property does not exist"),
77 Self::Exists => write!(f, "Attempted to create an existing node or property"),
78 Self::NoSpace => write!(f, "Insufficient buffer space to contain the expanded tree"),
79 Self::BadOffset => write!(f, "Structure block offset is out-of-bounds or invalid"),
80 Self::BadPath => write!(f, "Badly formatted path"),
81 Self::BadPhandle => write!(f, "Invalid phandle length or value"),
82 Self::BadState => write!(f, "Received incomplete device tree"),
83 Self::Truncated => write!(f, "Device tree or sub-block is improperly terminated"),
84 Self::BadMagic => write!(f, "Device tree header missing its magic number"),
85 Self::BadVersion => write!(f, "Device tree has a version which can't be handled"),
86 Self::BadStructure => write!(f, "Device tree has a corrupt structure block"),
87 Self::BadLayout => write!(f, "Device tree sub-blocks in unsupported order"),
88 Self::Internal => write!(f, "libfdt has failed an internal assertion"),
89 Self::BadNCells => write!(f, "Bad format or value of #address-cells or #size-cells"),
90 Self::BadValue => write!(f, "Unexpected property value"),
91 Self::BadOverlay => write!(f, "Overlay cannot be applied"),
92 Self::NoPhandles => write!(f, "Device tree doesn't have any phandle available anymore"),
93 Self::BadFlags => write!(f, "Invalid flag or invalid combination of flags"),
94 Self::Alignment => write!(f, "Device tree base address is not 8-byte aligned"),
95 Self::Unknown(e) => write!(f, "Unknown libfdt error '{e}'"),
96 }
97 }
98}
99
100/// Result type with FdtError enum.
101pub type Result<T> = result::Result<T, FdtError>;
102
103fn fdt_err(val: c_int) -> Result<c_int> {
104 if val >= 0 {
105 Ok(val)
106 } else {
107 Err(match -val as _ {
108 libfdt_bindgen::FDT_ERR_NOTFOUND => FdtError::NotFound,
109 libfdt_bindgen::FDT_ERR_EXISTS => FdtError::Exists,
110 libfdt_bindgen::FDT_ERR_NOSPACE => FdtError::NoSpace,
111 libfdt_bindgen::FDT_ERR_BADOFFSET => FdtError::BadOffset,
112 libfdt_bindgen::FDT_ERR_BADPATH => FdtError::BadPath,
113 libfdt_bindgen::FDT_ERR_BADPHANDLE => FdtError::BadPhandle,
114 libfdt_bindgen::FDT_ERR_BADSTATE => FdtError::BadState,
115 libfdt_bindgen::FDT_ERR_TRUNCATED => FdtError::Truncated,
116 libfdt_bindgen::FDT_ERR_BADMAGIC => FdtError::BadMagic,
117 libfdt_bindgen::FDT_ERR_BADVERSION => FdtError::BadVersion,
118 libfdt_bindgen::FDT_ERR_BADSTRUCTURE => FdtError::BadStructure,
119 libfdt_bindgen::FDT_ERR_BADLAYOUT => FdtError::BadLayout,
120 libfdt_bindgen::FDT_ERR_INTERNAL => FdtError::Internal,
121 libfdt_bindgen::FDT_ERR_BADNCELLS => FdtError::BadNCells,
122 libfdt_bindgen::FDT_ERR_BADVALUE => FdtError::BadValue,
123 libfdt_bindgen::FDT_ERR_BADOVERLAY => FdtError::BadOverlay,
124 libfdt_bindgen::FDT_ERR_NOPHANDLES => FdtError::NoPhandles,
125 libfdt_bindgen::FDT_ERR_BADFLAGS => FdtError::BadFlags,
126 libfdt_bindgen::FDT_ERR_ALIGNMENT => FdtError::Alignment,
127 _ => FdtError::Unknown(val),
128 })
129 }
130}
131
132fn fdt_err_expect_zero(val: c_int) -> Result<()> {
133 match fdt_err(val)? {
134 0 => Ok(()),
135 _ => Err(FdtError::Unknown(val)),
136 }
137}
138
139/// Value of a #address-cells property.
140#[derive(Copy, Clone, Debug)]
141enum AddrCells {
142 Single = 1,
143 Double = 2,
144}
145
146impl TryFrom<c_int> for AddrCells {
147 type Error = FdtError;
148
149 fn try_from(res: c_int) -> Result<Self> {
150 match fdt_err(res)? {
151 x if x == Self::Single as c_int => Ok(Self::Single),
152 x if x == Self::Double as c_int => Ok(Self::Double),
153 _ => Err(FdtError::BadNCells),
154 }
155 }
156}
157
158/// Value of a #size-cells property.
159#[derive(Copy, Clone, Debug)]
160enum SizeCells {
161 None = 0,
162 Single = 1,
163 Double = 2,
164}
165
166impl TryFrom<c_int> for SizeCells {
167 type Error = FdtError;
168
169 fn try_from(res: c_int) -> Result<Self> {
170 match fdt_err(res)? {
171 x if x == Self::None as c_int => Ok(Self::None),
172 x if x == Self::Single as c_int => Ok(Self::Single),
173 x if x == Self::Double as c_int => Ok(Self::Double),
174 _ => Err(FdtError::BadNCells),
175 }
176 }
177}
178
179/// Iterator over cells of a DT property.
180#[derive(Debug)]
181pub struct CellIterator<'a> {
182 chunks: slice::ChunksExact<'a, u8>,
183}
184
185impl<'a> CellIterator<'a> {
186 fn new(bytes: &'a [u8]) -> Self {
187 const CHUNK_SIZE: usize = mem::size_of::<<CellIterator as Iterator>::Item>();
188
189 Self { chunks: bytes.chunks_exact(CHUNK_SIZE) }
190 }
191}
192
193impl<'a> Iterator for CellIterator<'a> {
194 type Item = u32;
195
196 fn next(&mut self) -> Option<Self::Item> {
197 Some(Self::Item::from_be_bytes(self.chunks.next()?.try_into().ok()?))
198 }
199}
200
201/// Iterator over a 'reg' property of a DT node.
202#[derive(Debug)]
203pub struct RegIterator<'a> {
204 cells: CellIterator<'a>,
205 addr_cells: AddrCells,
206 size_cells: SizeCells,
207}
208
209/// Represents a contiguous region within the address space defined by the parent bus.
210/// Commonly means the offsets and lengths of MMIO blocks, but may have a different meaning on some
211/// bus types. Addresses in the address space defined by the root node are CPU real addresses.
212#[derive(Copy, Clone, Debug)]
213pub struct Reg<T> {
214 /// Base address of the region.
215 pub addr: T,
216 /// Size of the region (optional).
217 pub size: Option<T>,
218}
219
220impl<'a> RegIterator<'a> {
221 fn new(cells: CellIterator<'a>, addr_cells: AddrCells, size_cells: SizeCells) -> Self {
222 Self { cells, addr_cells, size_cells }
223 }
224}
225
226impl<'a> Iterator for RegIterator<'a> {
227 type Item = Reg<u64>;
228
229 fn next(&mut self) -> Option<Self::Item> {
230 let make_double = |a, b| (u64::from(a) << 32) | u64::from(b);
231
232 let addr = match self.addr_cells {
233 AddrCells::Single => self.cells.next()?.into(),
234 AddrCells::Double => make_double(self.cells.next()?, self.cells.next()?),
235 };
236 // If the parent node specifies a value of 0 for #size-cells, 'size' shall be omitted.
237 let size = match self.size_cells {
238 SizeCells::None => None,
239 SizeCells::Single => Some(self.cells.next()?.into()),
240 SizeCells::Double => Some(make_double(self.cells.next()?, self.cells.next()?)),
241 };
242
243 Some(Self::Item { addr, size })
244 }
245}
246
247/// Iterator over the address ranges defined by the /memory/ node.
248#[derive(Debug)]
249pub struct MemRegIterator<'a> {
250 reg: RegIterator<'a>,
251}
252
253impl<'a> MemRegIterator<'a> {
254 fn new(reg: RegIterator<'a>) -> Result<Self> {
255 Ok(Self { reg })
256 }
257}
258
259impl<'a> Iterator for MemRegIterator<'a> {
260 type Item = Range<usize>;
261
262 fn next(&mut self) -> Option<Self::Item> {
263 let next = self.reg.next()?;
264 let addr = usize::try_from(next.addr).ok()?;
265 let size = usize::try_from(next.size?).ok()?;
266
267 Some(addr..addr.checked_add(size)?)
268 }
269}
270
271/// DT node.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000272#[derive(Clone, Copy)]
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> {
279 /// Find parent node.
280 pub fn parent(&self) -> Result<Self> {
281 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
282 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
287 /// Retrieve the standard (deprecated) device_type <string> property.
288 pub fn device_type(&self) -> Result<&CStr> {
289 self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
290 }
291
292 /// Retrieve the standard reg <prop-encoded-array> property.
293 pub fn reg(&self) -> Result<RegIterator<'a>> {
294 let parent = self.parent()?;
295
296 let addr_cells = parent.address_cells()?;
297 let size_cells = parent.size_cells()?;
298 let cells = self.getprop_cells(CStr::from_bytes_with_nul(b"reg\0").unwrap())?;
299
300 Ok(RegIterator::new(cells, addr_cells, size_cells))
301 }
302
303 /// Retrieve the value of a given <string> property.
304 pub fn getprop_str(&self, name: &CStr) -> Result<&CStr> {
305 CStr::from_bytes_with_nul(self.getprop(name)?).map_err(|_| FdtError::BadValue)
306 }
307
308 /// Retrieve the value of a given property as an array of cells.
309 pub fn getprop_cells(&self, name: &CStr) -> Result<CellIterator<'a>> {
310 Ok(CellIterator::new(self.getprop(name)?))
311 }
312
313 /// Retrieve the value of a given <u32> property.
314 pub fn getprop_u32(&self, name: &CStr) -> Result<u32> {
315 let prop = self.getprop(name)?.try_into().map_err(|_| FdtError::BadValue)?;
316 Ok(u32::from_be_bytes(prop))
317 }
318
319 /// Retrieve the value of a given <u64> property.
320 pub fn getprop_u64(&self, name: &CStr) -> Result<u64> {
321 let prop = self.getprop(name)?.try_into().map_err(|_| FdtError::BadValue)?;
322 Ok(u64::from_be_bytes(prop))
323 }
324
325 /// Retrieve the value of a given property.
326 pub fn getprop(&self, name: &CStr) -> Result<&'a [u8]> {
327 let mut len: i32 = 0;
328 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
329 // function respects the passed number of characters.
330 let prop = unsafe {
331 libfdt_bindgen::fdt_getprop_namelen(
332 self.fdt.as_ptr(),
333 self.offset,
334 name.as_ptr(),
335 // *_namelen functions don't include the trailing nul terminator in 'len'.
336 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
337 &mut len as *mut i32,
338 )
339 } as *const u8;
340 if prop.is_null() {
341 return fdt_err(len).and(Err(FdtError::Internal));
342 }
343 let len = usize::try_from(fdt_err(len)?).map_err(|_| FdtError::Internal)?;
344 let base =
345 (prop as usize).checked_sub(self.fdt.as_ptr() as usize).ok_or(FdtError::Internal)?;
346
347 self.fdt.bytes.get(base..(base + len)).ok_or(FdtError::Internal)
348 }
349
350 /// Get reference to the containing device tree.
351 pub fn fdt(&self) -> &Fdt {
352 self.fdt
353 }
354
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000355 fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
356 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
357 let ret = unsafe {
358 libfdt_bindgen::fdt_node_offset_by_compatible(
359 self.fdt.as_ptr(),
360 self.offset,
361 compatible.as_ptr(),
362 )
363 };
364
365 match fdt_err(ret) {
366 Ok(offset) => Ok(Some(Self { fdt: self.fdt, offset })),
367 Err(FdtError::NotFound) => Ok(None),
368 Err(e) => Err(e),
369 }
370 }
371
David Brazdil1baa9a92022-06-28 14:47:50 +0100372 fn address_cells(&self) -> Result<AddrCells> {
373 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
374 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
375 .try_into()
376 .map_err(|_| FdtError::Internal)
377 }
378
379 fn size_cells(&self) -> Result<SizeCells> {
380 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
381 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
382 .try_into()
383 .map_err(|_| FdtError::Internal)
384 }
385}
386
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000387/// Mutable FDT node.
388pub struct FdtNodeMut<'a> {
389 fdt: &'a mut Fdt,
390 offset: c_int,
391}
392
393impl<'a> FdtNodeMut<'a> {
394 /// Append a property name-value (possibly empty) pair to the given node.
395 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
396 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
397 let ret = unsafe {
398 libfdt_bindgen::fdt_appendprop(
399 self.fdt.as_mut_ptr(),
400 self.offset,
401 name.as_ptr(),
402 value.as_ref().as_ptr().cast::<c_void>(),
403 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
404 )
405 };
406
407 fdt_err_expect_zero(ret)
408 }
409
410 /// Append a (address, size) pair property to the given node.
411 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
412 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
413 let ret = unsafe {
414 libfdt_bindgen::fdt_appendprop_addrrange(
415 self.fdt.as_mut_ptr(),
416 self.parent()?.offset,
417 self.offset,
418 name.as_ptr(),
419 addr,
420 size,
421 )
422 };
423
424 fdt_err_expect_zero(ret)
425 }
426
427 /// Get reference to the containing device tree.
428 pub fn fdt(&mut self) -> &mut Fdt {
429 self.fdt
430 }
431
432 /// Add a new subnode to the given node and return it as a FdtNodeMut on success.
433 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
434 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
435 let ret = unsafe {
436 libfdt_bindgen::fdt_add_subnode(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
437 };
438
439 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
440 }
441
442 fn parent(&'a self) -> Result<FdtNode<'a>> {
443 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
444 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
445
446 Ok(FdtNode { fdt: &*self.fdt, offset: fdt_err(ret)? })
447 }
448}
449
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000450/// Iterator over nodes sharing a same compatible string.
451pub struct CompatibleIterator<'a> {
452 node: FdtNode<'a>,
453 compatible: &'a CStr,
454}
455
456impl<'a> CompatibleIterator<'a> {
457 fn new(fdt: &'a Fdt, compatible: &'a CStr) -> Result<Self> {
458 let node = fdt.root()?;
459 Ok(Self { node, compatible })
460 }
461}
462
463impl<'a> Iterator for CompatibleIterator<'a> {
464 type Item = FdtNode<'a>;
465
466 fn next(&mut self) -> Option<Self::Item> {
467 let next = self.node.next_compatible(self.compatible).ok()?;
468
469 if let Some(node) = next {
470 self.node = node;
471 }
472
473 next
474 }
475}
476
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000477/// Wrapper around low-level libfdt functions.
David Brazdil1baa9a92022-06-28 14:47:50 +0100478#[repr(transparent)]
479pub struct Fdt {
480 bytes: [u8],
481}
482
483impl Fdt {
484 /// Wraps a slice containing a Flattened Device Tree.
485 ///
486 /// Fails if the FDT does not pass validation.
487 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
488 // SAFETY - The FDT will be validated before it is returned.
489 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
490 fdt.check_full()?;
491 Ok(fdt)
492 }
493
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000494 /// Wraps a mutable slice containing a Flattened Device Tree.
495 ///
496 /// Fails if the FDT does not pass validation.
497 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
498 // SAFETY - The FDT will be validated before it is returned.
499 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
500 fdt.check_full()?;
501 Ok(fdt)
502 }
503
David Brazdil1baa9a92022-06-28 14:47:50 +0100504 /// Wraps a slice containing a Flattened Device Tree.
505 ///
506 /// # Safety
507 ///
508 /// The returned FDT might be invalid, only use on slices containing a valid DT.
509 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
510 mem::transmute::<&[u8], &Self>(fdt)
511 }
512
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000513 /// Wraps a mutable slice containing a Flattened Device Tree.
514 ///
515 /// # Safety
516 ///
517 /// The returned FDT might be invalid, only use on slices containing a valid DT.
518 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
519 mem::transmute::<&mut [u8], &mut Self>(fdt)
520 }
521
522 /// Make the whole slice containing the DT available to libfdt.
523 pub fn unpack(&mut self) -> Result<()> {
524 // SAFETY - "Opens" the DT in-place (supported use-case) by updating its header and
525 // internal structures to make use of the whole self.fdt slice but performs no accesses
526 // outside of it and leaves the DT in a state that will be detected by other functions.
527 let ret = unsafe {
528 libfdt_bindgen::fdt_open_into(
529 self.as_ptr(),
530 self.as_mut_ptr(),
531 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
532 )
533 };
534 fdt_err_expect_zero(ret)
535 }
536
537 /// Pack the DT to take a minimum amount of memory.
538 ///
539 /// Doesn't shrink the underlying memory slice.
540 pub fn pack(&mut self) -> Result<()> {
541 // SAFETY - "Closes" the DT in-place by updating its header and relocating its structs.
542 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
543 fdt_err_expect_zero(ret)
544 }
545
David Brazdil1baa9a92022-06-28 14:47:50 +0100546 /// Return an iterator of memory banks specified the "/memory" node.
547 ///
548 /// NOTE: This does not support individual "/memory@XXXX" banks.
549 pub fn memory(&self) -> Result<MemRegIterator> {
550 let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
551 let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
552
553 let node = self.node(memory)?;
554 if node.device_type()? != device_type {
555 return Err(FdtError::BadValue);
556 }
557
558 MemRegIterator::new(node.reg()?)
559 }
560
561 /// Retrieve the standard /chosen node.
562 pub fn chosen(&self) -> Result<FdtNode> {
563 self.node(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
564 }
565
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000566 /// Get the root node of the tree.
567 pub fn root(&self) -> Result<FdtNode> {
568 self.node(CStr::from_bytes_with_nul(b"/\0").unwrap())
569 }
570
David Brazdil1baa9a92022-06-28 14:47:50 +0100571 /// Find a tree node by its full path.
572 pub fn node(&self, path: &CStr) -> Result<FdtNode> {
573 let offset = self.path_offset(path)?;
574 Ok(FdtNode { fdt: self, offset })
575 }
576
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000577 /// Iterate over nodes with a given compatible string.
578 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
579 CompatibleIterator::new(self, compatible)
580 }
581
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000582 /// Get the mutable root node of the tree.
583 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
584 self.node_mut(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
585 }
586
587 /// Find a mutable tree node by its full path.
588 pub fn node_mut(&mut self, path: &CStr) -> Result<FdtNodeMut> {
589 let offset = self.path_offset(path)?;
590 Ok(FdtNodeMut { fdt: self, offset })
591 }
592
David Brazdil1baa9a92022-06-28 14:47:50 +0100593 fn path_offset(&self, path: &CStr) -> Result<c_int> {
594 let len = path.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?;
595 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
596 // function respects the passed number of characters.
597 let ret = unsafe {
598 // *_namelen functions don't include the trailing nul terminator in 'len'.
599 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr(), len)
600 };
601
602 fdt_err(ret)
603 }
604
605 fn check_full(&self) -> Result<()> {
606 let len = self.bytes.len();
607 // SAFETY - Only performs read accesses within the limits of the slice. If successful, this
608 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
609 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
610 // checking. The library doesn't maintain an internal state (such as pointers) between
611 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
612 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), len) };
613 fdt_err_expect_zero(ret)
614 }
615
616 fn as_ptr(&self) -> *const c_void {
617 self as *const _ as *const c_void
618 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000619
620 fn as_mut_ptr(&mut self) -> *mut c_void {
621 self as *mut _ as *mut c_void
622 }
623
624 fn capacity(&self) -> usize {
625 self.bytes.len()
626 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100627}