• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
20 mod iterators;
21 
22 pub use iterators::{AddressRange, CellIterator, MemRegIterator, RangesIterator, Reg, RegIterator};
23 
24 use core::cmp::max;
25 use core::ffi::{c_int, c_void, CStr};
26 use core::fmt;
27 use core::mem;
28 use core::result;
29 
30 /// Error type corresponding to libfdt error codes.
31 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
32 pub 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 
75 impl fmt::Display for FdtError {
76     /// Prints error messages from libfdt.h documentation.
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result77     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.
104 pub type Result<T> = result::Result<T, FdtError>;
105 
fdt_err(val: c_int) -> Result<c_int>106 fn 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 
fdt_err_expect_zero(val: c_int) -> Result<()>135 fn fdt_err_expect_zero(val: c_int) -> Result<()> {
136     match fdt_err(val)? {
137         0 => Ok(()),
138         _ => Err(FdtError::Unknown(val)),
139     }
140 }
141 
fdt_err_or_option(val: c_int) -> Result<Option<c_int>>142 fn 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 
150 /// Value of a #address-cells property.
151 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
152 enum AddrCells {
153     Single = 1,
154     Double = 2,
155     Triple = 3,
156 }
157 
158 impl TryFrom<c_int> for AddrCells {
159     type Error = FdtError;
160 
try_from(res: c_int) -> Result<Self>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),
165             x if x == Self::Triple as c_int => Ok(Self::Triple),
166             _ => Err(FdtError::BadNCells),
167         }
168     }
169 }
170 
171 /// Value of a #size-cells property.
172 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
173 enum SizeCells {
174     None = 0,
175     Single = 1,
176     Double = 2,
177 }
178 
179 impl TryFrom<c_int> for SizeCells {
180     type Error = FdtError;
181 
try_from(res: c_int) -> Result<Self>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 
192 /// DT node.
193 #[derive(Clone, Copy)]
194 pub struct FdtNode<'a> {
195     fdt: &'a Fdt,
196     offset: c_int,
197 }
198 
199 impl<'a> FdtNode<'a> {
200     /// Create immutable node from a mutable node at the same offset
from_mut(other: &'a FdtNodeMut) -> Self201     pub fn from_mut(other: &'a FdtNodeMut) -> Self {
202         FdtNode { fdt: other.fdt, offset: other.offset }
203     }
204     /// Find parent node.
parent(&self) -> Result<Self>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.
device_type(&self) -> Result<Option<&CStr>>213     pub fn device_type(&self) -> Result<Option<&CStr>> {
214         self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
215     }
216 
217     /// Retrieve the standard reg <prop-encoded-array> property.
reg(&self) -> Result<Option<RegIterator<'a>>>218     pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
219         let reg = CStr::from_bytes_with_nul(b"reg\0").unwrap();
220 
221         if let Some(cells) = self.getprop_cells(reg)? {
222             let parent = self.parent()?;
223 
224             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         }
231     }
232 
233     /// Retrieves the standard ranges property.
ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>>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 
252     /// Retrieve the value of a given <string> property.
getprop_str(&self, name: &CStr) -> Result<Option<&CStr>>253     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)
260     }
261 
262     /// Retrieve the value of a given property as an array of cells.
getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>>263     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         }
269     }
270 
271     /// Retrieve the value of a given <u32> property.
getprop_u32(&self, name: &CStr) -> Result<Option<u32>>272     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)
279     }
280 
281     /// Retrieve the value of a given <u64> property.
getprop_u64(&self, name: &CStr) -> Result<Option<u64>>282     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)
289     }
290 
291     /// Retrieve the value of a given property.
getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>>292     pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
293         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.
getprop_internal( fdt: &'a Fdt, offset: c_int, name: &CStr, ) -> Result<Option<(*const c_void, usize)>>306     fn getprop_internal(
307         fdt: &'a Fdt,
308         offset: c_int,
309         name: &CStr,
310     ) -> Result<Option<(*const c_void, usize)>> {
311         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(
316                 fdt.as_ptr(),
317                 offset,
318                 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;
324 
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 
330         if prop.is_null() {
331             // We expected an error code in len but still received a valid value?!
332             return Err(FdtError::Internal);
333         }
334         Ok(Some((prop.cast::<c_void>(), len)))
335     }
336 
337     /// Get reference to the containing device tree.
fdt(&self) -> &Fdt338     pub fn fdt(&self) -> &Fdt {
339         self.fdt
340     }
341 
next_compatible(self, compatible: &CStr) -> Result<Option<Self>>342     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 
352         Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
353     }
354 
address_cells(&self) -> Result<AddrCells>355     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 
size_cells(&self) -> Result<SizeCells>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 
370 /// Mutable FDT node.
371 pub struct FdtNodeMut<'a> {
372     fdt: &'a mut Fdt,
373     offset: c_int,
374 }
375 
376 impl<'a> FdtNodeMut<'a> {
377     /// Append a property name-value (possibly empty) pair to the given node.
appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()>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.
appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()>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 
410     /// Create or change a property name-value pair to the given node.
setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()>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 
427     /// 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
setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()>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 
444     /// Create or change a flag-like empty property.
setprop_empty(&mut self, name: &CStr) -> Result<()>445     pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
446         self.setprop(name, &[])
447     }
448 
449     /// Delete the given property.
delprop(&mut self, name: &CStr) -> Result<()>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 
462     /// Reduce the size of the given property to new_size
trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()>463     pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
464         let (prop, len) =
465             FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
466         if len == new_size {
467             return Ok(());
468         }
469         if new_size > len {
470             return Err(FdtError::NoSpace);
471         }
472 
473         // SAFETY - new_size is smaller than the old size
474         let ret = unsafe {
475             libfdt_bindgen::fdt_setprop(
476                 self.fdt.as_mut_ptr(),
477                 self.offset,
478                 name.as_ptr(),
479                 prop.cast::<c_void>(),
480                 new_size.try_into().map_err(|_| FdtError::BadValue)?,
481             )
482         };
483 
484         fdt_err_expect_zero(ret)
485     }
486 
487     /// Get reference to the containing device tree.
fdt(&mut self) -> &mut Fdt488     pub fn fdt(&mut self) -> &mut Fdt {
489         self.fdt
490     }
491 
492     /// Add a new subnode to the given node and return it as a FdtNodeMut on success.
add_subnode(&'a mut self, name: &CStr) -> Result<Self>493     pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
494         // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
495         let ret = unsafe {
496             libfdt_bindgen::fdt_add_subnode(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
497         };
498 
499         Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
500     }
501 
parent(&'a self) -> Result<FdtNode<'a>>502     fn parent(&'a self) -> Result<FdtNode<'a>> {
503         // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
504         let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
505 
506         Ok(FdtNode { fdt: &*self.fdt, offset: fdt_err(ret)? })
507     }
508 
509     /// Return the compatible node of the given name that is next to this node
next_compatible(self, compatible: &CStr) -> Result<Option<Self>>510     pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
511         // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
512         let ret = unsafe {
513             libfdt_bindgen::fdt_node_offset_by_compatible(
514                 self.fdt.as_ptr(),
515                 self.offset,
516                 compatible.as_ptr(),
517             )
518         };
519 
520         Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
521     }
522 
523     /// Replace this node and its subtree with nop tags, effectively removing it from the tree, and
524     /// then return the next compatible node of the given name.
525     // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
526     // The reason is that libfdt ensures that the node from where the search for the next
527     // compatible node is started is always a valid one -- except for the special case of offset =
528     // -1 which is to find the first compatible node. So, we can't delete a node and then find the
529     // next compatible node from it.
530     //
531     // We can't do in the opposite direction either. If we call next_compatible to find the next
532     // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
533     // mutable reference to DT, so we can't use current node (which also has a mutable reference to
534     // DT).
delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>>535     pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
536         // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
537         let ret = unsafe {
538             libfdt_bindgen::fdt_node_offset_by_compatible(
539                 self.fdt.as_ptr(),
540                 self.offset,
541                 compatible.as_ptr(),
542             )
543         };
544         let next_offset = fdt_err_or_option(ret)?;
545 
546         // SAFETY - fdt_nop_node alter only the bytes in the blob which contain the node and its
547         // properties and subnodes, and will not alter or move any other part of the tree.
548         let ret = unsafe { libfdt_bindgen::fdt_nop_node(self.fdt.as_mut_ptr(), self.offset) };
549         fdt_err_expect_zero(ret)?;
550 
551         Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
552     }
553 }
554 
555 /// Iterator over nodes sharing a same compatible string.
556 pub struct CompatibleIterator<'a> {
557     node: FdtNode<'a>,
558     compatible: &'a CStr,
559 }
560 
561 impl<'a> CompatibleIterator<'a> {
new(fdt: &'a Fdt, compatible: &'a CStr) -> Result<Self>562     fn new(fdt: &'a Fdt, compatible: &'a CStr) -> Result<Self> {
563         let node = fdt.root()?;
564         Ok(Self { node, compatible })
565     }
566 }
567 
568 impl<'a> Iterator for CompatibleIterator<'a> {
569     type Item = FdtNode<'a>;
570 
next(&mut self) -> Option<Self::Item>571     fn next(&mut self) -> Option<Self::Item> {
572         let next = self.node.next_compatible(self.compatible).ok()?;
573 
574         if let Some(node) = next {
575             self.node = node;
576         }
577 
578         next
579     }
580 }
581 
582 /// Wrapper around low-level libfdt functions.
583 #[repr(transparent)]
584 pub struct Fdt {
585     buffer: [u8],
586 }
587 
588 impl Fdt {
589     /// Wraps a slice containing a Flattened Device Tree.
590     ///
591     /// Fails if the FDT does not pass validation.
from_slice(fdt: &[u8]) -> Result<&Self>592     pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
593         // SAFETY - The FDT will be validated before it is returned.
594         let fdt = unsafe { Self::unchecked_from_slice(fdt) };
595         fdt.check_full()?;
596         Ok(fdt)
597     }
598 
599     /// Wraps a mutable slice containing a Flattened Device Tree.
600     ///
601     /// Fails if the FDT does not pass validation.
from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self>602     pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
603         // SAFETY - The FDT will be validated before it is returned.
604         let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
605         fdt.check_full()?;
606         Ok(fdt)
607     }
608 
609     /// Creates an empty Flattened Device Tree with a mutable slice.
create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self>610     pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
611         // SAFETY - fdt_create_empty_tree() only write within the specified length,
612         //          and returns error if buffer was insufficient.
613         //          There will be no memory write outside of the given fdt.
614         let ret = unsafe {
615             libfdt_bindgen::fdt_create_empty_tree(
616                 fdt.as_mut_ptr().cast::<c_void>(),
617                 fdt.len() as i32,
618             )
619         };
620         fdt_err_expect_zero(ret)?;
621 
622         // SAFETY - The FDT will be validated before it is returned.
623         let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
624         fdt.check_full()?;
625 
626         Ok(fdt)
627     }
628 
629     /// Wraps a slice containing a Flattened Device Tree.
630     ///
631     /// # Safety
632     ///
633     /// The returned FDT might be invalid, only use on slices containing a valid DT.
unchecked_from_slice(fdt: &[u8]) -> &Self634     pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
635         mem::transmute::<&[u8], &Self>(fdt)
636     }
637 
638     /// Wraps a mutable slice containing a Flattened Device Tree.
639     ///
640     /// # Safety
641     ///
642     /// The returned FDT might be invalid, only use on slices containing a valid DT.
unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self643     pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
644         mem::transmute::<&mut [u8], &mut Self>(fdt)
645     }
646 
647     /// Update this FDT from a slice containing another FDT
copy_from_slice(&mut self, new_fdt: &[u8]) -> Result<()>648     pub fn copy_from_slice(&mut self, new_fdt: &[u8]) -> Result<()> {
649         if self.buffer.len() < new_fdt.len() {
650             Err(FdtError::NoSpace)
651         } else {
652             let totalsize = self.totalsize();
653             self.buffer[..new_fdt.len()].clone_from_slice(new_fdt);
654             // Zeroize the remaining part. We zeroize up to the size of the original DT because
655             // zeroizing the entire buffer (max 2MB) is not necessary and may increase the VM boot
656             // time.
657             self.buffer[new_fdt.len()..max(new_fdt.len(), totalsize)].fill(0_u8);
658             Ok(())
659         }
660     }
661 
662     /// Make the whole slice containing the DT available to libfdt.
unpack(&mut self) -> Result<()>663     pub fn unpack(&mut self) -> Result<()> {
664         // SAFETY - "Opens" the DT in-place (supported use-case) by updating its header and
665         // internal structures to make use of the whole self.fdt slice but performs no accesses
666         // outside of it and leaves the DT in a state that will be detected by other functions.
667         let ret = unsafe {
668             libfdt_bindgen::fdt_open_into(
669                 self.as_ptr(),
670                 self.as_mut_ptr(),
671                 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
672             )
673         };
674         fdt_err_expect_zero(ret)
675     }
676 
677     /// Pack the DT to take a minimum amount of memory.
678     ///
679     /// Doesn't shrink the underlying memory slice.
pack(&mut self) -> Result<()>680     pub fn pack(&mut self) -> Result<()> {
681         // SAFETY - "Closes" the DT in-place by updating its header and relocating its structs.
682         let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
683         fdt_err_expect_zero(ret)
684     }
685 
686     /// Applies a DT overlay on the base DT.
687     ///
688     /// # Safety
689     ///
690     /// On failure, the library corrupts the DT and overlay so both must be discarded.
apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self>691     pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
692         fdt_err_expect_zero(libfdt_bindgen::fdt_overlay_apply(
693             self.as_mut_ptr(),
694             overlay.as_mut_ptr(),
695         ))?;
696         Ok(self)
697     }
698 
699     /// Return an iterator of memory banks specified the "/memory" node.
700     ///
701     /// NOTE: This does not support individual "/memory@XXXX" banks.
memory(&self) -> Result<Option<MemRegIterator>>702     pub fn memory(&self) -> Result<Option<MemRegIterator>> {
703         let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
704         let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
705 
706         if let Some(node) = self.node(memory)? {
707             if node.device_type()? != Some(device_type) {
708                 return Err(FdtError::BadValue);
709             }
710             let reg = node.reg()?.ok_or(FdtError::BadValue)?;
711 
712             Ok(Some(MemRegIterator::new(reg)))
713         } else {
714             Ok(None)
715         }
716     }
717 
718     /// Retrieve the standard /chosen node.
chosen(&self) -> Result<Option<FdtNode>>719     pub fn chosen(&self) -> Result<Option<FdtNode>> {
720         self.node(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
721     }
722 
723     /// Retrieve the standard /chosen node as mutable.
chosen_mut(&mut self) -> Result<Option<FdtNodeMut>>724     pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
725         self.node_mut(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
726     }
727 
728     /// Get the root node of the tree.
root(&self) -> Result<FdtNode>729     pub fn root(&self) -> Result<FdtNode> {
730         self.node(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
731     }
732 
733     /// Find a tree node by its full path.
node(&self, path: &CStr) -> Result<Option<FdtNode>>734     pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
735         Ok(self.path_offset(path)?.map(|offset| FdtNode { fdt: self, offset }))
736     }
737 
738     /// Iterate over nodes with a given compatible string.
compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>>739     pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
740         CompatibleIterator::new(self, compatible)
741     }
742 
743     /// Get the mutable root node of the tree.
root_mut(&mut self) -> Result<FdtNodeMut>744     pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
745         self.node_mut(CStr::from_bytes_with_nul(b"/\0").unwrap())?.ok_or(FdtError::Internal)
746     }
747 
748     /// Find a mutable tree node by its full path.
node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>>749     pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
750         Ok(self.path_offset(path)?.map(|offset| FdtNodeMut { fdt: self, offset }))
751     }
752 
753     /// Return the device tree as a slice (may be smaller than the containing buffer).
as_slice(&self) -> &[u8]754     pub fn as_slice(&self) -> &[u8] {
755         &self.buffer[..self.totalsize()]
756     }
757 
path_offset(&self, path: &CStr) -> Result<Option<c_int>>758     fn path_offset(&self, path: &CStr) -> Result<Option<c_int>> {
759         let len = path.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?;
760         // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
761         // function respects the passed number of characters.
762         let ret = unsafe {
763             // *_namelen functions don't include the trailing nul terminator in 'len'.
764             libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr(), len)
765         };
766 
767         fdt_err_or_option(ret)
768     }
769 
check_full(&self) -> Result<()>770     fn check_full(&self) -> Result<()> {
771         let len = self.buffer.len();
772         // SAFETY - Only performs read accesses within the limits of the slice. If successful, this
773         // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
774         // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
775         // checking. The library doesn't maintain an internal state (such as pointers) between
776         // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
777         let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), len) };
778         fdt_err_expect_zero(ret)
779     }
780 
781     /// Return a shared pointer to the device tree.
as_ptr(&self) -> *const c_void782     pub fn as_ptr(&self) -> *const c_void {
783         self.buffer.as_ptr().cast::<_>()
784     }
785 
as_mut_ptr(&mut self) -> *mut c_void786     fn as_mut_ptr(&mut self) -> *mut c_void {
787         self.buffer.as_mut_ptr().cast::<_>()
788     }
789 
capacity(&self) -> usize790     fn capacity(&self) -> usize {
791         self.buffer.len()
792     }
793 
header(&self) -> &libfdt_bindgen::fdt_header794     fn header(&self) -> &libfdt_bindgen::fdt_header {
795         let p = self.as_ptr().cast::<_>();
796         // SAFETY - A valid FDT (verified by constructor) must contain a valid fdt_header.
797         unsafe { &*p }
798     }
799 
totalsize(&self) -> usize800     fn totalsize(&self) -> usize {
801         u32::from_be(self.header().totalsize) as usize
802     }
803 }
804