blob: a1a740b6143949dce9900e58d32996ea0947228d [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
Andrew Walbranb39e6922022-12-05 17:01:20 +000022pub use iterators::{AddressRange, CellIterator, MemRegIterator, RangesIterator, Reg, RegIterator};
Andrew Walbran55ad01b2022-12-05 17:00:40 +000023
David Brazdil1baa9a92022-06-28 14:47:50 +010024use core::ffi::{c_int, c_void, CStr};
25use core::fmt;
26use core::mem;
David Brazdil1baa9a92022-06-28 14:47:50 +010027use core::result;
David Brazdil1baa9a92022-06-28 14:47:50 +010028
29/// Error type corresponding to libfdt error codes.
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
31pub enum FdtError {
32 /// FDT_ERR_NOTFOUND
33 NotFound,
34 /// FDT_ERR_EXISTS
35 Exists,
36 /// FDT_ERR_NOSPACE
37 NoSpace,
38 /// FDT_ERR_BADOFFSET
39 BadOffset,
40 /// FDT_ERR_BADPATH
41 BadPath,
42 /// FDT_ERR_BADPHANDLE
43 BadPhandle,
44 /// FDT_ERR_BADSTATE
45 BadState,
46 /// FDT_ERR_TRUNCATED
47 Truncated,
48 /// FDT_ERR_BADMAGIC
49 BadMagic,
50 /// FDT_ERR_BADVERSION
51 BadVersion,
52 /// FDT_ERR_BADSTRUCTURE
53 BadStructure,
54 /// FDT_ERR_BADLAYOUT
55 BadLayout,
56 /// FDT_ERR_INTERNAL
57 Internal,
58 /// FDT_ERR_BADNCELLS
59 BadNCells,
60 /// FDT_ERR_BADVALUE
61 BadValue,
62 /// FDT_ERR_BADOVERLAY
63 BadOverlay,
64 /// FDT_ERR_NOPHANDLES
65 NoPhandles,
66 /// FDT_ERR_BADFLAGS
67 BadFlags,
68 /// FDT_ERR_ALIGNMENT
69 Alignment,
70 /// Unexpected error code
71 Unknown(i32),
72}
73
74impl fmt::Display for FdtError {
75 /// Prints error messages from libfdt.h documentation.
76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77 match self {
78 Self::NotFound => write!(f, "The requested node or property does not exist"),
79 Self::Exists => write!(f, "Attempted to create an existing node or property"),
80 Self::NoSpace => write!(f, "Insufficient buffer space to contain the expanded tree"),
81 Self::BadOffset => write!(f, "Structure block offset is out-of-bounds or invalid"),
82 Self::BadPath => write!(f, "Badly formatted path"),
83 Self::BadPhandle => write!(f, "Invalid phandle length or value"),
84 Self::BadState => write!(f, "Received incomplete device tree"),
85 Self::Truncated => write!(f, "Device tree or sub-block is improperly terminated"),
86 Self::BadMagic => write!(f, "Device tree header missing its magic number"),
87 Self::BadVersion => write!(f, "Device tree has a version which can't be handled"),
88 Self::BadStructure => write!(f, "Device tree has a corrupt structure block"),
89 Self::BadLayout => write!(f, "Device tree sub-blocks in unsupported order"),
90 Self::Internal => write!(f, "libfdt has failed an internal assertion"),
91 Self::BadNCells => write!(f, "Bad format or value of #address-cells or #size-cells"),
92 Self::BadValue => write!(f, "Unexpected property value"),
93 Self::BadOverlay => write!(f, "Overlay cannot be applied"),
94 Self::NoPhandles => write!(f, "Device tree doesn't have any phandle available anymore"),
95 Self::BadFlags => write!(f, "Invalid flag or invalid combination of flags"),
96 Self::Alignment => write!(f, "Device tree base address is not 8-byte aligned"),
97 Self::Unknown(e) => write!(f, "Unknown libfdt error '{e}'"),
98 }
99 }
100}
101
102/// Result type with FdtError enum.
103pub type Result<T> = result::Result<T, FdtError>;
104
105fn fdt_err(val: c_int) -> Result<c_int> {
106 if val >= 0 {
107 Ok(val)
108 } else {
109 Err(match -val as _ {
110 libfdt_bindgen::FDT_ERR_NOTFOUND => FdtError::NotFound,
111 libfdt_bindgen::FDT_ERR_EXISTS => FdtError::Exists,
112 libfdt_bindgen::FDT_ERR_NOSPACE => FdtError::NoSpace,
113 libfdt_bindgen::FDT_ERR_BADOFFSET => FdtError::BadOffset,
114 libfdt_bindgen::FDT_ERR_BADPATH => FdtError::BadPath,
115 libfdt_bindgen::FDT_ERR_BADPHANDLE => FdtError::BadPhandle,
116 libfdt_bindgen::FDT_ERR_BADSTATE => FdtError::BadState,
117 libfdt_bindgen::FDT_ERR_TRUNCATED => FdtError::Truncated,
118 libfdt_bindgen::FDT_ERR_BADMAGIC => FdtError::BadMagic,
119 libfdt_bindgen::FDT_ERR_BADVERSION => FdtError::BadVersion,
120 libfdt_bindgen::FDT_ERR_BADSTRUCTURE => FdtError::BadStructure,
121 libfdt_bindgen::FDT_ERR_BADLAYOUT => FdtError::BadLayout,
122 libfdt_bindgen::FDT_ERR_INTERNAL => FdtError::Internal,
123 libfdt_bindgen::FDT_ERR_BADNCELLS => FdtError::BadNCells,
124 libfdt_bindgen::FDT_ERR_BADVALUE => FdtError::BadValue,
125 libfdt_bindgen::FDT_ERR_BADOVERLAY => FdtError::BadOverlay,
126 libfdt_bindgen::FDT_ERR_NOPHANDLES => FdtError::NoPhandles,
127 libfdt_bindgen::FDT_ERR_BADFLAGS => FdtError::BadFlags,
128 libfdt_bindgen::FDT_ERR_ALIGNMENT => FdtError::Alignment,
129 _ => FdtError::Unknown(val),
130 })
131 }
132}
133
134fn fdt_err_expect_zero(val: c_int) -> Result<()> {
135 match fdt_err(val)? {
136 0 => Ok(()),
137 _ => Err(FdtError::Unknown(val)),
138 }
139}
140
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000141fn fdt_err_or_option(val: c_int) -> Result<Option<c_int>> {
142 match fdt_err(val) {
143 Ok(val) => Ok(Some(val)),
144 Err(FdtError::NotFound) => Ok(None),
145 Err(e) => Err(e),
146 }
147}
148
David Brazdil1baa9a92022-06-28 14:47:50 +0100149/// Value of a #address-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000150#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100151enum AddrCells {
152 Single = 1,
153 Double = 2,
Andrew Walbranb39e6922022-12-05 17:01:20 +0000154 Triple = 3,
David Brazdil1baa9a92022-06-28 14:47:50 +0100155}
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),
Andrew Walbranb39e6922022-12-05 17:01:20 +0000164 x if x == Self::Triple as c_int => Ok(Self::Triple),
David Brazdil1baa9a92022-06-28 14:47:50 +0100165 _ => Err(FdtError::BadNCells),
166 }
167 }
168}
169
170/// Value of a #size-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000171#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100172enum SizeCells {
173 None = 0,
174 Single = 1,
175 Double = 2,
176}
177
178impl TryFrom<c_int> for SizeCells {
179 type Error = FdtError;
180
181 fn try_from(res: c_int) -> Result<Self> {
182 match fdt_err(res)? {
183 x if x == Self::None as c_int => Ok(Self::None),
184 x if x == Self::Single as c_int => Ok(Self::Single),
185 x if x == Self::Double as c_int => Ok(Self::Double),
186 _ => Err(FdtError::BadNCells),
187 }
188 }
189}
190
David Brazdil1baa9a92022-06-28 14:47:50 +0100191/// DT node.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000192#[derive(Clone, Copy)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100193pub struct FdtNode<'a> {
194 fdt: &'a Fdt,
195 offset: c_int,
196}
197
198impl<'a> FdtNode<'a> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900199 /// Create immutable node from a mutable node at the same offset
200 pub fn from_mut(other: &'a FdtNodeMut) -> Self {
201 FdtNode { fdt: other.fdt, offset: other.offset }
202 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100203 /// Find parent node.
204 pub fn parent(&self) -> Result<Self> {
205 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
206 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
207
208 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
209 }
210
211 /// Retrieve the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000212 pub fn device_type(&self) -> Result<Option<&CStr>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100213 self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
214 }
215
216 /// Retrieve the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000217 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
218 let reg = CStr::from_bytes_with_nul(b"reg\0").unwrap();
David Brazdil1baa9a92022-06-28 14:47:50 +0100219
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000220 if let Some(cells) = self.getprop_cells(reg)? {
221 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100222
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000223 let addr_cells = parent.address_cells()?;
224 let size_cells = parent.size_cells()?;
225
226 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
227 } else {
228 Ok(None)
229 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100230 }
231
Andrew Walbranb39e6922022-12-05 17:01:20 +0000232 /// Retrieves the standard ranges property.
233 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
234 let ranges = CStr::from_bytes_with_nul(b"ranges\0").unwrap();
235 if let Some(cells) = self.getprop_cells(ranges)? {
236 let parent = self.parent()?;
237 let addr_cells = self.address_cells()?;
238 let parent_addr_cells = parent.address_cells()?;
239 let size_cells = self.size_cells()?;
240 Ok(Some(RangesIterator::<A, P, S>::new(
241 cells,
242 addr_cells,
243 parent_addr_cells,
244 size_cells,
245 )))
246 } else {
247 Ok(None)
248 }
249 }
250
David Brazdil1baa9a92022-06-28 14:47:50 +0100251 /// Retrieve the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000252 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
253 let value = if let Some(bytes) = self.getprop(name)? {
254 Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?)
255 } else {
256 None
257 };
258 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100259 }
260
261 /// Retrieve the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000262 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
263 if let Some(cells) = self.getprop(name)? {
264 Ok(Some(CellIterator::new(cells)))
265 } else {
266 Ok(None)
267 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100268 }
269
270 /// Retrieve the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000271 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
272 let value = if let Some(bytes) = self.getprop(name)? {
273 Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
274 } else {
275 None
276 };
277 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100278 }
279
280 /// Retrieve the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000281 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
282 let value = if let Some(bytes) = self.getprop(name)? {
283 Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
284 } else {
285 None
286 };
287 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100288 }
289
290 /// Retrieve the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000291 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900292 if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
293 let offset = (prop as usize)
294 .checked_sub(self.fdt.as_ptr() as usize)
295 .ok_or(FdtError::Internal)?;
296
297 Ok(Some(self.fdt.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)?))
298 } else {
299 Ok(None) // property was not found
300 }
301 }
302
303 /// Return the pointer and size of the property named `name`, in a node at offset `offset`, in
304 /// a device tree `fdt`. The pointer is guaranteed to be non-null, in which case error returns.
305 fn getprop_internal(
306 fdt: &'a Fdt,
307 offset: c_int,
308 name: &CStr,
309 ) -> Result<Option<(*const c_void, usize)>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100310 let mut len: i32 = 0;
311 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
312 // function respects the passed number of characters.
313 let prop = unsafe {
314 libfdt_bindgen::fdt_getprop_namelen(
Jiyong Park9c63cd12023-03-21 17:53:07 +0900315 fdt.as_ptr(),
316 offset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100317 name.as_ptr(),
318 // *_namelen functions don't include the trailing nul terminator in 'len'.
319 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
320 &mut len as *mut i32,
321 )
322 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000323
324 let Some(len) = fdt_err_or_option(len)? else {
325 return Ok(None); // Property was not found.
326 };
327 let len = usize::try_from(len).map_err(|_| FdtError::Internal)?;
328
David Brazdil1baa9a92022-06-28 14:47:50 +0100329 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000330 // We expected an error code in len but still received a valid value?!
331 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100332 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900333 Ok(Some((prop.cast::<c_void>(), len)))
David Brazdil1baa9a92022-06-28 14:47:50 +0100334 }
335
336 /// Get reference to the containing device tree.
337 pub fn fdt(&self) -> &Fdt {
338 self.fdt
339 }
340
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000341 fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
342 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
343 let ret = unsafe {
344 libfdt_bindgen::fdt_node_offset_by_compatible(
345 self.fdt.as_ptr(),
346 self.offset,
347 compatible.as_ptr(),
348 )
349 };
350
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000351 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000352 }
353
David Brazdil1baa9a92022-06-28 14:47:50 +0100354 fn address_cells(&self) -> Result<AddrCells> {
355 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
356 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
357 .try_into()
358 .map_err(|_| FdtError::Internal)
359 }
360
361 fn size_cells(&self) -> Result<SizeCells> {
362 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
363 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
364 .try_into()
365 .map_err(|_| FdtError::Internal)
366 }
367}
368
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000369/// Mutable FDT node.
370pub struct FdtNodeMut<'a> {
371 fdt: &'a mut Fdt,
372 offset: c_int,
373}
374
375impl<'a> FdtNodeMut<'a> {
376 /// Append a property name-value (possibly empty) pair to the given node.
377 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
378 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
379 let ret = unsafe {
380 libfdt_bindgen::fdt_appendprop(
381 self.fdt.as_mut_ptr(),
382 self.offset,
383 name.as_ptr(),
384 value.as_ref().as_ptr().cast::<c_void>(),
385 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
386 )
387 };
388
389 fdt_err_expect_zero(ret)
390 }
391
392 /// Append a (address, size) pair property to the given node.
393 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
394 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
395 let ret = unsafe {
396 libfdt_bindgen::fdt_appendprop_addrrange(
397 self.fdt.as_mut_ptr(),
398 self.parent()?.offset,
399 self.offset,
400 name.as_ptr(),
401 addr,
402 size,
403 )
404 };
405
406 fdt_err_expect_zero(ret)
407 }
408
Jaewan Kimba8929b2023-01-13 11:13:29 +0900409 /// Create or change a property name-value pair to the given node.
410 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
411 // SAFETY - New value size is constrained to the DT totalsize
412 // (validated by underlying libfdt).
413 let ret = unsafe {
414 libfdt_bindgen::fdt_setprop(
415 self.fdt.as_mut_ptr(),
416 self.offset,
417 name.as_ptr(),
418 value.as_ptr().cast::<c_void>(),
419 value.len().try_into().map_err(|_| FdtError::BadValue)?,
420 )
421 };
422
423 fdt_err_expect_zero(ret)
424 }
425
Jiyong Park9c63cd12023-03-21 17:53:07 +0900426 /// Replace the value of the given property with the given value, and ensure that the given
427 /// value has the same length as the current value length
428 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
429 // SAFETY - fdt size is not altered
430 let ret = unsafe {
431 libfdt_bindgen::fdt_setprop_inplace(
432 self.fdt.as_mut_ptr(),
433 self.offset,
434 name.as_ptr(),
435 value.as_ptr().cast::<c_void>(),
436 value.len().try_into().map_err(|_| FdtError::BadValue)?,
437 )
438 };
439
440 fdt_err_expect_zero(ret)
441 }
442
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000443 /// Create or change a flag-like empty property.
444 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
445 self.setprop(name, &[])
446 }
447
448 /// Delete the given property.
449 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
450 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) when the
451 // library locates the node's property. Removing the property may shift the offsets of
452 // other nodes and properties but the borrow checker should prevent this function from
453 // being called when FdtNode instances are in use.
454 let ret = unsafe {
455 libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
456 };
457
458 fdt_err_expect_zero(ret)
459 }
460
Jiyong Park9c63cd12023-03-21 17:53:07 +0900461 /// Reduce the size of the given property to new_size
462 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
463 let (prop, len) =
464 FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
465 if len == new_size {
466 return Ok(());
467 }
468 if new_size > len {
469 return Err(FdtError::NoSpace);
470 }
471
472 // SAFETY - new_size is smaller than the old size
473 let ret = unsafe {
474 libfdt_bindgen::fdt_setprop(
475 self.fdt.as_mut_ptr(),
476 self.offset,
477 name.as_ptr(),
478 prop.cast::<c_void>(),
479 new_size.try_into().map_err(|_| FdtError::BadValue)?,
480 )
481 };
482
483 fdt_err_expect_zero(ret)
484 }
485
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000486 /// Get reference to the containing device tree.
487 pub fn fdt(&mut self) -> &mut Fdt {
488 self.fdt
489 }
490
491 /// Add a new subnode to the given node and return it as a FdtNodeMut on success.
492 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
493 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
494 let ret = unsafe {
495 libfdt_bindgen::fdt_add_subnode(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
496 };
497
498 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
499 }
500
501 fn parent(&'a self) -> Result<FdtNode<'a>> {
502 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
503 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
504
505 Ok(FdtNode { fdt: &*self.fdt, offset: fdt_err(ret)? })
506 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900507
508 /// Return the compatible node of the given name that is next to this node
509 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
510 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
511 let ret = unsafe {
512 libfdt_bindgen::fdt_node_offset_by_compatible(
513 self.fdt.as_ptr(),
514 self.offset,
515 compatible.as_ptr(),
516 )
517 };
518
519 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
520 }
521
522 /// Replace this node and its subtree with nop tags, effectively removing it from the tree, and
523 /// then return the next compatible node of the given name.
524 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
525 // The reason is that libfdt ensures that the node from where the search for the next
526 // compatible node is started is always a valid one -- except for the special case of offset =
527 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
528 // next compatible node from it.
529 //
530 // We can't do in the opposite direction either. If we call next_compatible to find the next
531 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
532 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
533 // DT).
534 pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
535 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
536 let ret = unsafe {
537 libfdt_bindgen::fdt_node_offset_by_compatible(
538 self.fdt.as_ptr(),
539 self.offset,
540 compatible.as_ptr(),
541 )
542 };
543 let next_offset = fdt_err_or_option(ret)?;
544
545 // SAFETY - fdt_nop_node alter only the bytes in the blob which contain the node and its
546 // properties and subnodes, and will not alter or move any other part of the tree.
547 let ret = unsafe { libfdt_bindgen::fdt_nop_node(self.fdt.as_mut_ptr(), self.offset) };
548 fdt_err_expect_zero(ret)?;
549
550 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
551 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000552}
553
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000554/// Iterator over nodes sharing a same compatible string.
555pub struct CompatibleIterator<'a> {
556 node: FdtNode<'a>,
557 compatible: &'a CStr,
558}
559
560impl<'a> CompatibleIterator<'a> {
561 fn new(fdt: &'a Fdt, compatible: &'a CStr) -> Result<Self> {
562 let node = fdt.root()?;
563 Ok(Self { node, compatible })
564 }
565}
566
567impl<'a> Iterator for CompatibleIterator<'a> {
568 type Item = FdtNode<'a>;
569
570 fn next(&mut self) -> Option<Self::Item> {
571 let next = self.node.next_compatible(self.compatible).ok()?;
572
573 if let Some(node) = next {
574 self.node = node;
575 }
576
577 next
578 }
579}
580
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000581/// Wrapper around low-level libfdt functions.
David Brazdil1baa9a92022-06-28 14:47:50 +0100582#[repr(transparent)]
583pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000584 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100585}
586
587impl Fdt {
588 /// Wraps a slice containing a Flattened Device Tree.
589 ///
590 /// Fails if the FDT does not pass validation.
591 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
592 // SAFETY - The FDT will be validated before it is returned.
593 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
594 fdt.check_full()?;
595 Ok(fdt)
596 }
597
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000598 /// Wraps a mutable slice containing a Flattened Device Tree.
599 ///
600 /// Fails if the FDT does not pass validation.
601 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
602 // SAFETY - The FDT will be validated before it is returned.
603 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
604 fdt.check_full()?;
605 Ok(fdt)
606 }
607
David Brazdil1baa9a92022-06-28 14:47:50 +0100608 /// Wraps a slice containing a Flattened Device Tree.
609 ///
610 /// # Safety
611 ///
612 /// The returned FDT might be invalid, only use on slices containing a valid DT.
613 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
614 mem::transmute::<&[u8], &Self>(fdt)
615 }
616
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000617 /// Wraps a mutable slice containing a Flattened Device Tree.
618 ///
619 /// # Safety
620 ///
621 /// The returned FDT might be invalid, only use on slices containing a valid DT.
622 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
623 mem::transmute::<&mut [u8], &mut Self>(fdt)
624 }
625
626 /// Make the whole slice containing the DT available to libfdt.
627 pub fn unpack(&mut self) -> Result<()> {
628 // SAFETY - "Opens" the DT in-place (supported use-case) by updating its header and
629 // internal structures to make use of the whole self.fdt slice but performs no accesses
630 // outside of it and leaves the DT in a state that will be detected by other functions.
631 let ret = unsafe {
632 libfdt_bindgen::fdt_open_into(
633 self.as_ptr(),
634 self.as_mut_ptr(),
635 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
636 )
637 };
638 fdt_err_expect_zero(ret)
639 }
640
641 /// Pack the DT to take a minimum amount of memory.
642 ///
643 /// Doesn't shrink the underlying memory slice.
644 pub fn pack(&mut self) -> Result<()> {
645 // SAFETY - "Closes" the DT in-place by updating its header and relocating its structs.
646 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
647 fdt_err_expect_zero(ret)
648 }
649
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000650 /// Applies a DT overlay on the base DT.
651 ///
652 /// # Safety
653 ///
654 /// On failure, the library corrupts the DT and overlay so both must be discarded.
655 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
656 fdt_err_expect_zero(libfdt_bindgen::fdt_overlay_apply(
657 self.as_mut_ptr(),
658 overlay.as_mut_ptr(),
659 ))?;
660 Ok(self)
661 }
662
David Brazdil1baa9a92022-06-28 14:47:50 +0100663 /// Return an iterator of memory banks specified the "/memory" node.
664 ///
665 /// NOTE: This does not support individual "/memory@XXXX" banks.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000666 pub fn memory(&self) -> Result<Option<MemRegIterator>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100667 let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
668 let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
669
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000670 if let Some(node) = self.node(memory)? {
671 if node.device_type()? != Some(device_type) {
672 return Err(FdtError::BadValue);
673 }
674 let reg = node.reg()?.ok_or(FdtError::BadValue)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100675
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000676 Ok(Some(MemRegIterator::new(reg)))
677 } else {
678 Ok(None)
679 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100680 }
681
682 /// Retrieve the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000683 pub fn chosen(&self) -> Result<Option<FdtNode>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100684 self.node(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
685 }
686
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000687 /// Retrieve the standard /chosen node as mutable.
688 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
689 self.node_mut(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
690 }
691
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000692 /// Get the root node of the tree.
693 pub fn root(&self) -> Result<FdtNode> {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000694 self.node(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000695 }
696
David Brazdil1baa9a92022-06-28 14:47:50 +0100697 /// Find a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000698 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
699 Ok(self.path_offset(path)?.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100700 }
701
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000702 /// Iterate over nodes with a given compatible string.
703 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
704 CompatibleIterator::new(self, compatible)
705 }
706
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000707 /// Get the mutable root node of the tree.
708 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
709 self.node_mut(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
710 }
711
712 /// Find a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000713 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
714 Ok(self.path_offset(path)?.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000715 }
716
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000717 /// Return the device tree as a slice (may be smaller than the containing buffer).
718 pub fn as_slice(&self) -> &[u8] {
719 &self.buffer[..self.totalsize()]
720 }
721
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000722 fn path_offset(&self, path: &CStr) -> Result<Option<c_int>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100723 let len = path.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?;
724 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
725 // function respects the passed number of characters.
726 let ret = unsafe {
727 // *_namelen functions don't include the trailing nul terminator in 'len'.
728 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr(), len)
729 };
730
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000731 fdt_err_or_option(ret)
David Brazdil1baa9a92022-06-28 14:47:50 +0100732 }
733
734 fn check_full(&self) -> Result<()> {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000735 let len = self.buffer.len();
David Brazdil1baa9a92022-06-28 14:47:50 +0100736 // SAFETY - Only performs read accesses within the limits of the slice. If successful, this
737 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
738 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
739 // checking. The library doesn't maintain an internal state (such as pointers) between
740 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
741 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), len) };
742 fdt_err_expect_zero(ret)
743 }
744
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +0000745 /// Return a shared pointer to the device tree.
746 pub fn as_ptr(&self) -> *const c_void {
David Brazdil1baa9a92022-06-28 14:47:50 +0100747 self as *const _ as *const c_void
748 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000749
750 fn as_mut_ptr(&mut self) -> *mut c_void {
751 self as *mut _ as *mut c_void
752 }
753
754 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000755 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000756 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000757
758 fn header(&self) -> &libfdt_bindgen::fdt_header {
759 // SAFETY - A valid FDT (verified by constructor) must contain a valid fdt_header.
760 unsafe { &*(&self as *const _ as *const libfdt_bindgen::fdt_header) }
761 }
762
763 fn totalsize(&self) -> usize {
764 u32::from_be(self.header().totalsize) as usize
765 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100766}