blob: 17cafd5816037875442b368cf124fd93fe52d55a [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
Jiyong Parke9d87e82023-03-21 19:28:40 +090024use core::cmp::max;
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> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900200 /// Create immutable node from a mutable node at the same offset
201 pub fn from_mut(other: &'a FdtNodeMut) -> Self {
202 FdtNode { fdt: other.fdt, offset: other.offset }
203 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100204 /// Find parent node.
205 pub fn parent(&self) -> Result<Self> {
206 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
207 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
208
209 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
210 }
211
212 /// Retrieve the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000213 pub fn device_type(&self) -> Result<Option<&CStr>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100214 self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
215 }
216
217 /// Retrieve the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000218 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
219 let reg = CStr::from_bytes_with_nul(b"reg\0").unwrap();
David Brazdil1baa9a92022-06-28 14:47:50 +0100220
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000221 if let Some(cells) = self.getprop_cells(reg)? {
222 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100223
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000224 let addr_cells = parent.address_cells()?;
225 let size_cells = parent.size_cells()?;
226
227 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
228 } else {
229 Ok(None)
230 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100231 }
232
Andrew Walbranb39e6922022-12-05 17:01:20 +0000233 /// Retrieves the standard ranges property.
234 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
235 let ranges = CStr::from_bytes_with_nul(b"ranges\0").unwrap();
236 if let Some(cells) = self.getprop_cells(ranges)? {
237 let parent = self.parent()?;
238 let addr_cells = self.address_cells()?;
239 let parent_addr_cells = parent.address_cells()?;
240 let size_cells = self.size_cells()?;
241 Ok(Some(RangesIterator::<A, P, S>::new(
242 cells,
243 addr_cells,
244 parent_addr_cells,
245 size_cells,
246 )))
247 } else {
248 Ok(None)
249 }
250 }
251
David Brazdil1baa9a92022-06-28 14:47:50 +0100252 /// Retrieve the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000253 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
254 let value = if let Some(bytes) = self.getprop(name)? {
255 Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?)
256 } else {
257 None
258 };
259 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100260 }
261
262 /// Retrieve the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000263 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
264 if let Some(cells) = self.getprop(name)? {
265 Ok(Some(CellIterator::new(cells)))
266 } else {
267 Ok(None)
268 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100269 }
270
271 /// Retrieve the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000272 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
273 let value = if let Some(bytes) = self.getprop(name)? {
274 Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
275 } else {
276 None
277 };
278 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100279 }
280
281 /// Retrieve the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000282 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
283 let value = if let Some(bytes) = self.getprop(name)? {
284 Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
285 } else {
286 None
287 };
288 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100289 }
290
291 /// Retrieve the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000292 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900293 if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
294 let offset = (prop as usize)
295 .checked_sub(self.fdt.as_ptr() as usize)
296 .ok_or(FdtError::Internal)?;
297
298 Ok(Some(self.fdt.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)?))
299 } else {
300 Ok(None) // property was not found
301 }
302 }
303
304 /// Return the pointer and size of the property named `name`, in a node at offset `offset`, in
305 /// a device tree `fdt`. The pointer is guaranteed to be non-null, in which case error returns.
306 fn getprop_internal(
307 fdt: &'a Fdt,
308 offset: c_int,
309 name: &CStr,
310 ) -> Result<Option<(*const c_void, usize)>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100311 let mut len: i32 = 0;
312 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
313 // function respects the passed number of characters.
314 let prop = unsafe {
315 libfdt_bindgen::fdt_getprop_namelen(
Jiyong Park9c63cd12023-03-21 17:53:07 +0900316 fdt.as_ptr(),
317 offset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100318 name.as_ptr(),
319 // *_namelen functions don't include the trailing nul terminator in 'len'.
320 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
321 &mut len as *mut i32,
322 )
323 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000324
325 let Some(len) = fdt_err_or_option(len)? else {
326 return Ok(None); // Property was not found.
327 };
328 let len = usize::try_from(len).map_err(|_| FdtError::Internal)?;
329
David Brazdil1baa9a92022-06-28 14:47:50 +0100330 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000331 // We expected an error code in len but still received a valid value?!
332 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100333 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900334 Ok(Some((prop.cast::<c_void>(), len)))
David Brazdil1baa9a92022-06-28 14:47:50 +0100335 }
336
337 /// Get reference to the containing device tree.
338 pub fn fdt(&self) -> &Fdt {
339 self.fdt
340 }
341
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000342 fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
343 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
344 let ret = unsafe {
345 libfdt_bindgen::fdt_node_offset_by_compatible(
346 self.fdt.as_ptr(),
347 self.offset,
348 compatible.as_ptr(),
349 )
350 };
351
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000352 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000353 }
354
David Brazdil1baa9a92022-06-28 14:47:50 +0100355 fn address_cells(&self) -> Result<AddrCells> {
356 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
357 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
358 .try_into()
359 .map_err(|_| FdtError::Internal)
360 }
361
362 fn size_cells(&self) -> Result<SizeCells> {
363 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
364 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
365 .try_into()
366 .map_err(|_| FdtError::Internal)
367 }
368}
369
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000370/// Mutable FDT node.
371pub struct FdtNodeMut<'a> {
372 fdt: &'a mut Fdt,
373 offset: c_int,
374}
375
376impl<'a> FdtNodeMut<'a> {
377 /// Append a property name-value (possibly empty) pair to the given node.
378 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
379 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
380 let ret = unsafe {
381 libfdt_bindgen::fdt_appendprop(
382 self.fdt.as_mut_ptr(),
383 self.offset,
384 name.as_ptr(),
385 value.as_ref().as_ptr().cast::<c_void>(),
386 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
387 )
388 };
389
390 fdt_err_expect_zero(ret)
391 }
392
393 /// Append a (address, size) pair property to the given node.
394 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
395 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
396 let ret = unsafe {
397 libfdt_bindgen::fdt_appendprop_addrrange(
398 self.fdt.as_mut_ptr(),
399 self.parent()?.offset,
400 self.offset,
401 name.as_ptr(),
402 addr,
403 size,
404 )
405 };
406
407 fdt_err_expect_zero(ret)
408 }
409
Jaewan Kimba8929b2023-01-13 11:13:29 +0900410 /// Create or change a property name-value pair to the given node.
411 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
412 // SAFETY - New value size is constrained to the DT totalsize
413 // (validated by underlying libfdt).
414 let ret = unsafe {
415 libfdt_bindgen::fdt_setprop(
416 self.fdt.as_mut_ptr(),
417 self.offset,
418 name.as_ptr(),
419 value.as_ptr().cast::<c_void>(),
420 value.len().try_into().map_err(|_| FdtError::BadValue)?,
421 )
422 };
423
424 fdt_err_expect_zero(ret)
425 }
426
Jiyong Park9c63cd12023-03-21 17:53:07 +0900427 /// Replace the value of the given property with the given value, and ensure that the given
428 /// value has the same length as the current value length
429 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
430 // SAFETY - fdt size is not altered
431 let ret = unsafe {
432 libfdt_bindgen::fdt_setprop_inplace(
433 self.fdt.as_mut_ptr(),
434 self.offset,
435 name.as_ptr(),
436 value.as_ptr().cast::<c_void>(),
437 value.len().try_into().map_err(|_| FdtError::BadValue)?,
438 )
439 };
440
441 fdt_err_expect_zero(ret)
442 }
443
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000444 /// Create or change a flag-like empty property.
445 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
446 self.setprop(name, &[])
447 }
448
449 /// Delete the given property.
450 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
451 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) when the
452 // library locates the node's property. Removing the property may shift the offsets of
453 // other nodes and properties but the borrow checker should prevent this function from
454 // being called when FdtNode instances are in use.
455 let ret = unsafe {
456 libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
457 };
458
459 fdt_err_expect_zero(ret)
460 }
461
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000462 /// Overwrite the given property with FDT_NOP, effectively removing it from the DT.
463 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
464 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) when the
465 // library locates the node's property.
466 let ret = unsafe {
467 libfdt_bindgen::fdt_nop_property(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
468 };
469
470 fdt_err_expect_zero(ret)
471 }
472
Jiyong Park9c63cd12023-03-21 17:53:07 +0900473 /// Reduce the size of the given property to new_size
474 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
475 let (prop, len) =
476 FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
477 if len == new_size {
478 return Ok(());
479 }
480 if new_size > len {
481 return Err(FdtError::NoSpace);
482 }
483
484 // SAFETY - new_size is smaller than the old size
485 let ret = unsafe {
486 libfdt_bindgen::fdt_setprop(
487 self.fdt.as_mut_ptr(),
488 self.offset,
489 name.as_ptr(),
490 prop.cast::<c_void>(),
491 new_size.try_into().map_err(|_| FdtError::BadValue)?,
492 )
493 };
494
495 fdt_err_expect_zero(ret)
496 }
497
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000498 /// Get reference to the containing device tree.
499 pub fn fdt(&mut self) -> &mut Fdt {
500 self.fdt
501 }
502
503 /// Add a new subnode to the given node and return it as a FdtNodeMut on success.
504 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
505 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
506 let ret = unsafe {
507 libfdt_bindgen::fdt_add_subnode(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
508 };
509
510 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
511 }
512
513 fn parent(&'a self) -> Result<FdtNode<'a>> {
514 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
515 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
516
517 Ok(FdtNode { fdt: &*self.fdt, offset: fdt_err(ret)? })
518 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900519
520 /// Return the compatible node of the given name that is next to this node
521 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
522 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
523 let ret = unsafe {
524 libfdt_bindgen::fdt_node_offset_by_compatible(
525 self.fdt.as_ptr(),
526 self.offset,
527 compatible.as_ptr(),
528 )
529 };
530
531 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
532 }
533
534 /// Replace this node and its subtree with nop tags, effectively removing it from the tree, and
535 /// then return the next compatible node of the given name.
536 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
537 // The reason is that libfdt ensures that the node from where the search for the next
538 // compatible node is started is always a valid one -- except for the special case of offset =
539 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
540 // next compatible node from it.
541 //
542 // We can't do in the opposite direction either. If we call next_compatible to find the next
543 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
544 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
545 // DT).
546 pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
547 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
548 let ret = unsafe {
549 libfdt_bindgen::fdt_node_offset_by_compatible(
550 self.fdt.as_ptr(),
551 self.offset,
552 compatible.as_ptr(),
553 )
554 };
555 let next_offset = fdt_err_or_option(ret)?;
556
557 // SAFETY - fdt_nop_node alter only the bytes in the blob which contain the node and its
558 // properties and subnodes, and will not alter or move any other part of the tree.
559 let ret = unsafe { libfdt_bindgen::fdt_nop_node(self.fdt.as_mut_ptr(), self.offset) };
560 fdt_err_expect_zero(ret)?;
561
562 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
563 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000564}
565
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000566/// Iterator over nodes sharing a same compatible string.
567pub struct CompatibleIterator<'a> {
568 node: FdtNode<'a>,
569 compatible: &'a CStr,
570}
571
572impl<'a> CompatibleIterator<'a> {
573 fn new(fdt: &'a Fdt, compatible: &'a CStr) -> Result<Self> {
574 let node = fdt.root()?;
575 Ok(Self { node, compatible })
576 }
577}
578
579impl<'a> Iterator for CompatibleIterator<'a> {
580 type Item = FdtNode<'a>;
581
582 fn next(&mut self) -> Option<Self::Item> {
583 let next = self.node.next_compatible(self.compatible).ok()?;
584
585 if let Some(node) = next {
586 self.node = node;
587 }
588
589 next
590 }
591}
592
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000593/// Wrapper around low-level libfdt functions.
David Brazdil1baa9a92022-06-28 14:47:50 +0100594#[repr(transparent)]
595pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000596 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100597}
598
599impl Fdt {
600 /// Wraps a slice containing a Flattened Device Tree.
601 ///
602 /// Fails if the FDT does not pass validation.
603 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
604 // SAFETY - The FDT will be validated before it is returned.
605 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
606 fdt.check_full()?;
607 Ok(fdt)
608 }
609
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000610 /// Wraps a mutable slice containing a Flattened Device Tree.
611 ///
612 /// Fails if the FDT does not pass validation.
613 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
614 // SAFETY - The FDT will be validated before it is returned.
615 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
616 fdt.check_full()?;
617 Ok(fdt)
618 }
619
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900620 /// Creates an empty Flattened Device Tree with a mutable slice.
621 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
622 // SAFETY - fdt_create_empty_tree() only write within the specified length,
623 // and returns error if buffer was insufficient.
624 // There will be no memory write outside of the given fdt.
625 let ret = unsafe {
626 libfdt_bindgen::fdt_create_empty_tree(
627 fdt.as_mut_ptr().cast::<c_void>(),
628 fdt.len() as i32,
629 )
630 };
631 fdt_err_expect_zero(ret)?;
632
633 // SAFETY - The FDT will be validated before it is returned.
634 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
635 fdt.check_full()?;
636
637 Ok(fdt)
638 }
639
David Brazdil1baa9a92022-06-28 14:47:50 +0100640 /// Wraps a slice containing a Flattened Device Tree.
641 ///
642 /// # Safety
643 ///
644 /// The returned FDT might be invalid, only use on slices containing a valid DT.
645 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
646 mem::transmute::<&[u8], &Self>(fdt)
647 }
648
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000649 /// Wraps a mutable slice containing a Flattened Device Tree.
650 ///
651 /// # Safety
652 ///
653 /// The returned FDT might be invalid, only use on slices containing a valid DT.
654 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
655 mem::transmute::<&mut [u8], &mut Self>(fdt)
656 }
657
Jiyong Parke9d87e82023-03-21 19:28:40 +0900658 /// Update this FDT from a slice containing another FDT
659 pub fn copy_from_slice(&mut self, new_fdt: &[u8]) -> Result<()> {
660 if self.buffer.len() < new_fdt.len() {
661 Err(FdtError::NoSpace)
662 } else {
663 let totalsize = self.totalsize();
664 self.buffer[..new_fdt.len()].clone_from_slice(new_fdt);
665 // Zeroize the remaining part. We zeroize up to the size of the original DT because
666 // zeroizing the entire buffer (max 2MB) is not necessary and may increase the VM boot
667 // time.
668 self.buffer[new_fdt.len()..max(new_fdt.len(), totalsize)].fill(0_u8);
669 Ok(())
670 }
671 }
672
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000673 /// Make the whole slice containing the DT available to libfdt.
674 pub fn unpack(&mut self) -> Result<()> {
675 // SAFETY - "Opens" the DT in-place (supported use-case) by updating its header and
676 // internal structures to make use of the whole self.fdt slice but performs no accesses
677 // outside of it and leaves the DT in a state that will be detected by other functions.
678 let ret = unsafe {
679 libfdt_bindgen::fdt_open_into(
680 self.as_ptr(),
681 self.as_mut_ptr(),
682 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
683 )
684 };
685 fdt_err_expect_zero(ret)
686 }
687
688 /// Pack the DT to take a minimum amount of memory.
689 ///
690 /// Doesn't shrink the underlying memory slice.
691 pub fn pack(&mut self) -> Result<()> {
692 // SAFETY - "Closes" the DT in-place by updating its header and relocating its structs.
693 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
694 fdt_err_expect_zero(ret)
695 }
696
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000697 /// Applies a DT overlay on the base DT.
698 ///
699 /// # Safety
700 ///
701 /// On failure, the library corrupts the DT and overlay so both must be discarded.
702 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
703 fdt_err_expect_zero(libfdt_bindgen::fdt_overlay_apply(
704 self.as_mut_ptr(),
705 overlay.as_mut_ptr(),
706 ))?;
707 Ok(self)
708 }
709
David Brazdil1baa9a92022-06-28 14:47:50 +0100710 /// Return an iterator of memory banks specified the "/memory" node.
711 ///
712 /// NOTE: This does not support individual "/memory@XXXX" banks.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000713 pub fn memory(&self) -> Result<Option<MemRegIterator>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100714 let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
715 let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
716
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000717 if let Some(node) = self.node(memory)? {
718 if node.device_type()? != Some(device_type) {
719 return Err(FdtError::BadValue);
720 }
721 let reg = node.reg()?.ok_or(FdtError::BadValue)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100722
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000723 Ok(Some(MemRegIterator::new(reg)))
724 } else {
725 Ok(None)
726 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100727 }
728
729 /// Retrieve the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000730 pub fn chosen(&self) -> Result<Option<FdtNode>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100731 self.node(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
732 }
733
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000734 /// Retrieve the standard /chosen node as mutable.
735 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
736 self.node_mut(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
737 }
738
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000739 /// Get the root node of the tree.
740 pub fn root(&self) -> Result<FdtNode> {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000741 self.node(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000742 }
743
David Brazdil1baa9a92022-06-28 14:47:50 +0100744 /// Find a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000745 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
746 Ok(self.path_offset(path)?.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100747 }
748
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000749 /// Iterate over nodes with a given compatible string.
750 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
751 CompatibleIterator::new(self, compatible)
752 }
753
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000754 /// Get the mutable root node of the tree.
755 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
756 self.node_mut(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
757 }
758
759 /// Find a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000760 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
761 Ok(self.path_offset(path)?.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000762 }
763
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000764 /// Return the device tree as a slice (may be smaller than the containing buffer).
765 pub fn as_slice(&self) -> &[u8] {
766 &self.buffer[..self.totalsize()]
767 }
768
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000769 fn path_offset(&self, path: &CStr) -> Result<Option<c_int>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100770 let len = path.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?;
771 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
772 // function respects the passed number of characters.
773 let ret = unsafe {
774 // *_namelen functions don't include the trailing nul terminator in 'len'.
775 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr(), len)
776 };
777
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000778 fdt_err_or_option(ret)
David Brazdil1baa9a92022-06-28 14:47:50 +0100779 }
780
781 fn check_full(&self) -> Result<()> {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000782 let len = self.buffer.len();
David Brazdil1baa9a92022-06-28 14:47:50 +0100783 // SAFETY - Only performs read accesses within the limits of the slice. If successful, this
784 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
785 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
786 // checking. The library doesn't maintain an internal state (such as pointers) between
787 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
788 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), len) };
789 fdt_err_expect_zero(ret)
790 }
791
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +0000792 /// Return a shared pointer to the device tree.
793 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000794 self.buffer.as_ptr().cast::<_>()
David Brazdil1baa9a92022-06-28 14:47:50 +0100795 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000796
797 fn as_mut_ptr(&mut self) -> *mut c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000798 self.buffer.as_mut_ptr().cast::<_>()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000799 }
800
801 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000802 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000803 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000804
805 fn header(&self) -> &libfdt_bindgen::fdt_header {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000806 let p = self.as_ptr().cast::<_>();
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000807 // SAFETY - A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000808 unsafe { &*p }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000809 }
810
811 fn totalsize(&self) -> usize {
812 u32::from_be(self.header().totalsize) as usize
813 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100814}