blob: 7c72fab3c1eb614892b76aa3aac1b66f8d8bd1c4 [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
Andrew Walbranb39e6922022-12-05 17:01:20 +000023pub use iterators::{AddressRange, CellIterator, MemRegIterator, RangesIterator, Reg, RegIterator};
Andrew Walbran55ad01b2022-12-05 17:00:40 +000024
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.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000151#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100152enum AddrCells {
153 Single = 1,
154 Double = 2,
Andrew Walbranb39e6922022-12-05 17:01:20 +0000155 Triple = 3,
David Brazdil1baa9a92022-06-28 14:47:50 +0100156}
157
158impl TryFrom<c_int> for AddrCells {
159 type Error = FdtError;
160
161 fn try_from(res: c_int) -> Result<Self> {
162 match fdt_err(res)? {
163 x if x == Self::Single as c_int => Ok(Self::Single),
164 x if x == Self::Double as c_int => Ok(Self::Double),
Andrew Walbranb39e6922022-12-05 17:01:20 +0000165 x if x == Self::Triple as c_int => Ok(Self::Triple),
David Brazdil1baa9a92022-06-28 14:47:50 +0100166 _ => Err(FdtError::BadNCells),
167 }
168 }
169}
170
171/// Value of a #size-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000172#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100173enum SizeCells {
174 None = 0,
175 Single = 1,
176 Double = 2,
177}
178
179impl TryFrom<c_int> for SizeCells {
180 type Error = FdtError;
181
182 fn try_from(res: c_int) -> Result<Self> {
183 match fdt_err(res)? {
184 x if x == Self::None as c_int => Ok(Self::None),
185 x if x == Self::Single as c_int => Ok(Self::Single),
186 x if x == Self::Double as c_int => Ok(Self::Double),
187 _ => Err(FdtError::BadNCells),
188 }
189 }
190}
191
David Brazdil1baa9a92022-06-28 14:47:50 +0100192/// DT node.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000193#[derive(Clone, Copy)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100194pub struct FdtNode<'a> {
195 fdt: &'a Fdt,
196 offset: c_int,
197}
198
199impl<'a> FdtNode<'a> {
200 /// Find parent node.
201 pub fn parent(&self) -> Result<Self> {
202 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
203 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
204
205 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
206 }
207
208 /// Retrieve the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000209 pub fn device_type(&self) -> Result<Option<&CStr>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100210 self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
211 }
212
213 /// Retrieve the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000214 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
215 let reg = CStr::from_bytes_with_nul(b"reg\0").unwrap();
David Brazdil1baa9a92022-06-28 14:47:50 +0100216
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000217 if let Some(cells) = self.getprop_cells(reg)? {
218 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100219
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000220 let addr_cells = parent.address_cells()?;
221 let size_cells = parent.size_cells()?;
222
223 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
224 } else {
225 Ok(None)
226 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100227 }
228
Andrew Walbranb39e6922022-12-05 17:01:20 +0000229 /// Retrieves the standard ranges property.
230 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
231 let ranges = CStr::from_bytes_with_nul(b"ranges\0").unwrap();
232 if let Some(cells) = self.getprop_cells(ranges)? {
233 let parent = self.parent()?;
234 let addr_cells = self.address_cells()?;
235 let parent_addr_cells = parent.address_cells()?;
236 let size_cells = self.size_cells()?;
237 Ok(Some(RangesIterator::<A, P, S>::new(
238 cells,
239 addr_cells,
240 parent_addr_cells,
241 size_cells,
242 )))
243 } else {
244 Ok(None)
245 }
246 }
247
David Brazdil1baa9a92022-06-28 14:47:50 +0100248 /// Retrieve the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000249 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
250 let value = if let Some(bytes) = self.getprop(name)? {
251 Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?)
252 } else {
253 None
254 };
255 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100256 }
257
258 /// Retrieve the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000259 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
260 if let Some(cells) = self.getprop(name)? {
261 Ok(Some(CellIterator::new(cells)))
262 } else {
263 Ok(None)
264 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100265 }
266
267 /// Retrieve the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000268 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
269 let value = if let Some(bytes) = self.getprop(name)? {
270 Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
271 } else {
272 None
273 };
274 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100275 }
276
277 /// Retrieve the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000278 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
279 let value = if let Some(bytes) = self.getprop(name)? {
280 Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
281 } else {
282 None
283 };
284 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100285 }
286
287 /// Retrieve the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000288 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100289 let mut len: i32 = 0;
290 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
291 // function respects the passed number of characters.
292 let prop = unsafe {
293 libfdt_bindgen::fdt_getprop_namelen(
294 self.fdt.as_ptr(),
295 self.offset,
296 name.as_ptr(),
297 // *_namelen functions don't include the trailing nul terminator in 'len'.
298 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
299 &mut len as *mut i32,
300 )
301 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000302
303 let Some(len) = fdt_err_or_option(len)? else {
304 return Ok(None); // Property was not found.
305 };
306 let len = usize::try_from(len).map_err(|_| FdtError::Internal)?;
307
David Brazdil1baa9a92022-06-28 14:47:50 +0100308 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000309 // We expected an error code in len but still received a valid value?!
310 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100311 }
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000312
313 let offset =
David Brazdil1baa9a92022-06-28 14:47:50 +0100314 (prop as usize).checked_sub(self.fdt.as_ptr() as usize).ok_or(FdtError::Internal)?;
315
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000316 Ok(Some(self.fdt.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)?))
David Brazdil1baa9a92022-06-28 14:47:50 +0100317 }
318
319 /// Get reference to the containing device tree.
320 pub fn fdt(&self) -> &Fdt {
321 self.fdt
322 }
323
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000324 fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
325 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
326 let ret = unsafe {
327 libfdt_bindgen::fdt_node_offset_by_compatible(
328 self.fdt.as_ptr(),
329 self.offset,
330 compatible.as_ptr(),
331 )
332 };
333
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000334 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000335 }
336
David Brazdil1baa9a92022-06-28 14:47:50 +0100337 fn address_cells(&self) -> Result<AddrCells> {
338 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
339 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
340 .try_into()
341 .map_err(|_| FdtError::Internal)
342 }
343
344 fn size_cells(&self) -> Result<SizeCells> {
345 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
346 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
347 .try_into()
348 .map_err(|_| FdtError::Internal)
349 }
350}
351
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000352/// Mutable FDT node.
353pub struct FdtNodeMut<'a> {
354 fdt: &'a mut Fdt,
355 offset: c_int,
356}
357
358impl<'a> FdtNodeMut<'a> {
359 /// Append a property name-value (possibly empty) pair to the given node.
360 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
361 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
362 let ret = unsafe {
363 libfdt_bindgen::fdt_appendprop(
364 self.fdt.as_mut_ptr(),
365 self.offset,
366 name.as_ptr(),
367 value.as_ref().as_ptr().cast::<c_void>(),
368 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
369 )
370 };
371
372 fdt_err_expect_zero(ret)
373 }
374
375 /// Append a (address, size) pair property to the given node.
376 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
377 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
378 let ret = unsafe {
379 libfdt_bindgen::fdt_appendprop_addrrange(
380 self.fdt.as_mut_ptr(),
381 self.parent()?.offset,
382 self.offset,
383 name.as_ptr(),
384 addr,
385 size,
386 )
387 };
388
389 fdt_err_expect_zero(ret)
390 }
391
392 /// Get reference to the containing device tree.
393 pub fn fdt(&mut self) -> &mut Fdt {
394 self.fdt
395 }
396
397 /// Add a new subnode to the given node and return it as a FdtNodeMut on success.
398 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
399 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
400 let ret = unsafe {
401 libfdt_bindgen::fdt_add_subnode(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
402 };
403
404 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
405 }
406
407 fn parent(&'a self) -> Result<FdtNode<'a>> {
408 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
409 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
410
411 Ok(FdtNode { fdt: &*self.fdt, offset: fdt_err(ret)? })
412 }
413}
414
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000415/// Iterator over nodes sharing a same compatible string.
416pub struct CompatibleIterator<'a> {
417 node: FdtNode<'a>,
418 compatible: &'a CStr,
419}
420
421impl<'a> CompatibleIterator<'a> {
422 fn new(fdt: &'a Fdt, compatible: &'a CStr) -> Result<Self> {
423 let node = fdt.root()?;
424 Ok(Self { node, compatible })
425 }
426}
427
428impl<'a> Iterator for CompatibleIterator<'a> {
429 type Item = FdtNode<'a>;
430
431 fn next(&mut self) -> Option<Self::Item> {
432 let next = self.node.next_compatible(self.compatible).ok()?;
433
434 if let Some(node) = next {
435 self.node = node;
436 }
437
438 next
439 }
440}
441
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000442/// Wrapper around low-level libfdt functions.
David Brazdil1baa9a92022-06-28 14:47:50 +0100443#[repr(transparent)]
444pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000445 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100446}
447
448impl Fdt {
449 /// Wraps a slice containing a Flattened Device Tree.
450 ///
451 /// Fails if the FDT does not pass validation.
452 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
453 // SAFETY - The FDT will be validated before it is returned.
454 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
455 fdt.check_full()?;
456 Ok(fdt)
457 }
458
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000459 /// Wraps a mutable slice containing a Flattened Device Tree.
460 ///
461 /// Fails if the FDT does not pass validation.
462 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
463 // SAFETY - The FDT will be validated before it is returned.
464 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
465 fdt.check_full()?;
466 Ok(fdt)
467 }
468
David Brazdil1baa9a92022-06-28 14:47:50 +0100469 /// Wraps a slice containing a Flattened Device Tree.
470 ///
471 /// # Safety
472 ///
473 /// The returned FDT might be invalid, only use on slices containing a valid DT.
474 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
475 mem::transmute::<&[u8], &Self>(fdt)
476 }
477
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000478 /// Wraps a mutable slice containing a Flattened Device Tree.
479 ///
480 /// # Safety
481 ///
482 /// The returned FDT might be invalid, only use on slices containing a valid DT.
483 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
484 mem::transmute::<&mut [u8], &mut Self>(fdt)
485 }
486
487 /// Make the whole slice containing the DT available to libfdt.
488 pub fn unpack(&mut self) -> Result<()> {
489 // SAFETY - "Opens" the DT in-place (supported use-case) by updating its header and
490 // internal structures to make use of the whole self.fdt slice but performs no accesses
491 // outside of it and leaves the DT in a state that will be detected by other functions.
492 let ret = unsafe {
493 libfdt_bindgen::fdt_open_into(
494 self.as_ptr(),
495 self.as_mut_ptr(),
496 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
497 )
498 };
499 fdt_err_expect_zero(ret)
500 }
501
502 /// Pack the DT to take a minimum amount of memory.
503 ///
504 /// Doesn't shrink the underlying memory slice.
505 pub fn pack(&mut self) -> Result<()> {
506 // SAFETY - "Closes" the DT in-place by updating its header and relocating its structs.
507 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
508 fdt_err_expect_zero(ret)
509 }
510
David Brazdil1baa9a92022-06-28 14:47:50 +0100511 /// Return an iterator of memory banks specified the "/memory" node.
512 ///
513 /// NOTE: This does not support individual "/memory@XXXX" banks.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000514 pub fn memory(&self) -> Result<Option<MemRegIterator>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100515 let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
516 let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
517
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000518 if let Some(node) = self.node(memory)? {
519 if node.device_type()? != Some(device_type) {
520 return Err(FdtError::BadValue);
521 }
522 let reg = node.reg()?.ok_or(FdtError::BadValue)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100523
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000524 Ok(Some(MemRegIterator::new(reg)))
525 } else {
526 Ok(None)
527 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100528 }
529
530 /// Retrieve the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000531 pub fn chosen(&self) -> Result<Option<FdtNode>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100532 self.node(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
533 }
534
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000535 /// Get the root node of the tree.
536 pub fn root(&self) -> Result<FdtNode> {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000537 self.node(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000538 }
539
David Brazdil1baa9a92022-06-28 14:47:50 +0100540 /// Find a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000541 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
542 Ok(self.path_offset(path)?.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100543 }
544
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000545 /// Iterate over nodes with a given compatible string.
546 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
547 CompatibleIterator::new(self, compatible)
548 }
549
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000550 /// Get the mutable root node of the tree.
551 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
552 self.node_mut(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
553 }
554
555 /// Find a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000556 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
557 Ok(self.path_offset(path)?.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000558 }
559
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000560 /// Return the device tree as a slice (may be smaller than the containing buffer).
561 pub fn as_slice(&self) -> &[u8] {
562 &self.buffer[..self.totalsize()]
563 }
564
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000565 fn path_offset(&self, path: &CStr) -> Result<Option<c_int>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100566 let len = path.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?;
567 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
568 // function respects the passed number of characters.
569 let ret = unsafe {
570 // *_namelen functions don't include the trailing nul terminator in 'len'.
571 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr(), len)
572 };
573
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000574 fdt_err_or_option(ret)
David Brazdil1baa9a92022-06-28 14:47:50 +0100575 }
576
577 fn check_full(&self) -> Result<()> {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000578 let len = self.buffer.len();
David Brazdil1baa9a92022-06-28 14:47:50 +0100579 // SAFETY - Only performs read accesses within the limits of the slice. If successful, this
580 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
581 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
582 // checking. The library doesn't maintain an internal state (such as pointers) between
583 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
584 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), len) };
585 fdt_err_expect_zero(ret)
586 }
587
588 fn as_ptr(&self) -> *const c_void {
589 self as *const _ as *const c_void
590 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000591
592 fn as_mut_ptr(&mut self) -> *mut c_void {
593 self as *mut _ as *mut c_void
594 }
595
596 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000597 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000598 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000599
600 fn header(&self) -> &libfdt_bindgen::fdt_header {
601 // SAFETY - A valid FDT (verified by constructor) must contain a valid fdt_header.
602 unsafe { &*(&self as *const _ as *const libfdt_bindgen::fdt_header) }
603 }
604
605 fn totalsize(&self) -> usize {
606 u32::from_be(self.header().totalsize) as usize
607 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100608}