blob: 32483973bc5a41ee9049aab80100a948cfeabeb9 [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
Jaewan Kimfe06c852023-10-05 23:40:06 +090022pub use iterators::{
Jaewan Kimc9e14112023-12-04 17:05:27 +090023 AddressRange, CellIterator, CompatibleIterator, DescendantsIterator, MemRegIterator,
24 PropertyIterator, RangesIterator, Reg, RegIterator, SubnodeIterator,
Jaewan Kimfe06c852023-10-05 23:40:06 +090025};
Andrew Walbran55ad01b2022-12-05 17:00:40 +000026
Jiyong Parke9d87e82023-03-21 19:28:40 +090027use core::cmp::max;
David Brazdil1baa9a92022-06-28 14:47:50 +010028use core::ffi::{c_int, c_void, CStr};
29use core::fmt;
Alice Wang2422bdc2023-06-12 08:37:55 +000030use core::ops::Range;
Jaewan Kim5b057772023-10-19 01:02:17 +090031use core::ptr;
David Brazdil1baa9a92022-06-28 14:47:50 +010032use core::result;
Pierre-Clément Tosi1bf532b2023-11-13 11:06:20 +000033use cstr::cstr;
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +000034use zerocopy::AsBytes as _;
David Brazdil1baa9a92022-06-28 14:47:50 +010035
36/// Error type corresponding to libfdt error codes.
37#[derive(Clone, Copy, Debug, Eq, PartialEq)]
38pub enum FdtError {
39 /// FDT_ERR_NOTFOUND
40 NotFound,
41 /// FDT_ERR_EXISTS
42 Exists,
43 /// FDT_ERR_NOSPACE
44 NoSpace,
45 /// FDT_ERR_BADOFFSET
46 BadOffset,
47 /// FDT_ERR_BADPATH
48 BadPath,
49 /// FDT_ERR_BADPHANDLE
50 BadPhandle,
51 /// FDT_ERR_BADSTATE
52 BadState,
53 /// FDT_ERR_TRUNCATED
54 Truncated,
55 /// FDT_ERR_BADMAGIC
56 BadMagic,
57 /// FDT_ERR_BADVERSION
58 BadVersion,
59 /// FDT_ERR_BADSTRUCTURE
60 BadStructure,
61 /// FDT_ERR_BADLAYOUT
62 BadLayout,
63 /// FDT_ERR_INTERNAL
64 Internal,
65 /// FDT_ERR_BADNCELLS
66 BadNCells,
67 /// FDT_ERR_BADVALUE
68 BadValue,
69 /// FDT_ERR_BADOVERLAY
70 BadOverlay,
71 /// FDT_ERR_NOPHANDLES
72 NoPhandles,
73 /// FDT_ERR_BADFLAGS
74 BadFlags,
75 /// FDT_ERR_ALIGNMENT
76 Alignment,
77 /// Unexpected error code
78 Unknown(i32),
79}
80
81impl fmt::Display for FdtError {
82 /// Prints error messages from libfdt.h documentation.
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 match self {
85 Self::NotFound => write!(f, "The requested node or property does not exist"),
86 Self::Exists => write!(f, "Attempted to create an existing node or property"),
87 Self::NoSpace => write!(f, "Insufficient buffer space to contain the expanded tree"),
88 Self::BadOffset => write!(f, "Structure block offset is out-of-bounds or invalid"),
89 Self::BadPath => write!(f, "Badly formatted path"),
90 Self::BadPhandle => write!(f, "Invalid phandle length or value"),
91 Self::BadState => write!(f, "Received incomplete device tree"),
92 Self::Truncated => write!(f, "Device tree or sub-block is improperly terminated"),
93 Self::BadMagic => write!(f, "Device tree header missing its magic number"),
94 Self::BadVersion => write!(f, "Device tree has a version which can't be handled"),
95 Self::BadStructure => write!(f, "Device tree has a corrupt structure block"),
96 Self::BadLayout => write!(f, "Device tree sub-blocks in unsupported order"),
97 Self::Internal => write!(f, "libfdt has failed an internal assertion"),
98 Self::BadNCells => write!(f, "Bad format or value of #address-cells or #size-cells"),
99 Self::BadValue => write!(f, "Unexpected property value"),
100 Self::BadOverlay => write!(f, "Overlay cannot be applied"),
101 Self::NoPhandles => write!(f, "Device tree doesn't have any phandle available anymore"),
102 Self::BadFlags => write!(f, "Invalid flag or invalid combination of flags"),
103 Self::Alignment => write!(f, "Device tree base address is not 8-byte aligned"),
104 Self::Unknown(e) => write!(f, "Unknown libfdt error '{e}'"),
105 }
106 }
107}
108
109/// Result type with FdtError enum.
110pub type Result<T> = result::Result<T, FdtError>;
111
112fn fdt_err(val: c_int) -> Result<c_int> {
113 if val >= 0 {
114 Ok(val)
115 } else {
116 Err(match -val as _ {
117 libfdt_bindgen::FDT_ERR_NOTFOUND => FdtError::NotFound,
118 libfdt_bindgen::FDT_ERR_EXISTS => FdtError::Exists,
119 libfdt_bindgen::FDT_ERR_NOSPACE => FdtError::NoSpace,
120 libfdt_bindgen::FDT_ERR_BADOFFSET => FdtError::BadOffset,
121 libfdt_bindgen::FDT_ERR_BADPATH => FdtError::BadPath,
122 libfdt_bindgen::FDT_ERR_BADPHANDLE => FdtError::BadPhandle,
123 libfdt_bindgen::FDT_ERR_BADSTATE => FdtError::BadState,
124 libfdt_bindgen::FDT_ERR_TRUNCATED => FdtError::Truncated,
125 libfdt_bindgen::FDT_ERR_BADMAGIC => FdtError::BadMagic,
126 libfdt_bindgen::FDT_ERR_BADVERSION => FdtError::BadVersion,
127 libfdt_bindgen::FDT_ERR_BADSTRUCTURE => FdtError::BadStructure,
128 libfdt_bindgen::FDT_ERR_BADLAYOUT => FdtError::BadLayout,
129 libfdt_bindgen::FDT_ERR_INTERNAL => FdtError::Internal,
130 libfdt_bindgen::FDT_ERR_BADNCELLS => FdtError::BadNCells,
131 libfdt_bindgen::FDT_ERR_BADVALUE => FdtError::BadValue,
132 libfdt_bindgen::FDT_ERR_BADOVERLAY => FdtError::BadOverlay,
133 libfdt_bindgen::FDT_ERR_NOPHANDLES => FdtError::NoPhandles,
134 libfdt_bindgen::FDT_ERR_BADFLAGS => FdtError::BadFlags,
135 libfdt_bindgen::FDT_ERR_ALIGNMENT => FdtError::Alignment,
136 _ => FdtError::Unknown(val),
137 })
138 }
139}
140
141fn fdt_err_expect_zero(val: c_int) -> Result<()> {
142 match fdt_err(val)? {
143 0 => Ok(()),
144 _ => Err(FdtError::Unknown(val)),
145 }
146}
147
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000148fn fdt_err_or_option(val: c_int) -> Result<Option<c_int>> {
149 match fdt_err(val) {
150 Ok(val) => Ok(Some(val)),
151 Err(FdtError::NotFound) => Ok(None),
152 Err(e) => Err(e),
153 }
154}
155
David Brazdil1baa9a92022-06-28 14:47:50 +0100156/// Value of a #address-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000157#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100158enum AddrCells {
159 Single = 1,
160 Double = 2,
Andrew Walbranb39e6922022-12-05 17:01:20 +0000161 Triple = 3,
David Brazdil1baa9a92022-06-28 14:47:50 +0100162}
163
164impl TryFrom<c_int> for AddrCells {
165 type Error = FdtError;
166
167 fn try_from(res: c_int) -> Result<Self> {
168 match fdt_err(res)? {
169 x if x == Self::Single as c_int => Ok(Self::Single),
170 x if x == Self::Double as c_int => Ok(Self::Double),
Andrew Walbranb39e6922022-12-05 17:01:20 +0000171 x if x == Self::Triple as c_int => Ok(Self::Triple),
David Brazdil1baa9a92022-06-28 14:47:50 +0100172 _ => Err(FdtError::BadNCells),
173 }
174 }
175}
176
177/// Value of a #size-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000178#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100179enum SizeCells {
180 None = 0,
181 Single = 1,
182 Double = 2,
183}
184
185impl TryFrom<c_int> for SizeCells {
186 type Error = FdtError;
187
188 fn try_from(res: c_int) -> Result<Self> {
189 match fdt_err(res)? {
190 x if x == Self::None as c_int => Ok(Self::None),
191 x if x == Self::Single as c_int => Ok(Self::Single),
192 x if x == Self::Double as c_int => Ok(Self::Double),
193 _ => Err(FdtError::BadNCells),
194 }
195 }
196}
197
Jaewan Kim72d10902023-10-12 21:59:26 +0900198/// DT property wrapper to abstract endianess changes
199#[repr(transparent)]
200#[derive(Debug)]
201struct FdtPropertyStruct(libfdt_bindgen::fdt_property);
202
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000203impl AsRef<FdtPropertyStruct> for libfdt_bindgen::fdt_property {
204 fn as_ref(&self) -> &FdtPropertyStruct {
205 let ptr = self as *const _ as *const _;
206 // SAFETY: Types have the same layout (transparent) so the valid reference remains valid.
207 unsafe { &*ptr }
208 }
209}
210
Jaewan Kim72d10902023-10-12 21:59:26 +0900211impl FdtPropertyStruct {
212 fn from_offset(fdt: &Fdt, offset: c_int) -> Result<&Self> {
213 let mut len = 0;
214 let prop =
215 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
216 unsafe { libfdt_bindgen::fdt_get_property_by_offset(fdt.as_ptr(), offset, &mut len) };
217 if prop.is_null() {
218 fdt_err(len)?;
219 return Err(FdtError::Internal); // shouldn't happen.
220 }
221 // SAFETY: prop is only returned when it points to valid libfdt_bindgen.
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000222 let prop = unsafe { &*prop };
223 Ok(prop.as_ref())
Jaewan Kim72d10902023-10-12 21:59:26 +0900224 }
225
226 fn name_offset(&self) -> c_int {
227 u32::from_be(self.0.nameoff).try_into().unwrap()
228 }
229
230 fn data_len(&self) -> usize {
231 u32::from_be(self.0.len).try_into().unwrap()
232 }
233
234 fn data_ptr(&self) -> *const c_void {
235 self.0.data.as_ptr().cast::<_>()
236 }
237}
238
239/// DT property.
240#[derive(Clone, Copy, Debug)]
241pub struct FdtProperty<'a> {
242 fdt: &'a Fdt,
243 offset: c_int,
244 property: &'a FdtPropertyStruct,
245}
246
247impl<'a> FdtProperty<'a> {
248 fn new(fdt: &'a Fdt, offset: c_int) -> Result<Self> {
249 let property = FdtPropertyStruct::from_offset(fdt, offset)?;
250 Ok(Self { fdt, offset, property })
251 }
252
253 /// Returns the property name
254 pub fn name(&self) -> Result<&'a CStr> {
255 self.fdt.string(self.property.name_offset())
256 }
257
258 /// Returns the property value
259 pub fn value(&self) -> Result<&'a [u8]> {
260 self.fdt.get_from_ptr(self.property.data_ptr(), self.property.data_len())
261 }
262
263 fn next_property(&self) -> Result<Option<Self>> {
264 let ret =
265 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
266 unsafe { libfdt_bindgen::fdt_next_property_offset(self.fdt.as_ptr(), self.offset) };
267
268 fdt_err_or_option(ret)?.map(|offset| Self::new(self.fdt, offset)).transpose()
269 }
270}
271
David Brazdil1baa9a92022-06-28 14:47:50 +0100272/// DT node.
Alice Wang9d4df702023-05-25 14:14:12 +0000273#[derive(Clone, Copy, Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100274pub struct FdtNode<'a> {
275 fdt: &'a Fdt,
276 offset: c_int,
277}
278
279impl<'a> FdtNode<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900280 /// Creates immutable node from a mutable node at the same offset.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900281 pub fn from_mut(other: &'a FdtNodeMut) -> Self {
282 FdtNode { fdt: other.fdt, offset: other.offset }
283 }
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900284 /// Returns parent node.
David Brazdil1baa9a92022-06-28 14:47:50 +0100285 pub fn parent(&self) -> Result<Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000286 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
David Brazdil1baa9a92022-06-28 14:47:50 +0100287 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
288
289 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
290 }
291
Jaewan Kim5b057772023-10-19 01:02:17 +0900292 /// Returns supernode with depth. Note that root is at depth 0.
293 pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
294 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
295 let ret = unsafe {
296 libfdt_bindgen::fdt_supernode_atdepth_offset(
297 self.fdt.as_ptr(),
298 self.offset,
299 depth.try_into().unwrap(),
300 ptr::null_mut(),
301 )
302 };
303
304 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
305 }
306
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900307 /// Returns the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000308 pub fn device_type(&self) -> Result<Option<&CStr>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900309 self.getprop_str(cstr!("device_type"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100310 }
311
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900312 /// Returns the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000313 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900314 let reg = cstr!("reg");
David Brazdil1baa9a92022-06-28 14:47:50 +0100315
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000316 if let Some(cells) = self.getprop_cells(reg)? {
317 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100318
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000319 let addr_cells = parent.address_cells()?;
320 let size_cells = parent.size_cells()?;
321
322 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
323 } else {
324 Ok(None)
325 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100326 }
327
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900328 /// Returns the standard ranges property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000329 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900330 let ranges = cstr!("ranges");
Andrew Walbranb39e6922022-12-05 17:01:20 +0000331 if let Some(cells) = self.getprop_cells(ranges)? {
332 let parent = self.parent()?;
333 let addr_cells = self.address_cells()?;
334 let parent_addr_cells = parent.address_cells()?;
335 let size_cells = self.size_cells()?;
336 Ok(Some(RangesIterator::<A, P, S>::new(
337 cells,
338 addr_cells,
339 parent_addr_cells,
340 size_cells,
341 )))
342 } else {
343 Ok(None)
344 }
345 }
346
Jaewan Kimaa638702023-09-19 13:34:01 +0900347 /// Returns the node name.
348 pub fn name(&self) -> Result<&'a CStr> {
349 let mut len: c_int = 0;
350 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor). On success, the
351 // function returns valid null terminating string and otherwise returned values are dropped.
352 let name = unsafe { libfdt_bindgen::fdt_get_name(self.fdt.as_ptr(), self.offset, &mut len) }
353 as *const c_void;
354 let len = usize::try_from(fdt_err(len)?).unwrap();
355 let name = self.fdt.get_from_ptr(name, len + 1)?;
356 CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
357 }
358
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900359 /// Returns the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000360 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
361 let value = if let Some(bytes) = self.getprop(name)? {
362 Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?)
363 } else {
364 None
365 };
366 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100367 }
368
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900369 /// Returns the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000370 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
371 if let Some(cells) = self.getprop(name)? {
372 Ok(Some(CellIterator::new(cells)))
373 } else {
374 Ok(None)
375 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100376 }
377
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900378 /// Returns the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000379 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
380 let value = if let Some(bytes) = self.getprop(name)? {
381 Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
382 } else {
383 None
384 };
385 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100386 }
387
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900388 /// Returns the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000389 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
390 let value = if let Some(bytes) = self.getprop(name)? {
391 Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
392 } else {
393 None
394 };
395 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100396 }
397
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900398 /// Returns the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000399 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900400 if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
Jaewan Kimaa638702023-09-19 13:34:01 +0900401 Ok(Some(self.fdt.get_from_ptr(prop, len)?))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900402 } else {
403 Ok(None) // property was not found
404 }
405 }
406
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900407 /// Returns the pointer and size of the property named `name`, in a node at offset `offset`, in
Jiyong Park9c63cd12023-03-21 17:53:07 +0900408 /// a device tree `fdt`. The pointer is guaranteed to be non-null, in which case error returns.
409 fn getprop_internal(
410 fdt: &'a Fdt,
411 offset: c_int,
412 name: &CStr,
413 ) -> Result<Option<(*const c_void, usize)>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100414 let mut len: i32 = 0;
Andrew Walbran84b9a232023-07-05 14:01:40 +0000415 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +0100416 // function respects the passed number of characters.
417 let prop = unsafe {
418 libfdt_bindgen::fdt_getprop_namelen(
Jiyong Park9c63cd12023-03-21 17:53:07 +0900419 fdt.as_ptr(),
420 offset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100421 name.as_ptr(),
422 // *_namelen functions don't include the trailing nul terminator in 'len'.
423 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
424 &mut len as *mut i32,
425 )
426 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000427
428 let Some(len) = fdt_err_or_option(len)? else {
429 return Ok(None); // Property was not found.
430 };
Jaewan Kimaa638702023-09-19 13:34:01 +0900431 let len = usize::try_from(len).unwrap();
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000432
David Brazdil1baa9a92022-06-28 14:47:50 +0100433 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000434 // We expected an error code in len but still received a valid value?!
435 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100436 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900437 Ok(Some((prop.cast::<c_void>(), len)))
David Brazdil1baa9a92022-06-28 14:47:50 +0100438 }
439
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900440 /// Returns reference to the containing device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100441 pub fn fdt(&self) -> &Fdt {
442 self.fdt
443 }
444
Alice Wang474c0ee2023-09-14 12:52:33 +0000445 /// Returns the compatible node of the given name that is next after this node.
446 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000447 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000448 let ret = unsafe {
449 libfdt_bindgen::fdt_node_offset_by_compatible(
450 self.fdt.as_ptr(),
451 self.offset,
452 compatible.as_ptr(),
453 )
454 };
455
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000456 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000457 }
458
Alice Wang474c0ee2023-09-14 12:52:33 +0000459 /// Returns the first range of `reg` in this node.
460 pub fn first_reg(&self) -> Result<Reg<u64>> {
461 self.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
462 }
463
David Brazdil1baa9a92022-06-28 14:47:50 +0100464 fn address_cells(&self) -> Result<AddrCells> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000465 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
David Brazdil1baa9a92022-06-28 14:47:50 +0100466 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
467 .try_into()
468 .map_err(|_| FdtError::Internal)
469 }
470
471 fn size_cells(&self) -> Result<SizeCells> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000472 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
David Brazdil1baa9a92022-06-28 14:47:50 +0100473 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
474 .try_into()
475 .map_err(|_| FdtError::Internal)
476 }
Jaewan Kimbc828d72023-09-19 15:52:08 +0900477
478 /// Returns an iterator of subnodes
Jaewan Kim4a34b0d2024-01-19 13:17:47 +0900479 pub fn subnodes(&self) -> Result<SubnodeIterator<'a>> {
Jaewan Kimbc828d72023-09-19 15:52:08 +0900480 SubnodeIterator::new(self)
481 }
482
483 fn first_subnode(&self) -> Result<Option<Self>> {
484 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
485 let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
486
487 Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
488 }
489
490 fn next_subnode(&self) -> Result<Option<Self>> {
491 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
492 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
493
494 Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
495 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900496
Jaewan Kimc9e14112023-12-04 17:05:27 +0900497 /// Returns an iterator of descendants
Jaewan Kim1eab7232024-01-04 09:46:16 +0900498 pub fn descendants(&self) -> DescendantsIterator<'a> {
Jaewan Kimc9e14112023-12-04 17:05:27 +0900499 DescendantsIterator::new(self)
500 }
501
502 fn next_node(&self, depth: usize) -> Result<Option<(Self, usize)>> {
503 let mut next_depth: c_int = depth.try_into().unwrap();
504 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
505 let ret = unsafe {
506 libfdt_bindgen::fdt_next_node(self.fdt.as_ptr(), self.offset, &mut next_depth)
507 };
508 let Ok(next_depth) = usize::try_from(next_depth) else {
509 return Ok(None);
510 };
511 Ok(fdt_err_or_option(ret)?.map(|offset| (FdtNode { fdt: self.fdt, offset }, next_depth)))
512 }
513
Jaewan Kim72d10902023-10-12 21:59:26 +0900514 /// Returns an iterator of properties
515 pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
516 PropertyIterator::new(self)
517 }
518
519 fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
520 let ret =
521 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
522 unsafe { libfdt_bindgen::fdt_first_property_offset(self.fdt.as_ptr(), self.offset) };
523
524 fdt_err_or_option(ret)?.map(|offset| FdtProperty::new(self.fdt, offset)).transpose()
525 }
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900526
527 /// Returns the phandle
528 pub fn get_phandle(&self) -> Result<Option<Phandle>> {
529 // This rewrites the fdt_get_phandle() because it doesn't return error code.
530 if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
531 Ok(Some(prop.try_into()?))
532 } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
533 Ok(Some(prop.try_into()?))
534 } else {
535 Ok(None)
536 }
537 }
Jaewan Kim52026012023-12-13 13:49:28 +0900538
539 /// Returns the subnode of the given name. The name doesn't need to be nul-terminated.
540 pub fn subnode(&self, name: &CStr) -> Result<Option<Self>> {
541 let offset = self.subnode_offset(name.to_bytes())?;
542 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
543 }
544
545 /// Returns the subnode of the given name bytes
546 pub fn subnode_with_name_bytes(&self, name: &[u8]) -> Result<Option<Self>> {
547 let offset = self.subnode_offset(name)?;
548 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
549 }
550
551 fn subnode_offset(&self, name: &[u8]) -> Result<Option<c_int>> {
552 let namelen = name.len().try_into().unwrap();
553 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
554 let ret = unsafe {
555 libfdt_bindgen::fdt_subnode_offset_namelen(
556 self.fdt.as_ptr(),
557 self.offset,
558 name.as_ptr().cast::<_>(),
559 namelen,
560 )
561 };
562 fdt_err_or_option(ret)
563 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100564}
565
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000566impl<'a> PartialEq for FdtNode<'a> {
567 fn eq(&self, other: &Self) -> bool {
568 self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
569 }
570}
571
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900572/// Phandle of a FDT node
573#[repr(transparent)]
Jaewan Kim55f438c2023-11-15 01:24:36 +0900574#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900575pub struct Phandle(u32);
576
577impl Phandle {
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000578 /// Minimum valid value for device tree phandles.
579 pub const MIN: Self = Self(1);
580 /// Maximum valid value for device tree phandles.
581 pub const MAX: Self = Self(libfdt_bindgen::FDT_MAX_PHANDLE);
582
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900583 /// Creates a new Phandle
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000584 pub const fn new(value: u32) -> Option<Self> {
585 if Self::MIN.0 <= value && value <= Self::MAX.0 {
586 Some(Self(value))
587 } else {
588 None
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900589 }
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900590 }
591}
592
593impl From<Phandle> for u32 {
594 fn from(phandle: Phandle) -> u32 {
595 phandle.0
596 }
597}
598
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000599impl TryFrom<u32> for Phandle {
600 type Error = FdtError;
601
602 fn try_from(value: u32) -> Result<Self> {
603 Self::new(value).ok_or(FdtError::BadPhandle)
604 }
605}
606
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000607/// Mutable FDT node.
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000608#[derive(Debug)]
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000609pub struct FdtNodeMut<'a> {
610 fdt: &'a mut Fdt,
611 offset: c_int,
612}
613
614impl<'a> FdtNodeMut<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900615 /// Appends a property name-value (possibly empty) pair to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000616 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000617 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000618 let ret = unsafe {
619 libfdt_bindgen::fdt_appendprop(
620 self.fdt.as_mut_ptr(),
621 self.offset,
622 name.as_ptr(),
623 value.as_ref().as_ptr().cast::<c_void>(),
624 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
625 )
626 };
627
628 fdt_err_expect_zero(ret)
629 }
630
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900631 /// Appends a (address, size) pair property to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000632 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000633 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000634 let ret = unsafe {
635 libfdt_bindgen::fdt_appendprop_addrrange(
636 self.fdt.as_mut_ptr(),
637 self.parent()?.offset,
638 self.offset,
639 name.as_ptr(),
640 addr,
641 size,
642 )
643 };
644
645 fdt_err_expect_zero(ret)
646 }
647
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900648 /// Sets a property name-value pair to the given node.
649 ///
650 /// This may create a new prop or replace existing value.
Jaewan Kimba8929b2023-01-13 11:13:29 +0900651 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000652 // SAFETY: New value size is constrained to the DT totalsize
Jaewan Kimba8929b2023-01-13 11:13:29 +0900653 // (validated by underlying libfdt).
654 let ret = unsafe {
655 libfdt_bindgen::fdt_setprop(
656 self.fdt.as_mut_ptr(),
657 self.offset,
658 name.as_ptr(),
659 value.as_ptr().cast::<c_void>(),
660 value.len().try_into().map_err(|_| FdtError::BadValue)?,
661 )
662 };
663
664 fdt_err_expect_zero(ret)
665 }
666
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900667 /// Sets the value of the given property with the given value, and ensure that the given
668 /// value has the same length as the current value length.
669 ///
670 /// This can only be used to replace existing value.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900671 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000672 // SAFETY: fdt size is not altered
Jiyong Park9c63cd12023-03-21 17:53:07 +0900673 let ret = unsafe {
674 libfdt_bindgen::fdt_setprop_inplace(
675 self.fdt.as_mut_ptr(),
676 self.offset,
677 name.as_ptr(),
678 value.as_ptr().cast::<c_void>(),
679 value.len().try_into().map_err(|_| FdtError::BadValue)?,
680 )
681 };
682
683 fdt_err_expect_zero(ret)
684 }
685
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900686 /// Sets the value of the given (address, size) pair property with the given value, and
687 /// ensure that the given value has the same length as the current value length.
688 ///
689 /// This can only be used to replace existing value.
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000690 pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
691 let pair = [addr.to_be(), size.to_be()];
692 self.setprop_inplace(name, pair.as_bytes())
693 }
694
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900695 /// Sets a flag-like empty property.
696 ///
697 /// This may create a new prop or replace existing value.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000698 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
699 self.setprop(name, &[])
700 }
701
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900702 /// Deletes the given property.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000703 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000704 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000705 // library locates the node's property. Removing the property may shift the offsets of
706 // other nodes and properties but the borrow checker should prevent this function from
707 // being called when FdtNode instances are in use.
708 let ret = unsafe {
709 libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
710 };
711
712 fdt_err_expect_zero(ret)
713 }
714
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900715 /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000716 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000717 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000718 // library locates the node's property.
719 let ret = unsafe {
720 libfdt_bindgen::fdt_nop_property(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
721 };
722
723 fdt_err_expect_zero(ret)
724 }
725
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900726 /// Trims the size of the given property to new_size.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900727 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
728 let (prop, len) =
729 FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
730 if len == new_size {
731 return Ok(());
732 }
733 if new_size > len {
734 return Err(FdtError::NoSpace);
735 }
736
Andrew Walbran84b9a232023-07-05 14:01:40 +0000737 // SAFETY: new_size is smaller than the old size
Jiyong Park9c63cd12023-03-21 17:53:07 +0900738 let ret = unsafe {
739 libfdt_bindgen::fdt_setprop(
740 self.fdt.as_mut_ptr(),
741 self.offset,
742 name.as_ptr(),
743 prop.cast::<c_void>(),
744 new_size.try_into().map_err(|_| FdtError::BadValue)?,
745 )
746 };
747
748 fdt_err_expect_zero(ret)
749 }
750
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900751 /// Returns reference to the containing device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000752 pub fn fdt(&mut self) -> &mut Fdt {
753 self.fdt
754 }
755
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900756 /// Returns immutable FdtNode of this node.
757 pub fn as_node(&self) -> FdtNode {
758 FdtNode { fdt: self.fdt, offset: self.offset }
759 }
760
Jaewan Kime6363422024-01-19 14:00:00 +0900761 /// Adds new subnodes to the given node.
762 pub fn add_subnodes(&mut self, names: &[&CStr]) -> Result<()> {
763 for name in names {
764 self.add_subnode_offset(name.to_bytes())?;
765 }
766 Ok(())
767 }
768
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900769 /// Adds a new subnode to the given node and return it as a FdtNodeMut on success.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000770 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
Jaewan Kim5ab13582023-10-20 20:56:27 +0900771 let offset = self.add_subnode_offset(name.to_bytes())?;
772 Ok(Self { fdt: self.fdt, offset })
773 }
774
775 /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
776 /// on success.
777 pub fn add_subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Self> {
778 let offset = { self.add_subnode_offset(&name.to_bytes()[..namelen])? };
779 Ok(Self { fdt: self.fdt, offset })
780 }
781
782 fn add_subnode_offset(&mut self, name: &[u8]) -> Result<c_int> {
783 let namelen = name.len().try_into().unwrap();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000784 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000785 let ret = unsafe {
Jaewan Kim5ab13582023-10-20 20:56:27 +0900786 libfdt_bindgen::fdt_add_subnode_namelen(
787 self.fdt.as_mut_ptr(),
788 self.offset,
789 name.as_ptr().cast::<_>(),
790 namelen,
791 )
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000792 };
Jaewan Kim5ab13582023-10-20 20:56:27 +0900793 fdt_err(ret)
794 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000795
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900796 /// Returns the first subnode of this
797 pub fn first_subnode(&'a mut self) -> Result<Option<Self>> {
798 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
799 let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
800
801 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
802 }
803
804 /// Returns the next subnode that shares the same parent with this
805 pub fn next_subnode(self) -> Result<Option<Self>> {
806 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
807 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
808
809 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
810 }
811
812 /// Deletes the current node and returns the next subnode
813 pub fn delete_and_next_subnode(mut self) -> Result<Option<Self>> {
814 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
815 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
816
817 let next_offset = fdt_err_or_option(ret)?;
818
819 if Some(self.offset) == next_offset {
820 return Err(FdtError::Internal);
821 }
822
823 // SAFETY: nop_self() only touches bytes of the self and its properties and subnodes, and
824 // doesn't alter any other blob in the tree. self.fdt and next_offset would remain valid.
825 unsafe { self.nop_self()? };
826
827 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
828 }
829
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900830 fn next_node_offset(&self, depth: usize) -> Result<Option<(c_int, usize)>> {
831 let mut next_depth: c_int = depth.try_into().or(Err(FdtError::BadValue))?;
832 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
833 let ret = unsafe {
834 libfdt_bindgen::fdt_next_node(self.fdt.as_ptr(), self.offset, &mut next_depth)
835 };
836 let Ok(next_depth) = usize::try_from(next_depth) else {
837 return Ok(None);
838 };
839 Ok(fdt_err_or_option(ret)?.map(|offset| (offset, next_depth)))
840 }
841
842 /// Returns the next node
843 pub fn next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
844 Ok(self
845 .next_node_offset(depth)?
846 .map(|(offset, next_depth)| (FdtNodeMut { fdt: self.fdt, offset }, next_depth)))
847 }
848
849 /// Deletes this and returns the next node
850 pub fn delete_and_next_node(mut self, depth: usize) -> Result<Option<(Self, usize)>> {
851 // Skip all would-be-removed descendants.
852 let mut iter = self.next_node_offset(depth)?;
853 while let Some((descendant_offset, descendant_depth)) = iter {
854 if descendant_depth <= depth {
855 break;
856 }
857 let descendant = FdtNodeMut { fdt: self.fdt, offset: descendant_offset };
858 iter = descendant.next_node_offset(descendant_depth)?;
859 }
860 // SAFETY: This consumes self, so invalid node wouldn't be used any further
861 unsafe { self.nop_self()? };
862 Ok(iter.map(|(offset, next_depth)| (FdtNodeMut { fdt: self.fdt, offset }, next_depth)))
863 }
864
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000865 fn parent(&'a self) -> Result<FdtNode<'a>> {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000866 self.as_node().parent()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000867 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900868
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900869 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900870 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000871 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900872 let ret = unsafe {
873 libfdt_bindgen::fdt_node_offset_by_compatible(
874 self.fdt.as_ptr(),
875 self.offset,
876 compatible.as_ptr(),
877 )
878 };
879
880 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
881 }
882
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900883 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
884 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900885 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
886 // The reason is that libfdt ensures that the node from where the search for the next
887 // compatible node is started is always a valid one -- except for the special case of offset =
888 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
889 // next compatible node from it.
890 //
891 // We can't do in the opposite direction either. If we call next_compatible to find the next
892 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
893 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
894 // DT).
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900895 pub fn delete_and_next_compatible(mut self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000896 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900897 let ret = unsafe {
898 libfdt_bindgen::fdt_node_offset_by_compatible(
899 self.fdt.as_ptr(),
900 self.offset,
901 compatible.as_ptr(),
902 )
903 };
904 let next_offset = fdt_err_or_option(ret)?;
905
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900906 if Some(self.offset) == next_offset {
907 return Err(FdtError::Internal);
908 }
909
910 // SAFETY: nop_self() only touches bytes of the self and its properties and subnodes, and
911 // doesn't alter any other blob in the tree. self.fdt and next_offset would remain valid.
912 unsafe { self.nop_self()? };
Jiyong Park9c63cd12023-03-21 17:53:07 +0900913
914 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
915 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900916
917 /// Deletes this node effectively from DT, by setting it with FDT_NOP
918 pub fn nop(mut self) -> Result<()> {
919 // SAFETY: This consumes self, so invalid node wouldn't be used any further
920 unsafe { self.nop_self() }
921 }
922
923 /// Deletes this node effectively from DT, by setting it with FDT_NOP.
924 /// This only changes bytes of the node and its properties and subnodes, and doesn't alter or
925 /// move any other part of the tree.
926 /// SAFETY: This node is no longer valid.
927 unsafe fn nop_self(&mut self) -> Result<()> {
928 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
929 let ret = unsafe { libfdt_bindgen::fdt_nop_node(self.fdt.as_mut_ptr(), self.offset) };
930
931 fdt_err_expect_zero(ret)
932 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000933}
934
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000935/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000936#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100937#[repr(transparent)]
938pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000939 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100940}
941
942impl Fdt {
943 /// Wraps a slice containing a Flattened Device Tree.
944 ///
945 /// Fails if the FDT does not pass validation.
946 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000947 // SAFETY: The FDT will be validated before it is returned.
David Brazdil1baa9a92022-06-28 14:47:50 +0100948 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
949 fdt.check_full()?;
950 Ok(fdt)
951 }
952
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000953 /// Wraps a mutable slice containing a Flattened Device Tree.
954 ///
955 /// Fails if the FDT does not pass validation.
956 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000957 // SAFETY: The FDT will be validated before it is returned.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000958 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
959 fdt.check_full()?;
960 Ok(fdt)
961 }
962
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900963 /// Creates an empty Flattened Device Tree with a mutable slice.
964 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000965 // SAFETY: fdt_create_empty_tree() only write within the specified length,
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900966 // and returns error if buffer was insufficient.
967 // There will be no memory write outside of the given fdt.
968 let ret = unsafe {
969 libfdt_bindgen::fdt_create_empty_tree(
970 fdt.as_mut_ptr().cast::<c_void>(),
971 fdt.len() as i32,
972 )
973 };
974 fdt_err_expect_zero(ret)?;
975
Andrew Walbran84b9a232023-07-05 14:01:40 +0000976 // SAFETY: The FDT will be validated before it is returned.
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900977 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
978 fdt.check_full()?;
979
980 Ok(fdt)
981 }
982
David Brazdil1baa9a92022-06-28 14:47:50 +0100983 /// Wraps a slice containing a Flattened Device Tree.
984 ///
985 /// # Safety
986 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000987 /// It is undefined to call this function on a slice that does not contain a valid device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100988 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000989 let self_ptr = fdt as *const _ as *const _;
990 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
991 unsafe { &*self_ptr }
David Brazdil1baa9a92022-06-28 14:47:50 +0100992 }
993
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000994 /// Wraps a mutable slice containing a Flattened Device Tree.
995 ///
996 /// # Safety
997 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000998 /// It is undefined to call this function on a slice that does not contain a valid device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000999 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +00001000 let self_mut_ptr = fdt as *mut _ as *mut _;
1001 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
1002 unsafe { &mut *self_mut_ptr }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001003 }
1004
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001005 /// Updates this FDT from a slice containing another FDT.
Jiyong Parke9d87e82023-03-21 19:28:40 +09001006 pub fn copy_from_slice(&mut self, new_fdt: &[u8]) -> Result<()> {
1007 if self.buffer.len() < new_fdt.len() {
1008 Err(FdtError::NoSpace)
1009 } else {
1010 let totalsize = self.totalsize();
1011 self.buffer[..new_fdt.len()].clone_from_slice(new_fdt);
1012 // Zeroize the remaining part. We zeroize up to the size of the original DT because
1013 // zeroizing the entire buffer (max 2MB) is not necessary and may increase the VM boot
1014 // time.
1015 self.buffer[new_fdt.len()..max(new_fdt.len(), totalsize)].fill(0_u8);
1016 Ok(())
1017 }
1018 }
1019
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001020 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001021 pub fn unpack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001022 // SAFETY: "Opens" the DT in-place (supported use-case) by updating its header and
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001023 // internal structures to make use of the whole self.fdt slice but performs no accesses
1024 // outside of it and leaves the DT in a state that will be detected by other functions.
1025 let ret = unsafe {
1026 libfdt_bindgen::fdt_open_into(
1027 self.as_ptr(),
1028 self.as_mut_ptr(),
1029 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
1030 )
1031 };
1032 fdt_err_expect_zero(ret)
1033 }
1034
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001035 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001036 ///
1037 /// Doesn't shrink the underlying memory slice.
1038 pub fn pack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001039 // SAFETY: "Closes" the DT in-place by updating its header and relocating its structs.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001040 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
1041 fdt_err_expect_zero(ret)
1042 }
1043
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +00001044 /// Applies a DT overlay on the base DT.
1045 ///
1046 /// # Safety
1047 ///
1048 /// On failure, the library corrupts the DT and overlay so both must be discarded.
1049 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001050 let ret =
1051 // SAFETY: Both pointers are valid because they come from references, and fdt_overlay_apply
1052 // doesn't keep them after it returns. It may corrupt their contents if there is an error,
1053 // but that's our caller's responsibility.
1054 unsafe { libfdt_bindgen::fdt_overlay_apply(self.as_mut_ptr(), overlay.as_mut_ptr()) };
1055 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +00001056 Ok(self)
1057 }
1058
Alice Wang2422bdc2023-06-12 08:37:55 +00001059 /// Returns an iterator of memory banks specified the "/memory" node.
1060 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +01001061 ///
1062 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +00001063 pub fn memory(&self) -> Result<MemRegIterator> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001064 let memory_node_name = cstr!("/memory");
1065 let memory_device_type = cstr!("memory");
David Brazdil1baa9a92022-06-28 14:47:50 +01001066
Alice Wang2422bdc2023-06-12 08:37:55 +00001067 let node = self.node(memory_node_name)?.ok_or(FdtError::NotFound)?;
1068 if node.device_type()? != Some(memory_device_type) {
1069 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001070 }
Alice Wang2422bdc2023-06-12 08:37:55 +00001071 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
1072 }
1073
1074 /// Returns the first memory range in the `/memory` node.
1075 pub fn first_memory_range(&self) -> Result<Range<usize>> {
1076 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +01001077 }
1078
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001079 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001080 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001081 self.node(cstr!("/chosen"))
David Brazdil1baa9a92022-06-28 14:47:50 +01001082 }
1083
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001084 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +00001085 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001086 self.node_mut(cstr!("/chosen"))
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +00001087 }
1088
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001089 /// Returns the root node of the tree.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001090 pub fn root(&self) -> Result<FdtNode> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001091 self.node(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001092 }
1093
Jaewan Kimf163d762023-11-01 13:12:50 +09001094 /// Returns the standard /__symbols__ node.
1095 pub fn symbols(&self) -> Result<Option<FdtNode>> {
1096 self.node(cstr!("/__symbols__"))
1097 }
1098
1099 /// Returns the standard /__symbols__ node as mutable
1100 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
1101 self.node_mut(cstr!("/__symbols__"))
1102 }
1103
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001104 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001105 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Jaewan Kimbab42592023-10-13 15:47:19 +09001106 Ok(self.path_offset(path.to_bytes())?.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +01001107 }
1108
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001109 /// Iterate over nodes with a given compatible string.
1110 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
1111 CompatibleIterator::new(self, compatible)
1112 }
1113
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001114 /// Returns max phandle in the tree.
1115 pub fn max_phandle(&self) -> Result<Phandle> {
1116 let mut phandle: u32 = 0;
1117 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
1118 let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(self.as_ptr(), &mut phandle) };
1119
1120 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosieba27792023-10-30 12:04:12 +00001121 phandle.try_into()
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001122 }
1123
1124 /// Returns a node with the phandle
1125 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Jaewan Kimc63246d2023-11-09 15:41:01 +09001126 let offset = self.node_offset_with_phandle(phandle)?;
1127 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
1128 }
1129
1130 /// Returns a mutable node with the phandle
1131 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
1132 let offset = self.node_offset_with_phandle(phandle)?;
1133 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
1134 }
1135
1136 fn node_offset_with_phandle(&self, phandle: Phandle) -> Result<Option<c_int>> {
1137 // SAFETY: Accesses are constrained to the DT totalsize.
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001138 let ret = unsafe { libfdt_bindgen::fdt_node_offset_by_phandle(self.as_ptr(), phandle.0) };
Jaewan Kimc63246d2023-11-09 15:41:01 +09001139 fdt_err_or_option(ret)
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001140 }
1141
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001142 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001143 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001144 self.node_mut(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001145 }
1146
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001147 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001148 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Jaewan Kimbab42592023-10-13 15:47:19 +09001149 Ok(self.path_offset(path.to_bytes())?.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001150 }
1151
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001152 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001153 pub fn as_slice(&self) -> &[u8] {
1154 &self.buffer[..self.totalsize()]
1155 }
1156
Jaewan Kimbab42592023-10-13 15:47:19 +09001157 fn path_offset(&self, path: &[u8]) -> Result<Option<c_int>> {
1158 let len = path.len().try_into().map_err(|_| FdtError::BadPath)?;
Andrew Walbran84b9a232023-07-05 14:01:40 +00001159 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +01001160 // function respects the passed number of characters.
1161 let ret = unsafe {
1162 // *_namelen functions don't include the trailing nul terminator in 'len'.
Jaewan Kimbab42592023-10-13 15:47:19 +09001163 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr().cast::<_>(), len)
David Brazdil1baa9a92022-06-28 14:47:50 +01001164 };
1165
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001166 fdt_err_or_option(ret)
David Brazdil1baa9a92022-06-28 14:47:50 +01001167 }
1168
1169 fn check_full(&self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001170 // SAFETY: Only performs read accesses within the limits of the slice. If successful, this
David Brazdil1baa9a92022-06-28 14:47:50 +01001171 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
1172 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
1173 // checking. The library doesn't maintain an internal state (such as pointers) between
1174 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
Pierre-Clément Tosi02017da2023-09-26 17:57:04 +01001175 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), self.capacity()) };
David Brazdil1baa9a92022-06-28 14:47:50 +01001176 fdt_err_expect_zero(ret)
1177 }
1178
Jaewan Kimaa638702023-09-19 13:34:01 +09001179 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
1180 let ptr = ptr as usize;
1181 let offset = ptr.checked_sub(self.as_ptr() as usize).ok_or(FdtError::Internal)?;
1182 self.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)
1183 }
1184
Jaewan Kim72d10902023-10-12 21:59:26 +09001185 fn string(&self, offset: c_int) -> Result<&CStr> {
1186 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
1187 let res = unsafe { libfdt_bindgen::fdt_string(self.as_ptr(), offset) };
1188 if res.is_null() {
1189 return Err(FdtError::Internal);
1190 }
1191
1192 // SAFETY: Non-null return from fdt_string() is valid null-terminating string within FDT.
1193 Ok(unsafe { CStr::from_ptr(res) })
1194 }
1195
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001196 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +00001197 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001198 self.buffer.as_ptr().cast::<_>()
David Brazdil1baa9a92022-06-28 14:47:50 +01001199 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001200
1201 fn as_mut_ptr(&mut self) -> *mut c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001202 self.buffer.as_mut_ptr().cast::<_>()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001203 }
1204
1205 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +00001206 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001207 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001208
1209 fn header(&self) -> &libfdt_bindgen::fdt_header {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001210 let p = self.as_ptr().cast::<_>();
Andrew Walbran84b9a232023-07-05 14:01:40 +00001211 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001212 unsafe { &*p }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001213 }
1214
1215 fn totalsize(&self) -> usize {
1216 u32::from_be(self.header().totalsize) as usize
1217 }
David Brazdil1baa9a92022-06-28 14:47:50 +01001218}