blob: b36939083b389337362b25fabd88045da8f52be5 [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 Kim72d10902023-10-12 21:59:26 +090023 AddressRange, CellIterator, CompatibleIterator, MemRegIterator, PropertyIterator,
24 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;
30use core::mem;
Alice Wang2422bdc2023-06-12 08:37:55 +000031use core::ops::Range;
Jaewan Kim5b057772023-10-19 01:02:17 +090032use core::ptr;
David Brazdil1baa9a92022-06-28 14:47:50 +010033use core::result;
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +000034use zerocopy::AsBytes as _;
David Brazdil1baa9a92022-06-28 14:47:50 +010035
Jaewan Kimb635bb02023-11-01 13:00:34 +090036// TODO(b/308694211): Use cstr!() from vmbase
37macro_rules! cstr {
38 ($str:literal) => {{
39 core::ffi::CStr::from_bytes_with_nul(concat!($str, "\0").as_bytes()).unwrap()
40 }};
41}
42
David Brazdil1baa9a92022-06-28 14:47:50 +010043/// Error type corresponding to libfdt error codes.
44#[derive(Clone, Copy, Debug, Eq, PartialEq)]
45pub enum FdtError {
46 /// FDT_ERR_NOTFOUND
47 NotFound,
48 /// FDT_ERR_EXISTS
49 Exists,
50 /// FDT_ERR_NOSPACE
51 NoSpace,
52 /// FDT_ERR_BADOFFSET
53 BadOffset,
54 /// FDT_ERR_BADPATH
55 BadPath,
56 /// FDT_ERR_BADPHANDLE
57 BadPhandle,
58 /// FDT_ERR_BADSTATE
59 BadState,
60 /// FDT_ERR_TRUNCATED
61 Truncated,
62 /// FDT_ERR_BADMAGIC
63 BadMagic,
64 /// FDT_ERR_BADVERSION
65 BadVersion,
66 /// FDT_ERR_BADSTRUCTURE
67 BadStructure,
68 /// FDT_ERR_BADLAYOUT
69 BadLayout,
70 /// FDT_ERR_INTERNAL
71 Internal,
72 /// FDT_ERR_BADNCELLS
73 BadNCells,
74 /// FDT_ERR_BADVALUE
75 BadValue,
76 /// FDT_ERR_BADOVERLAY
77 BadOverlay,
78 /// FDT_ERR_NOPHANDLES
79 NoPhandles,
80 /// FDT_ERR_BADFLAGS
81 BadFlags,
82 /// FDT_ERR_ALIGNMENT
83 Alignment,
84 /// Unexpected error code
85 Unknown(i32),
86}
87
88impl fmt::Display for FdtError {
89 /// Prints error messages from libfdt.h documentation.
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 match self {
92 Self::NotFound => write!(f, "The requested node or property does not exist"),
93 Self::Exists => write!(f, "Attempted to create an existing node or property"),
94 Self::NoSpace => write!(f, "Insufficient buffer space to contain the expanded tree"),
95 Self::BadOffset => write!(f, "Structure block offset is out-of-bounds or invalid"),
96 Self::BadPath => write!(f, "Badly formatted path"),
97 Self::BadPhandle => write!(f, "Invalid phandle length or value"),
98 Self::BadState => write!(f, "Received incomplete device tree"),
99 Self::Truncated => write!(f, "Device tree or sub-block is improperly terminated"),
100 Self::BadMagic => write!(f, "Device tree header missing its magic number"),
101 Self::BadVersion => write!(f, "Device tree has a version which can't be handled"),
102 Self::BadStructure => write!(f, "Device tree has a corrupt structure block"),
103 Self::BadLayout => write!(f, "Device tree sub-blocks in unsupported order"),
104 Self::Internal => write!(f, "libfdt has failed an internal assertion"),
105 Self::BadNCells => write!(f, "Bad format or value of #address-cells or #size-cells"),
106 Self::BadValue => write!(f, "Unexpected property value"),
107 Self::BadOverlay => write!(f, "Overlay cannot be applied"),
108 Self::NoPhandles => write!(f, "Device tree doesn't have any phandle available anymore"),
109 Self::BadFlags => write!(f, "Invalid flag or invalid combination of flags"),
110 Self::Alignment => write!(f, "Device tree base address is not 8-byte aligned"),
111 Self::Unknown(e) => write!(f, "Unknown libfdt error '{e}'"),
112 }
113 }
114}
115
116/// Result type with FdtError enum.
117pub type Result<T> = result::Result<T, FdtError>;
118
119fn fdt_err(val: c_int) -> Result<c_int> {
120 if val >= 0 {
121 Ok(val)
122 } else {
123 Err(match -val as _ {
124 libfdt_bindgen::FDT_ERR_NOTFOUND => FdtError::NotFound,
125 libfdt_bindgen::FDT_ERR_EXISTS => FdtError::Exists,
126 libfdt_bindgen::FDT_ERR_NOSPACE => FdtError::NoSpace,
127 libfdt_bindgen::FDT_ERR_BADOFFSET => FdtError::BadOffset,
128 libfdt_bindgen::FDT_ERR_BADPATH => FdtError::BadPath,
129 libfdt_bindgen::FDT_ERR_BADPHANDLE => FdtError::BadPhandle,
130 libfdt_bindgen::FDT_ERR_BADSTATE => FdtError::BadState,
131 libfdt_bindgen::FDT_ERR_TRUNCATED => FdtError::Truncated,
132 libfdt_bindgen::FDT_ERR_BADMAGIC => FdtError::BadMagic,
133 libfdt_bindgen::FDT_ERR_BADVERSION => FdtError::BadVersion,
134 libfdt_bindgen::FDT_ERR_BADSTRUCTURE => FdtError::BadStructure,
135 libfdt_bindgen::FDT_ERR_BADLAYOUT => FdtError::BadLayout,
136 libfdt_bindgen::FDT_ERR_INTERNAL => FdtError::Internal,
137 libfdt_bindgen::FDT_ERR_BADNCELLS => FdtError::BadNCells,
138 libfdt_bindgen::FDT_ERR_BADVALUE => FdtError::BadValue,
139 libfdt_bindgen::FDT_ERR_BADOVERLAY => FdtError::BadOverlay,
140 libfdt_bindgen::FDT_ERR_NOPHANDLES => FdtError::NoPhandles,
141 libfdt_bindgen::FDT_ERR_BADFLAGS => FdtError::BadFlags,
142 libfdt_bindgen::FDT_ERR_ALIGNMENT => FdtError::Alignment,
143 _ => FdtError::Unknown(val),
144 })
145 }
146}
147
148fn fdt_err_expect_zero(val: c_int) -> Result<()> {
149 match fdt_err(val)? {
150 0 => Ok(()),
151 _ => Err(FdtError::Unknown(val)),
152 }
153}
154
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000155fn fdt_err_or_option(val: c_int) -> Result<Option<c_int>> {
156 match fdt_err(val) {
157 Ok(val) => Ok(Some(val)),
158 Err(FdtError::NotFound) => Ok(None),
159 Err(e) => Err(e),
160 }
161}
162
David Brazdil1baa9a92022-06-28 14:47:50 +0100163/// Value of a #address-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000164#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100165enum AddrCells {
166 Single = 1,
167 Double = 2,
Andrew Walbranb39e6922022-12-05 17:01:20 +0000168 Triple = 3,
David Brazdil1baa9a92022-06-28 14:47:50 +0100169}
170
171impl TryFrom<c_int> for AddrCells {
172 type Error = FdtError;
173
174 fn try_from(res: c_int) -> Result<Self> {
175 match fdt_err(res)? {
176 x if x == Self::Single as c_int => Ok(Self::Single),
177 x if x == Self::Double as c_int => Ok(Self::Double),
Andrew Walbranb39e6922022-12-05 17:01:20 +0000178 x if x == Self::Triple as c_int => Ok(Self::Triple),
David Brazdil1baa9a92022-06-28 14:47:50 +0100179 _ => Err(FdtError::BadNCells),
180 }
181 }
182}
183
184/// Value of a #size-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000185#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100186enum SizeCells {
187 None = 0,
188 Single = 1,
189 Double = 2,
190}
191
192impl TryFrom<c_int> for SizeCells {
193 type Error = FdtError;
194
195 fn try_from(res: c_int) -> Result<Self> {
196 match fdt_err(res)? {
197 x if x == Self::None as c_int => Ok(Self::None),
198 x if x == Self::Single as c_int => Ok(Self::Single),
199 x if x == Self::Double as c_int => Ok(Self::Double),
200 _ => Err(FdtError::BadNCells),
201 }
202 }
203}
204
Jaewan Kim72d10902023-10-12 21:59:26 +0900205/// DT property wrapper to abstract endianess changes
206#[repr(transparent)]
207#[derive(Debug)]
208struct FdtPropertyStruct(libfdt_bindgen::fdt_property);
209
210impl FdtPropertyStruct {
211 fn from_offset(fdt: &Fdt, offset: c_int) -> Result<&Self> {
212 let mut len = 0;
213 let prop =
214 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
215 unsafe { libfdt_bindgen::fdt_get_property_by_offset(fdt.as_ptr(), offset, &mut len) };
216 if prop.is_null() {
217 fdt_err(len)?;
218 return Err(FdtError::Internal); // shouldn't happen.
219 }
220 // SAFETY: prop is only returned when it points to valid libfdt_bindgen.
221 Ok(unsafe { &*prop.cast::<FdtPropertyStruct>() })
222 }
223
224 fn name_offset(&self) -> c_int {
225 u32::from_be(self.0.nameoff).try_into().unwrap()
226 }
227
228 fn data_len(&self) -> usize {
229 u32::from_be(self.0.len).try_into().unwrap()
230 }
231
232 fn data_ptr(&self) -> *const c_void {
233 self.0.data.as_ptr().cast::<_>()
234 }
235}
236
237/// DT property.
238#[derive(Clone, Copy, Debug)]
239pub struct FdtProperty<'a> {
240 fdt: &'a Fdt,
241 offset: c_int,
242 property: &'a FdtPropertyStruct,
243}
244
245impl<'a> FdtProperty<'a> {
246 fn new(fdt: &'a Fdt, offset: c_int) -> Result<Self> {
247 let property = FdtPropertyStruct::from_offset(fdt, offset)?;
248 Ok(Self { fdt, offset, property })
249 }
250
251 /// Returns the property name
252 pub fn name(&self) -> Result<&'a CStr> {
253 self.fdt.string(self.property.name_offset())
254 }
255
256 /// Returns the property value
257 pub fn value(&self) -> Result<&'a [u8]> {
258 self.fdt.get_from_ptr(self.property.data_ptr(), self.property.data_len())
259 }
260
261 fn next_property(&self) -> Result<Option<Self>> {
262 let ret =
263 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
264 unsafe { libfdt_bindgen::fdt_next_property_offset(self.fdt.as_ptr(), self.offset) };
265
266 fdt_err_or_option(ret)?.map(|offset| Self::new(self.fdt, offset)).transpose()
267 }
268}
269
David Brazdil1baa9a92022-06-28 14:47:50 +0100270/// DT node.
Alice Wang9d4df702023-05-25 14:14:12 +0000271#[derive(Clone, Copy, Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100272pub struct FdtNode<'a> {
273 fdt: &'a Fdt,
274 offset: c_int,
275}
276
277impl<'a> FdtNode<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900278 /// Creates immutable node from a mutable node at the same offset.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900279 pub fn from_mut(other: &'a FdtNodeMut) -> Self {
280 FdtNode { fdt: other.fdt, offset: other.offset }
281 }
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900282 /// Returns parent node.
David Brazdil1baa9a92022-06-28 14:47:50 +0100283 pub fn parent(&self) -> Result<Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000284 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
David Brazdil1baa9a92022-06-28 14:47:50 +0100285 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
286
287 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
288 }
289
Jaewan Kim5b057772023-10-19 01:02:17 +0900290 /// Returns supernode with depth. Note that root is at depth 0.
291 pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
292 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
293 let ret = unsafe {
294 libfdt_bindgen::fdt_supernode_atdepth_offset(
295 self.fdt.as_ptr(),
296 self.offset,
297 depth.try_into().unwrap(),
298 ptr::null_mut(),
299 )
300 };
301
302 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
303 }
304
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900305 /// Returns the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000306 pub fn device_type(&self) -> Result<Option<&CStr>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900307 self.getprop_str(cstr!("device_type"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100308 }
309
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900310 /// Returns the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000311 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900312 let reg = cstr!("reg");
David Brazdil1baa9a92022-06-28 14:47:50 +0100313
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000314 if let Some(cells) = self.getprop_cells(reg)? {
315 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100316
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000317 let addr_cells = parent.address_cells()?;
318 let size_cells = parent.size_cells()?;
319
320 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
321 } else {
322 Ok(None)
323 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100324 }
325
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900326 /// Returns the standard ranges property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000327 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900328 let ranges = cstr!("ranges");
Andrew Walbranb39e6922022-12-05 17:01:20 +0000329 if let Some(cells) = self.getprop_cells(ranges)? {
330 let parent = self.parent()?;
331 let addr_cells = self.address_cells()?;
332 let parent_addr_cells = parent.address_cells()?;
333 let size_cells = self.size_cells()?;
334 Ok(Some(RangesIterator::<A, P, S>::new(
335 cells,
336 addr_cells,
337 parent_addr_cells,
338 size_cells,
339 )))
340 } else {
341 Ok(None)
342 }
343 }
344
Jaewan Kimaa638702023-09-19 13:34:01 +0900345 /// Returns the node name.
346 pub fn name(&self) -> Result<&'a CStr> {
347 let mut len: c_int = 0;
348 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor). On success, the
349 // function returns valid null terminating string and otherwise returned values are dropped.
350 let name = unsafe { libfdt_bindgen::fdt_get_name(self.fdt.as_ptr(), self.offset, &mut len) }
351 as *const c_void;
352 let len = usize::try_from(fdt_err(len)?).unwrap();
353 let name = self.fdt.get_from_ptr(name, len + 1)?;
354 CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
355 }
356
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900357 /// Returns the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000358 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
359 let value = if let Some(bytes) = self.getprop(name)? {
360 Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?)
361 } else {
362 None
363 };
364 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100365 }
366
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900367 /// Returns the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000368 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
369 if let Some(cells) = self.getprop(name)? {
370 Ok(Some(CellIterator::new(cells)))
371 } else {
372 Ok(None)
373 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100374 }
375
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900376 /// Returns the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000377 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
378 let value = if let Some(bytes) = self.getprop(name)? {
379 Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
380 } else {
381 None
382 };
383 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100384 }
385
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900386 /// Returns the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000387 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
388 let value = if let Some(bytes) = self.getprop(name)? {
389 Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?))
390 } else {
391 None
392 };
393 Ok(value)
David Brazdil1baa9a92022-06-28 14:47:50 +0100394 }
395
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900396 /// Returns the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000397 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900398 if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
Jaewan Kimaa638702023-09-19 13:34:01 +0900399 Ok(Some(self.fdt.get_from_ptr(prop, len)?))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900400 } else {
401 Ok(None) // property was not found
402 }
403 }
404
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900405 /// Returns the pointer and size of the property named `name`, in a node at offset `offset`, in
Jiyong Park9c63cd12023-03-21 17:53:07 +0900406 /// a device tree `fdt`. The pointer is guaranteed to be non-null, in which case error returns.
407 fn getprop_internal(
408 fdt: &'a Fdt,
409 offset: c_int,
410 name: &CStr,
411 ) -> Result<Option<(*const c_void, usize)>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100412 let mut len: i32 = 0;
Andrew Walbran84b9a232023-07-05 14:01:40 +0000413 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +0100414 // function respects the passed number of characters.
415 let prop = unsafe {
416 libfdt_bindgen::fdt_getprop_namelen(
Jiyong Park9c63cd12023-03-21 17:53:07 +0900417 fdt.as_ptr(),
418 offset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100419 name.as_ptr(),
420 // *_namelen functions don't include the trailing nul terminator in 'len'.
421 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
422 &mut len as *mut i32,
423 )
424 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000425
426 let Some(len) = fdt_err_or_option(len)? else {
427 return Ok(None); // Property was not found.
428 };
Jaewan Kimaa638702023-09-19 13:34:01 +0900429 let len = usize::try_from(len).unwrap();
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000430
David Brazdil1baa9a92022-06-28 14:47:50 +0100431 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000432 // We expected an error code in len but still received a valid value?!
433 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100434 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900435 Ok(Some((prop.cast::<c_void>(), len)))
David Brazdil1baa9a92022-06-28 14:47:50 +0100436 }
437
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900438 /// Returns reference to the containing device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100439 pub fn fdt(&self) -> &Fdt {
440 self.fdt
441 }
442
Alice Wang474c0ee2023-09-14 12:52:33 +0000443 /// Returns the compatible node of the given name that is next after this node.
444 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000445 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000446 let ret = unsafe {
447 libfdt_bindgen::fdt_node_offset_by_compatible(
448 self.fdt.as_ptr(),
449 self.offset,
450 compatible.as_ptr(),
451 )
452 };
453
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000454 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000455 }
456
Alice Wang474c0ee2023-09-14 12:52:33 +0000457 /// Returns the first range of `reg` in this node.
458 pub fn first_reg(&self) -> Result<Reg<u64>> {
459 self.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
460 }
461
David Brazdil1baa9a92022-06-28 14:47:50 +0100462 fn address_cells(&self) -> Result<AddrCells> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000463 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
David Brazdil1baa9a92022-06-28 14:47:50 +0100464 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
465 .try_into()
466 .map_err(|_| FdtError::Internal)
467 }
468
469 fn size_cells(&self) -> Result<SizeCells> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000470 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
David Brazdil1baa9a92022-06-28 14:47:50 +0100471 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
472 .try_into()
473 .map_err(|_| FdtError::Internal)
474 }
Jaewan Kimbc828d72023-09-19 15:52:08 +0900475
476 /// Returns an iterator of subnodes
477 pub fn subnodes(&'a self) -> Result<SubnodeIterator<'a>> {
478 SubnodeIterator::new(self)
479 }
480
481 fn first_subnode(&self) -> Result<Option<Self>> {
482 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
483 let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
484
485 Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
486 }
487
488 fn next_subnode(&self) -> Result<Option<Self>> {
489 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
490 let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
491
492 Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
493 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900494
495 /// Returns an iterator of properties
496 pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
497 PropertyIterator::new(self)
498 }
499
500 fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
501 let ret =
502 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
503 unsafe { libfdt_bindgen::fdt_first_property_offset(self.fdt.as_ptr(), self.offset) };
504
505 fdt_err_or_option(ret)?.map(|offset| FdtProperty::new(self.fdt, offset)).transpose()
506 }
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900507
508 /// Returns the phandle
509 pub fn get_phandle(&self) -> Result<Option<Phandle>> {
510 // This rewrites the fdt_get_phandle() because it doesn't return error code.
511 if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
512 Ok(Some(prop.try_into()?))
513 } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
514 Ok(Some(prop.try_into()?))
515 } else {
516 Ok(None)
517 }
518 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100519}
520
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000521impl<'a> PartialEq for FdtNode<'a> {
522 fn eq(&self, other: &Self) -> bool {
523 self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
524 }
525}
526
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900527/// Phandle of a FDT node
528#[repr(transparent)]
529#[derive(Debug, Copy, Clone, PartialEq)]
530pub struct Phandle(u32);
531
532impl Phandle {
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000533 /// Minimum valid value for device tree phandles.
534 pub const MIN: Self = Self(1);
535 /// Maximum valid value for device tree phandles.
536 pub const MAX: Self = Self(libfdt_bindgen::FDT_MAX_PHANDLE);
537
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900538 /// Creates a new Phandle
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000539 pub const fn new(value: u32) -> Option<Self> {
540 if Self::MIN.0 <= value && value <= Self::MAX.0 {
541 Some(Self(value))
542 } else {
543 None
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900544 }
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900545 }
546}
547
548impl From<Phandle> for u32 {
549 fn from(phandle: Phandle) -> u32 {
550 phandle.0
551 }
552}
553
Pierre-Clément Tosieba27792023-10-30 12:04:12 +0000554impl TryFrom<u32> for Phandle {
555 type Error = FdtError;
556
557 fn try_from(value: u32) -> Result<Self> {
558 Self::new(value).ok_or(FdtError::BadPhandle)
559 }
560}
561
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000562/// Mutable FDT node.
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000563#[derive(Debug)]
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000564pub struct FdtNodeMut<'a> {
565 fdt: &'a mut Fdt,
566 offset: c_int,
567}
568
569impl<'a> FdtNodeMut<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900570 /// Appends a property name-value (possibly empty) pair to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000571 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000572 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000573 let ret = unsafe {
574 libfdt_bindgen::fdt_appendprop(
575 self.fdt.as_mut_ptr(),
576 self.offset,
577 name.as_ptr(),
578 value.as_ref().as_ptr().cast::<c_void>(),
579 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
580 )
581 };
582
583 fdt_err_expect_zero(ret)
584 }
585
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900586 /// Appends a (address, size) pair property to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000587 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000588 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000589 let ret = unsafe {
590 libfdt_bindgen::fdt_appendprop_addrrange(
591 self.fdt.as_mut_ptr(),
592 self.parent()?.offset,
593 self.offset,
594 name.as_ptr(),
595 addr,
596 size,
597 )
598 };
599
600 fdt_err_expect_zero(ret)
601 }
602
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900603 /// Sets a property name-value pair to the given node.
604 ///
605 /// This may create a new prop or replace existing value.
Jaewan Kimba8929b2023-01-13 11:13:29 +0900606 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000607 // SAFETY: New value size is constrained to the DT totalsize
Jaewan Kimba8929b2023-01-13 11:13:29 +0900608 // (validated by underlying libfdt).
609 let ret = unsafe {
610 libfdt_bindgen::fdt_setprop(
611 self.fdt.as_mut_ptr(),
612 self.offset,
613 name.as_ptr(),
614 value.as_ptr().cast::<c_void>(),
615 value.len().try_into().map_err(|_| FdtError::BadValue)?,
616 )
617 };
618
619 fdt_err_expect_zero(ret)
620 }
621
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900622 /// Sets the value of the given property with the given value, and ensure that the given
623 /// value has the same length as the current value length.
624 ///
625 /// This can only be used to replace existing value.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900626 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000627 // SAFETY: fdt size is not altered
Jiyong Park9c63cd12023-03-21 17:53:07 +0900628 let ret = unsafe {
629 libfdt_bindgen::fdt_setprop_inplace(
630 self.fdt.as_mut_ptr(),
631 self.offset,
632 name.as_ptr(),
633 value.as_ptr().cast::<c_void>(),
634 value.len().try_into().map_err(|_| FdtError::BadValue)?,
635 )
636 };
637
638 fdt_err_expect_zero(ret)
639 }
640
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900641 /// Sets the value of the given (address, size) pair property with the given value, and
642 /// ensure that the given value has the same length as the current value length.
643 ///
644 /// This can only be used to replace existing value.
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000645 pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
646 let pair = [addr.to_be(), size.to_be()];
647 self.setprop_inplace(name, pair.as_bytes())
648 }
649
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900650 /// Sets a flag-like empty property.
651 ///
652 /// This may create a new prop or replace existing value.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000653 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
654 self.setprop(name, &[])
655 }
656
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900657 /// Deletes the given property.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000658 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000659 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000660 // library locates the node's property. Removing the property may shift the offsets of
661 // other nodes and properties but the borrow checker should prevent this function from
662 // being called when FdtNode instances are in use.
663 let ret = unsafe {
664 libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
665 };
666
667 fdt_err_expect_zero(ret)
668 }
669
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900670 /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000671 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000672 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000673 // library locates the node's property.
674 let ret = unsafe {
675 libfdt_bindgen::fdt_nop_property(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
676 };
677
678 fdt_err_expect_zero(ret)
679 }
680
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900681 /// Trims the size of the given property to new_size.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900682 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
683 let (prop, len) =
684 FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
685 if len == new_size {
686 return Ok(());
687 }
688 if new_size > len {
689 return Err(FdtError::NoSpace);
690 }
691
Andrew Walbran84b9a232023-07-05 14:01:40 +0000692 // SAFETY: new_size is smaller than the old size
Jiyong Park9c63cd12023-03-21 17:53:07 +0900693 let ret = unsafe {
694 libfdt_bindgen::fdt_setprop(
695 self.fdt.as_mut_ptr(),
696 self.offset,
697 name.as_ptr(),
698 prop.cast::<c_void>(),
699 new_size.try_into().map_err(|_| FdtError::BadValue)?,
700 )
701 };
702
703 fdt_err_expect_zero(ret)
704 }
705
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900706 /// Returns reference to the containing device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000707 pub fn fdt(&mut self) -> &mut Fdt {
708 self.fdt
709 }
710
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900711 /// Returns immutable FdtNode of this node.
712 pub fn as_node(&self) -> FdtNode {
713 FdtNode { fdt: self.fdt, offset: self.offset }
714 }
715
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900716 /// 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 +0000717 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
Jaewan Kim5ab13582023-10-20 20:56:27 +0900718 let offset = self.add_subnode_offset(name.to_bytes())?;
719 Ok(Self { fdt: self.fdt, offset })
720 }
721
722 /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
723 /// on success.
724 pub fn add_subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Self> {
725 let offset = { self.add_subnode_offset(&name.to_bytes()[..namelen])? };
726 Ok(Self { fdt: self.fdt, offset })
727 }
728
729 fn add_subnode_offset(&mut self, name: &[u8]) -> Result<c_int> {
730 let namelen = name.len().try_into().unwrap();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000731 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000732 let ret = unsafe {
Jaewan Kim5ab13582023-10-20 20:56:27 +0900733 libfdt_bindgen::fdt_add_subnode_namelen(
734 self.fdt.as_mut_ptr(),
735 self.offset,
736 name.as_ptr().cast::<_>(),
737 namelen,
738 )
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000739 };
Jaewan Kim5ab13582023-10-20 20:56:27 +0900740 fdt_err(ret)
741 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000742
Jaewan Kim5ab13582023-10-20 20:56:27 +0900743 /// Returns the subnode of the given name with len.
744 pub fn subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Option<Self>> {
745 let offset = self.subnode_offset(&name.to_bytes()[..namelen])?;
746 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
747 }
748
749 fn subnode_offset(&self, name: &[u8]) -> Result<Option<c_int>> {
750 let namelen = name.len().try_into().unwrap();
751 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
752 let ret = unsafe {
753 libfdt_bindgen::fdt_subnode_offset_namelen(
754 self.fdt.as_ptr(),
755 self.offset,
756 name.as_ptr().cast::<_>(),
757 namelen,
758 )
759 };
760 fdt_err_or_option(ret)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000761 }
762
763 fn parent(&'a self) -> Result<FdtNode<'a>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000764 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000765 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
766
767 Ok(FdtNode { fdt: &*self.fdt, offset: fdt_err(ret)? })
768 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900769
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900770 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900771 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000772 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900773 let ret = unsafe {
774 libfdt_bindgen::fdt_node_offset_by_compatible(
775 self.fdt.as_ptr(),
776 self.offset,
777 compatible.as_ptr(),
778 )
779 };
780
781 Ok(fdt_err_or_option(ret)?.map(|offset| Self { fdt: self.fdt, offset }))
782 }
783
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900784 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
785 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900786 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
787 // The reason is that libfdt ensures that the node from where the search for the next
788 // compatible node is started is always a valid one -- except for the special case of offset =
789 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
790 // next compatible node from it.
791 //
792 // We can't do in the opposite direction either. If we call next_compatible to find the next
793 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
794 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
795 // DT).
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900796 pub fn delete_and_next_compatible(mut self, compatible: &CStr) -> Result<Option<Self>> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000797 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900798 let ret = unsafe {
799 libfdt_bindgen::fdt_node_offset_by_compatible(
800 self.fdt.as_ptr(),
801 self.offset,
802 compatible.as_ptr(),
803 )
804 };
805 let next_offset = fdt_err_or_option(ret)?;
806
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900807 if Some(self.offset) == next_offset {
808 return Err(FdtError::Internal);
809 }
810
811 // SAFETY: nop_self() only touches bytes of the self and its properties and subnodes, and
812 // doesn't alter any other blob in the tree. self.fdt and next_offset would remain valid.
813 unsafe { self.nop_self()? };
Jiyong Park9c63cd12023-03-21 17:53:07 +0900814
815 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
816 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900817
818 /// Deletes this node effectively from DT, by setting it with FDT_NOP
819 pub fn nop(mut self) -> Result<()> {
820 // SAFETY: This consumes self, so invalid node wouldn't be used any further
821 unsafe { self.nop_self() }
822 }
823
824 /// Deletes this node effectively from DT, by setting it with FDT_NOP.
825 /// This only changes bytes of the node and its properties and subnodes, and doesn't alter or
826 /// move any other part of the tree.
827 /// SAFETY: This node is no longer valid.
828 unsafe fn nop_self(&mut self) -> Result<()> {
829 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
830 let ret = unsafe { libfdt_bindgen::fdt_nop_node(self.fdt.as_mut_ptr(), self.offset) };
831
832 fdt_err_expect_zero(ret)
833 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000834}
835
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000836/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000837#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100838#[repr(transparent)]
839pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000840 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100841}
842
843impl Fdt {
844 /// Wraps a slice containing a Flattened Device Tree.
845 ///
846 /// Fails if the FDT does not pass validation.
847 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000848 // SAFETY: The FDT will be validated before it is returned.
David Brazdil1baa9a92022-06-28 14:47:50 +0100849 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
850 fdt.check_full()?;
851 Ok(fdt)
852 }
853
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000854 /// Wraps a mutable slice containing a Flattened Device Tree.
855 ///
856 /// Fails if the FDT does not pass validation.
857 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000858 // SAFETY: The FDT will be validated before it is returned.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000859 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
860 fdt.check_full()?;
861 Ok(fdt)
862 }
863
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900864 /// Creates an empty Flattened Device Tree with a mutable slice.
865 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000866 // SAFETY: fdt_create_empty_tree() only write within the specified length,
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900867 // and returns error if buffer was insufficient.
868 // There will be no memory write outside of the given fdt.
869 let ret = unsafe {
870 libfdt_bindgen::fdt_create_empty_tree(
871 fdt.as_mut_ptr().cast::<c_void>(),
872 fdt.len() as i32,
873 )
874 };
875 fdt_err_expect_zero(ret)?;
876
Andrew Walbran84b9a232023-07-05 14:01:40 +0000877 // SAFETY: The FDT will be validated before it is returned.
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900878 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
879 fdt.check_full()?;
880
881 Ok(fdt)
882 }
883
David Brazdil1baa9a92022-06-28 14:47:50 +0100884 /// Wraps a slice containing a Flattened Device Tree.
885 ///
886 /// # Safety
887 ///
888 /// The returned FDT might be invalid, only use on slices containing a valid DT.
889 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000890 // SAFETY: Fdt is a wrapper around a [u8], so the transmute is valid. The caller is
891 // responsible for ensuring that it is actually a valid FDT.
892 unsafe { mem::transmute::<&[u8], &Self>(fdt) }
David Brazdil1baa9a92022-06-28 14:47:50 +0100893 }
894
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000895 /// Wraps a mutable slice containing a Flattened Device Tree.
896 ///
897 /// # Safety
898 ///
899 /// The returned FDT might be invalid, only use on slices containing a valid DT.
900 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000901 // SAFETY: Fdt is a wrapper around a [u8], so the transmute is valid. The caller is
902 // responsible for ensuring that it is actually a valid FDT.
903 unsafe { mem::transmute::<&mut [u8], &mut Self>(fdt) }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000904 }
905
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900906 /// Updates this FDT from a slice containing another FDT.
Jiyong Parke9d87e82023-03-21 19:28:40 +0900907 pub fn copy_from_slice(&mut self, new_fdt: &[u8]) -> Result<()> {
908 if self.buffer.len() < new_fdt.len() {
909 Err(FdtError::NoSpace)
910 } else {
911 let totalsize = self.totalsize();
912 self.buffer[..new_fdt.len()].clone_from_slice(new_fdt);
913 // Zeroize the remaining part. We zeroize up to the size of the original DT because
914 // zeroizing the entire buffer (max 2MB) is not necessary and may increase the VM boot
915 // time.
916 self.buffer[new_fdt.len()..max(new_fdt.len(), totalsize)].fill(0_u8);
917 Ok(())
918 }
919 }
920
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900921 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000922 pub fn unpack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000923 // SAFETY: "Opens" the DT in-place (supported use-case) by updating its header and
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000924 // internal structures to make use of the whole self.fdt slice but performs no accesses
925 // outside of it and leaves the DT in a state that will be detected by other functions.
926 let ret = unsafe {
927 libfdt_bindgen::fdt_open_into(
928 self.as_ptr(),
929 self.as_mut_ptr(),
930 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
931 )
932 };
933 fdt_err_expect_zero(ret)
934 }
935
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900936 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000937 ///
938 /// Doesn't shrink the underlying memory slice.
939 pub fn pack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000940 // SAFETY: "Closes" the DT in-place by updating its header and relocating its structs.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000941 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
942 fdt_err_expect_zero(ret)
943 }
944
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000945 /// Applies a DT overlay on the base DT.
946 ///
947 /// # Safety
948 ///
949 /// On failure, the library corrupts the DT and overlay so both must be discarded.
950 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000951 let ret =
952 // SAFETY: Both pointers are valid because they come from references, and fdt_overlay_apply
953 // doesn't keep them after it returns. It may corrupt their contents if there is an error,
954 // but that's our caller's responsibility.
955 unsafe { libfdt_bindgen::fdt_overlay_apply(self.as_mut_ptr(), overlay.as_mut_ptr()) };
956 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000957 Ok(self)
958 }
959
Alice Wang2422bdc2023-06-12 08:37:55 +0000960 /// Returns an iterator of memory banks specified the "/memory" node.
961 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100962 ///
963 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +0000964 pub fn memory(&self) -> Result<MemRegIterator> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900965 let memory_node_name = cstr!("/memory");
966 let memory_device_type = cstr!("memory");
David Brazdil1baa9a92022-06-28 14:47:50 +0100967
Alice Wang2422bdc2023-06-12 08:37:55 +0000968 let node = self.node(memory_node_name)?.ok_or(FdtError::NotFound)?;
969 if node.device_type()? != Some(memory_device_type) {
970 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000971 }
Alice Wang2422bdc2023-06-12 08:37:55 +0000972 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
973 }
974
975 /// Returns the first memory range in the `/memory` node.
976 pub fn first_memory_range(&self) -> Result<Range<usize>> {
977 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +0100978 }
979
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900980 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000981 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900982 self.node(cstr!("/chosen"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100983 }
984
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900985 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000986 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900987 self.node_mut(cstr!("/chosen"))
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000988 }
989
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900990 /// Returns the root node of the tree.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000991 pub fn root(&self) -> Result<FdtNode> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900992 self.node(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000993 }
994
Jaewan Kimf163d762023-11-01 13:12:50 +0900995 /// Returns the standard /__symbols__ node.
996 pub fn symbols(&self) -> Result<Option<FdtNode>> {
997 self.node(cstr!("/__symbols__"))
998 }
999
1000 /// Returns the standard /__symbols__ node as mutable
1001 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
1002 self.node_mut(cstr!("/__symbols__"))
1003 }
1004
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001005 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001006 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Jaewan Kimbab42592023-10-13 15:47:19 +09001007 Ok(self.path_offset(path.to_bytes())?.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +01001008 }
1009
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +00001010 /// Iterate over nodes with a given compatible string.
1011 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
1012 CompatibleIterator::new(self, compatible)
1013 }
1014
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001015 /// Returns max phandle in the tree.
1016 pub fn max_phandle(&self) -> Result<Phandle> {
1017 let mut phandle: u32 = 0;
1018 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
1019 let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(self.as_ptr(), &mut phandle) };
1020
1021 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosieba27792023-10-30 12:04:12 +00001022 phandle.try_into()
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001023 }
1024
1025 /// Returns a node with the phandle
1026 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Jaewan Kimc63246d2023-11-09 15:41:01 +09001027 let offset = self.node_offset_with_phandle(phandle)?;
1028 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
1029 }
1030
1031 /// Returns a mutable node with the phandle
1032 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
1033 let offset = self.node_offset_with_phandle(phandle)?;
1034 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
1035 }
1036
1037 fn node_offset_with_phandle(&self, phandle: Phandle) -> Result<Option<c_int>> {
1038 // SAFETY: Accesses are constrained to the DT totalsize.
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001039 let ret = unsafe { libfdt_bindgen::fdt_node_offset_by_phandle(self.as_ptr(), phandle.0) };
Jaewan Kimc63246d2023-11-09 15:41:01 +09001040 fdt_err_or_option(ret)
Jaewan Kim17ba7a32023-10-19 13:25:15 +09001041 }
1042
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001043 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001044 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
Jaewan Kimb635bb02023-11-01 13:00:34 +09001045 self.node_mut(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001046 }
1047
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001048 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001049 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Jaewan Kimbab42592023-10-13 15:47:19 +09001050 Ok(self.path_offset(path.to_bytes())?.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001051 }
1052
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001053 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001054 pub fn as_slice(&self) -> &[u8] {
1055 &self.buffer[..self.totalsize()]
1056 }
1057
Jaewan Kimbab42592023-10-13 15:47:19 +09001058 fn path_offset(&self, path: &[u8]) -> Result<Option<c_int>> {
1059 let len = path.len().try_into().map_err(|_| FdtError::BadPath)?;
Andrew Walbran84b9a232023-07-05 14:01:40 +00001060 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +01001061 // function respects the passed number of characters.
1062 let ret = unsafe {
1063 // *_namelen functions don't include the trailing nul terminator in 'len'.
Jaewan Kimbab42592023-10-13 15:47:19 +09001064 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr().cast::<_>(), len)
David Brazdil1baa9a92022-06-28 14:47:50 +01001065 };
1066
Pierre-Clément Tosib244d932022-11-24 16:45:53 +00001067 fdt_err_or_option(ret)
David Brazdil1baa9a92022-06-28 14:47:50 +01001068 }
1069
1070 fn check_full(&self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +00001071 // SAFETY: Only performs read accesses within the limits of the slice. If successful, this
David Brazdil1baa9a92022-06-28 14:47:50 +01001072 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
1073 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
1074 // checking. The library doesn't maintain an internal state (such as pointers) between
1075 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
Pierre-Clément Tosi02017da2023-09-26 17:57:04 +01001076 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), self.capacity()) };
David Brazdil1baa9a92022-06-28 14:47:50 +01001077 fdt_err_expect_zero(ret)
1078 }
1079
Jaewan Kimaa638702023-09-19 13:34:01 +09001080 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
1081 let ptr = ptr as usize;
1082 let offset = ptr.checked_sub(self.as_ptr() as usize).ok_or(FdtError::Internal)?;
1083 self.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)
1084 }
1085
Jaewan Kim72d10902023-10-12 21:59:26 +09001086 fn string(&self, offset: c_int) -> Result<&CStr> {
1087 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
1088 let res = unsafe { libfdt_bindgen::fdt_string(self.as_ptr(), offset) };
1089 if res.is_null() {
1090 return Err(FdtError::Internal);
1091 }
1092
1093 // SAFETY: Non-null return from fdt_string() is valid null-terminating string within FDT.
1094 Ok(unsafe { CStr::from_ptr(res) })
1095 }
1096
Jaewan Kimb3dcfc22023-09-20 10:20:52 +09001097 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +00001098 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001099 self.buffer.as_ptr().cast::<_>()
David Brazdil1baa9a92022-06-28 14:47:50 +01001100 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001101
1102 fn as_mut_ptr(&mut self) -> *mut c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001103 self.buffer.as_mut_ptr().cast::<_>()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001104 }
1105
1106 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +00001107 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +00001108 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001109
1110 fn header(&self) -> &libfdt_bindgen::fdt_header {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001111 let p = self.as_ptr().cast::<_>();
Andrew Walbran84b9a232023-07-05 14:01:40 +00001112 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +00001113 unsafe { &*p }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +00001114 }
1115
1116 fn totalsize(&self) -> usize {
1117 u32::from_be(self.header().totalsize) as usize
1118 }
David Brazdil1baa9a92022-06-28 14:47:50 +01001119}