blob: 47f481768191fadf5c5f4112fd280fbf16387373 [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;
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +000021mod libfdt;
Pierre-Clément Tosi99a76902023-12-21 10:30:37 +000022mod result;
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +000023mod safe_types;
Andrew Walbran55ad01b2022-12-05 17:00:40 +000024
Jaewan Kimfe06c852023-10-05 23:40:06 +090025pub use iterators::{
Jaewan Kimc9e14112023-12-04 17:05:27 +090026 AddressRange, CellIterator, CompatibleIterator, DescendantsIterator, MemRegIterator,
27 PropertyIterator, RangesIterator, Reg, RegIterator, SubnodeIterator,
Jaewan Kimfe06c852023-10-05 23:40:06 +090028};
Pierre-Clément Tosi99a76902023-12-21 10:30:37 +000029pub use result::{FdtError, Result};
Pierre-Clément Tosi566723a2024-01-24 13:01:54 +000030pub use safe_types::{FdtHeader, NodeOffset, Phandle, PropOffset, StringOffset};
Andrew Walbran55ad01b2022-12-05 17:00:40 +000031
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +000032use core::ffi::{c_void, CStr};
Alice Wang2422bdc2023-06-12 08:37:55 +000033use core::ops::Range;
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +000034use libfdt::get_slice_at_ptr;
Andrew Walbran47d316e2024-11-28 18:41:09 +000035use zerocopy::IntoBytes as _;
David Brazdil1baa9a92022-06-28 14:47:50 +010036
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +000037use crate::libfdt::{Libfdt, LibfdtMut};
38
David Brazdil1baa9a92022-06-28 14:47:50 +010039/// Value of a #address-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +000040#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +010041enum AddrCells {
42 Single = 1,
43 Double = 2,
Andrew Walbranb39e6922022-12-05 17:01:20 +000044 Triple = 3,
David Brazdil1baa9a92022-06-28 14:47:50 +010045}
46
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000047impl TryFrom<usize> for AddrCells {
David Brazdil1baa9a92022-06-28 14:47:50 +010048 type Error = FdtError;
49
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000050 fn try_from(value: usize) -> Result<Self> {
51 match value {
52 x if x == Self::Single as _ => Ok(Self::Single),
53 x if x == Self::Double as _ => Ok(Self::Double),
54 x if x == Self::Triple as _ => Ok(Self::Triple),
David Brazdil1baa9a92022-06-28 14:47:50 +010055 _ => Err(FdtError::BadNCells),
56 }
57 }
58}
59
60/// Value of a #size-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +000061#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +010062enum SizeCells {
63 None = 0,
64 Single = 1,
65 Double = 2,
66}
67
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000068impl TryFrom<usize> for SizeCells {
David Brazdil1baa9a92022-06-28 14:47:50 +010069 type Error = FdtError;
70
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000071 fn try_from(value: usize) -> Result<Self> {
72 match value {
73 x if x == Self::None as _ => Ok(Self::None),
74 x if x == Self::Single as _ => Ok(Self::Single),
75 x if x == Self::Double as _ => Ok(Self::Double),
David Brazdil1baa9a92022-06-28 14:47:50 +010076 _ => Err(FdtError::BadNCells),
77 }
78 }
79}
80
Jaewan Kim72d10902023-10-12 21:59:26 +090081/// DT property wrapper to abstract endianess changes
82#[repr(transparent)]
83#[derive(Debug)]
84struct FdtPropertyStruct(libfdt_bindgen::fdt_property);
85
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +000086impl AsRef<FdtPropertyStruct> for libfdt_bindgen::fdt_property {
87 fn as_ref(&self) -> &FdtPropertyStruct {
88 let ptr = self as *const _ as *const _;
89 // SAFETY: Types have the same layout (transparent) so the valid reference remains valid.
90 unsafe { &*ptr }
91 }
92}
93
Jaewan Kim72d10902023-10-12 21:59:26 +090094impl FdtPropertyStruct {
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +000095 fn from_offset(fdt: &Fdt, offset: PropOffset) -> Result<&Self> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +000096 Ok(fdt.get_property_by_offset(offset)?.as_ref())
Jaewan Kim72d10902023-10-12 21:59:26 +090097 }
98
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +000099 fn name_offset(&self) -> StringOffset {
100 StringOffset(u32::from_be(self.0.nameoff).try_into().unwrap())
Jaewan Kim72d10902023-10-12 21:59:26 +0900101 }
102
103 fn data_len(&self) -> usize {
104 u32::from_be(self.0.len).try_into().unwrap()
105 }
106
107 fn data_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000108 self.0.data.as_ptr().cast()
Jaewan Kim72d10902023-10-12 21:59:26 +0900109 }
110}
111
112/// DT property.
113#[derive(Clone, Copy, Debug)]
114pub struct FdtProperty<'a> {
115 fdt: &'a Fdt,
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +0000116 offset: PropOffset,
Jaewan Kim72d10902023-10-12 21:59:26 +0900117 property: &'a FdtPropertyStruct,
118}
119
120impl<'a> FdtProperty<'a> {
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +0000121 fn new(fdt: &'a Fdt, offset: PropOffset) -> Result<Self> {
Jaewan Kim72d10902023-10-12 21:59:26 +0900122 let property = FdtPropertyStruct::from_offset(fdt, offset)?;
123 Ok(Self { fdt, offset, property })
124 }
125
126 /// Returns the property name
127 pub fn name(&self) -> Result<&'a CStr> {
128 self.fdt.string(self.property.name_offset())
129 }
130
131 /// Returns the property value
132 pub fn value(&self) -> Result<&'a [u8]> {
133 self.fdt.get_from_ptr(self.property.data_ptr(), self.property.data_len())
134 }
135
136 fn next_property(&self) -> Result<Option<Self>> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000137 if let Some(offset) = self.fdt.next_property_offset(self.offset)? {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000138 Ok(Some(Self::new(self.fdt, offset)?))
139 } else {
140 Ok(None)
141 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900142 }
143}
144
David Brazdil1baa9a92022-06-28 14:47:50 +0100145/// DT node.
Alice Wang9d4df702023-05-25 14:14:12 +0000146#[derive(Clone, Copy, Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100147pub struct FdtNode<'a> {
148 fdt: &'a Fdt,
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000149 offset: NodeOffset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100150}
151
152impl<'a> FdtNode<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900153 /// Returns parent node.
David Brazdil1baa9a92022-06-28 14:47:50 +0100154 pub fn parent(&self) -> Result<Self> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000155 let offset = self.fdt.parent_offset(self.offset)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100156
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000157 Ok(Self { fdt: self.fdt, offset })
David Brazdil1baa9a92022-06-28 14:47:50 +0100158 }
159
Jaewan Kim5b057772023-10-19 01:02:17 +0900160 /// Returns supernode with depth. Note that root is at depth 0.
161 pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000162 let offset = self.fdt.supernode_atdepth_offset(self.offset, depth)?;
Jaewan Kim5b057772023-10-19 01:02:17 +0900163
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000164 Ok(Self { fdt: self.fdt, offset })
Jaewan Kim5b057772023-10-19 01:02:17 +0900165 }
166
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900167 /// Returns the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000168 pub fn device_type(&self) -> Result<Option<&CStr>> {
Alan Stokesf46a17c2025-01-05 15:50:18 +0000169 self.getprop_str(c"device_type")
David Brazdil1baa9a92022-06-28 14:47:50 +0100170 }
171
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900172 /// Returns the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000173 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
Alan Stokesf46a17c2025-01-05 15:50:18 +0000174 if let Some(cells) = self.getprop_cells(c"reg")? {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000175 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100176
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000177 let addr_cells = parent.address_cells()?;
178 let size_cells = parent.size_cells()?;
179
180 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
181 } else {
182 Ok(None)
183 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100184 }
185
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900186 /// Returns the standard ranges property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000187 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
Alan Stokesf46a17c2025-01-05 15:50:18 +0000188 if let Some(cells) = self.getprop_cells(c"ranges")? {
Andrew Walbranb39e6922022-12-05 17:01:20 +0000189 let parent = self.parent()?;
190 let addr_cells = self.address_cells()?;
191 let parent_addr_cells = parent.address_cells()?;
192 let size_cells = self.size_cells()?;
193 Ok(Some(RangesIterator::<A, P, S>::new(
194 cells,
195 addr_cells,
196 parent_addr_cells,
197 size_cells,
198 )))
199 } else {
200 Ok(None)
201 }
202 }
203
Jaewan Kimaa638702023-09-19 13:34:01 +0900204 /// Returns the node name.
205 pub fn name(&self) -> Result<&'a CStr> {
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +0000206 let name = self.fdt.get_name(self.offset)?;
Jaewan Kimaa638702023-09-19 13:34:01 +0900207 CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
208 }
209
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900210 /// Returns the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000211 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000212 if let Some(bytes) = self.getprop(name)? {
213 Ok(Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000214 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000215 Ok(None)
216 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100217 }
218
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900219 /// Returns the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000220 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
221 if let Some(cells) = self.getprop(name)? {
222 Ok(Some(CellIterator::new(cells)))
223 } else {
224 Ok(None)
225 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100226 }
227
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900228 /// Returns the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000229 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000230 if let Some(bytes) = self.getprop(name)? {
231 Ok(Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000232 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000233 Ok(None)
234 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100235 }
236
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900237 /// Returns the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000238 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000239 if let Some(bytes) = self.getprop(name)? {
240 Ok(Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000241 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000242 Ok(None)
243 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100244 }
245
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900246 /// Returns the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000247 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000248 self.fdt.getprop_namelen(self.offset, name.to_bytes())
David Brazdil1baa9a92022-06-28 14:47:50 +0100249 }
250
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900251 /// Returns reference to the containing device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100252 pub fn fdt(&self) -> &Fdt {
253 self.fdt
254 }
255
Alice Wang474c0ee2023-09-14 12:52:33 +0000256 /// Returns the compatible node of the given name that is next after this node.
257 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000258 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000259
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000260 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000261 }
262
Alice Wang474c0ee2023-09-14 12:52:33 +0000263 /// Returns the first range of `reg` in this node.
264 pub fn first_reg(&self) -> Result<Reg<u64>> {
265 self.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
266 }
267
David Brazdil1baa9a92022-06-28 14:47:50 +0100268 fn address_cells(&self) -> Result<AddrCells> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000269 self.fdt.address_cells(self.offset)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100270 }
271
272 fn size_cells(&self) -> Result<SizeCells> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000273 self.fdt.size_cells(self.offset)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100274 }
Jaewan Kimbc828d72023-09-19 15:52:08 +0900275
276 /// Returns an iterator of subnodes
Jaewan Kim4a34b0d2024-01-19 13:17:47 +0900277 pub fn subnodes(&self) -> Result<SubnodeIterator<'a>> {
Jaewan Kimbc828d72023-09-19 15:52:08 +0900278 SubnodeIterator::new(self)
279 }
280
281 fn first_subnode(&self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000282 let offset = self.fdt.first_subnode(self.offset)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900283
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000284 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900285 }
286
287 fn next_subnode(&self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000288 let offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900289
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000290 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900291 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900292
Jaewan Kimc9e14112023-12-04 17:05:27 +0900293 /// Returns an iterator of descendants
Jaewan Kim1eab7232024-01-04 09:46:16 +0900294 pub fn descendants(&self) -> DescendantsIterator<'a> {
Jaewan Kimc9e14112023-12-04 17:05:27 +0900295 DescendantsIterator::new(self)
296 }
297
298 fn next_node(&self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000299 if let Some((offset, depth)) = self.fdt.next_node(self.offset, depth)? {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000300 Ok(Some((Self { fdt: self.fdt, offset }, depth)))
301 } else {
302 Ok(None)
303 }
Jaewan Kimc9e14112023-12-04 17:05:27 +0900304 }
305
Jaewan Kim72d10902023-10-12 21:59:26 +0900306 /// Returns an iterator of properties
307 pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
308 PropertyIterator::new(self)
309 }
310
311 fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000312 if let Some(offset) = self.fdt.first_property_offset(self.offset)? {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000313 Ok(Some(FdtProperty::new(self.fdt, offset)?))
314 } else {
315 Ok(None)
316 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900317 }
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900318
319 /// Returns the phandle
320 pub fn get_phandle(&self) -> Result<Option<Phandle>> {
321 // This rewrites the fdt_get_phandle() because it doesn't return error code.
Alan Stokesf46a17c2025-01-05 15:50:18 +0000322 if let Some(prop) = self.getprop_u32(c"phandle")? {
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900323 Ok(Some(prop.try_into()?))
Alan Stokesf46a17c2025-01-05 15:50:18 +0000324 } else if let Some(prop) = self.getprop_u32(c"linux,phandle")? {
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900325 Ok(Some(prop.try_into()?))
326 } else {
327 Ok(None)
328 }
329 }
Jaewan Kim52026012023-12-13 13:49:28 +0900330
331 /// Returns the subnode of the given name. The name doesn't need to be nul-terminated.
332 pub fn subnode(&self, name: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000333 let name = name.to_bytes();
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000334 let offset = self.fdt.subnode_offset_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000335
Jaewan Kim52026012023-12-13 13:49:28 +0900336 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
337 }
338
339 /// Returns the subnode of the given name bytes
340 pub fn subnode_with_name_bytes(&self, name: &[u8]) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000341 let offset = self.fdt.subnode_offset_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000342
Jaewan Kim52026012023-12-13 13:49:28 +0900343 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
344 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100345}
346
Chris Wailes73a1eb72025-01-15 11:56:43 -0800347impl PartialEq for FdtNode<'_> {
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000348 fn eq(&self, other: &Self) -> bool {
349 self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
350 }
351}
352
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000353/// Mutable FDT node.
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000354#[derive(Debug)]
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000355pub struct FdtNodeMut<'a> {
356 fdt: &'a mut Fdt,
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000357 offset: NodeOffset,
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000358}
359
360impl<'a> FdtNodeMut<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900361 /// Appends a property name-value (possibly empty) pair to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000362 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000363 self.fdt.appendprop(self.offset, name, value.as_ref())
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000364 }
365
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900366 /// Appends a (address, size) pair property to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000367 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000368 let parent = self.parent()?.offset;
369 self.fdt.appendprop_addrrange(parent, self.offset, name, addr, size)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000370 }
371
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900372 /// Sets a property name-value pair to the given node.
373 ///
374 /// This may create a new prop or replace existing value.
Jaewan Kimba8929b2023-01-13 11:13:29 +0900375 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000376 self.fdt.setprop(self.offset, name, value)
Jaewan Kimba8929b2023-01-13 11:13:29 +0900377 }
378
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900379 /// Sets the value of the given property with the given value, and ensure that the given
380 /// value has the same length as the current value length.
381 ///
382 /// This can only be used to replace existing value.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900383 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000384 self.fdt.setprop_inplace(self.offset, name, value)
Jiyong Park9c63cd12023-03-21 17:53:07 +0900385 }
386
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900387 /// Sets the value of the given (address, size) pair property with the given value, and
388 /// ensure that the given value has the same length as the current value length.
389 ///
390 /// This can only be used to replace existing value.
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000391 pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
392 let pair = [addr.to_be(), size.to_be()];
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000393 self.fdt.setprop_inplace(self.offset, name, pair.as_bytes())
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000394 }
395
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900396 /// Sets a flag-like empty property.
397 ///
398 /// This may create a new prop or replace existing value.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000399 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000400 self.fdt.setprop(self.offset, name, &[])
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000401 }
402
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900403 /// Deletes the given property.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000404 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000405 self.fdt.delprop(self.offset, name)
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000406 }
407
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900408 /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000409 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000410 self.fdt.nop_property(self.offset, name)
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000411 }
412
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900413 /// Trims the size of the given property to new_size.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900414 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
Pierre-Clément Tosi843845d2024-01-23 23:35:01 +0000415 let prop = self.as_node().getprop(name)?.ok_or(FdtError::NotFound)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900416
Pierre-Clément Tosi843845d2024-01-23 23:35:01 +0000417 match prop.len() {
418 x if x == new_size => Ok(()),
419 x if x < new_size => Err(FdtError::NoSpace),
420 _ => self.fdt.setprop_placeholder(self.offset, name, new_size).map(|_| ()),
421 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900422 }
423
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900424 /// Returns reference to the containing device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000425 pub fn fdt(&mut self) -> &mut Fdt {
426 self.fdt
427 }
428
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900429 /// Returns immutable FdtNode of this node.
430 pub fn as_node(&self) -> FdtNode {
431 FdtNode { fdt: self.fdt, offset: self.offset }
432 }
433
Jaewan Kime6363422024-01-19 14:00:00 +0900434 /// Adds new subnodes to the given node.
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +0000435 pub fn add_subnodes(self, names: &[&CStr]) -> Result<()> {
Jaewan Kime6363422024-01-19 14:00:00 +0900436 for name in names {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000437 self.fdt.add_subnode_namelen(self.offset, name.to_bytes())?;
Jaewan Kime6363422024-01-19 14:00:00 +0900438 }
439 Ok(())
440 }
441
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900442 /// Adds a new subnode to the given node and return it as a FdtNodeMut on success.
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +0000443 pub fn add_subnode(self, name: &CStr) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000444 let name = name.to_bytes();
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000445 let offset = self.fdt.add_subnode_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000446
Jaewan Kim5ab13582023-10-20 20:56:27 +0900447 Ok(Self { fdt: self.fdt, offset })
448 }
449
450 /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
451 /// on success.
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +0000452 pub fn add_subnode_with_namelen(self, name: &CStr, namelen: usize) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000453 let name = &name.to_bytes()[..namelen];
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000454 let offset = self.fdt.add_subnode_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000455
Jaewan Kim5ab13582023-10-20 20:56:27 +0900456 Ok(Self { fdt: self.fdt, offset })
457 }
458
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900459 /// Returns the first subnode of this
Pierre-Clément Tosi973dda32024-02-14 16:08:28 +0000460 pub fn first_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000461 let offset = self.fdt.first_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900462
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000463 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900464 }
465
466 /// Returns the next subnode that shares the same parent with this
467 pub fn next_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000468 let offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900469
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000470 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900471 }
472
473 /// Deletes the current node and returns the next subnode
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000474 pub fn delete_and_next_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000475 let next_offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900476
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000477 self.delete_and_next(next_offset)
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900478 }
479
Jaewan Kime2a0bb02024-02-21 15:28:32 +0900480 /// Returns the next node. Use this API to travel descendant of a node.
481 ///
482 /// Returned depth is relative to the initial node that had called with any of next node APIs.
483 /// Returns None if end of FDT reached or depth becomes negative.
484 ///
485 /// See also: [`next_node_skip_subnodes`], and [`delete_and_next_node`]
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900486 pub fn next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000487 let next = self.fdt.next_node(self.offset, depth)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000488
489 Ok(next.map(|(offset, depth)| (Self { fdt: self.fdt, offset }, depth)))
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900490 }
491
Jaewan Kime2a0bb02024-02-21 15:28:32 +0900492 /// Returns the next node skipping subnodes. Use this API to travel descendants of a node while
493 /// ignoring certain node.
494 ///
495 /// Returned depth is relative to the initial node that had called with any of next node APIs.
496 /// Returns None if end of FDT reached or depth becomes negative.
497 ///
498 /// See also: [`next_node`], and [`delete_and_next_node`]
499 pub fn next_node_skip_subnodes(self, depth: usize) -> Result<Option<(Self, usize)>> {
500 let next = self.fdt.next_node_skip_subnodes(self.offset, depth)?;
501
502 Ok(next.map(|(offset, depth)| (Self { fdt: self.fdt, offset }, depth)))
503 }
504
505 /// Deletes this and returns the next node. Use this API to travel descendants of a node while
506 /// removing certain node.
507 ///
508 /// Returned depth is relative to the initial node that had called with any of next node APIs.
509 /// Returns None if end of FDT reached or depth becomes negative.
510 ///
511 /// See also: [`next_node`], and [`next_node_skip_subnodes`]
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000512 pub fn delete_and_next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
513 let next_node = self.fdt.next_node_skip_subnodes(self.offset, depth)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000514 if let Some((offset, depth)) = next_node {
515 let next_node = self.delete_and_next(Some(offset))?.unwrap();
516 Ok(Some((next_node, depth)))
517 } else {
Jaewan Kima5bc8922024-02-20 01:15:37 +0900518 self.delete_and_next(None)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000519 Ok(None)
520 }
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900521 }
522
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000523 fn parent(&'a self) -> Result<FdtNode<'a>> {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000524 self.as_node().parent()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000525 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900526
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900527 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900528 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000529 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900530
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000531 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900532 }
533
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900534 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
535 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900536 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
537 // The reason is that libfdt ensures that the node from where the search for the next
538 // compatible node is started is always a valid one -- except for the special case of offset =
539 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
540 // next compatible node from it.
541 //
542 // We can't do in the opposite direction either. If we call next_compatible to find the next
543 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
544 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
545 // DT).
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000546 pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000547 let next_offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900548
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000549 self.delete_and_next(next_offset)
550 }
551
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000552 fn delete_and_next(self, next_offset: Option<NodeOffset>) -> Result<Option<Self>> {
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900553 if Some(self.offset) == next_offset {
554 return Err(FdtError::Internal);
555 }
556
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000557 self.fdt.nop_node(self.offset)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900558
559 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
560 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900561
562 /// Deletes this node effectively from DT, by setting it with FDT_NOP
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000563 pub fn nop(self) -> Result<()> {
564 self.fdt.nop_node(self.offset)
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900565 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000566}
567
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000568/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000569#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100570#[repr(transparent)]
571pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000572 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100573}
574
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000575// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
576// methods to be called on invalid device trees.
577unsafe impl Libfdt for Fdt {
578 fn as_fdt_slice(&self) -> &[u8] {
579 &self.buffer[..self.totalsize()]
580 }
581}
582
583// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
584// methods to be called on invalid device trees.
585unsafe impl LibfdtMut for Fdt {
586 fn as_fdt_slice_mut(&mut self) -> &mut [u8] {
587 &mut self.buffer
588 }
589}
590
David Brazdil1baa9a92022-06-28 14:47:50 +0100591impl Fdt {
592 /// Wraps a slice containing a Flattened Device Tree.
593 ///
594 /// Fails if the FDT does not pass validation.
595 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000596 libfdt::check_full(fdt)?;
597 // SAFETY: The FDT was validated.
David Brazdil1baa9a92022-06-28 14:47:50 +0100598 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000599
David Brazdil1baa9a92022-06-28 14:47:50 +0100600 Ok(fdt)
601 }
602
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000603 /// Wraps a mutable slice containing a Flattened Device Tree.
604 ///
605 /// Fails if the FDT does not pass validation.
606 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000607 libfdt::check_full(fdt)?;
608 // SAFETY: The FDT was validated.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000609 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000610
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000611 Ok(fdt)
612 }
613
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900614 /// Creates an empty Flattened Device Tree with a mutable slice.
615 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000616 libfdt::create_empty_tree(fdt)?;
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900617
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000618 Self::from_mut_slice(fdt)
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900619 }
620
David Brazdil1baa9a92022-06-28 14:47:50 +0100621 /// Wraps a slice containing a Flattened Device Tree.
622 ///
623 /// # Safety
624 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000625 /// It is undefined to call this function on a slice that does not contain a valid device tree.
Pierre-Clément Tosi84ba1a82024-10-30 11:27:32 +0000626 pub const unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000627 let self_ptr = fdt as *const _ as *const _;
628 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
629 unsafe { &*self_ptr }
David Brazdil1baa9a92022-06-28 14:47:50 +0100630 }
631
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000632 /// Wraps a mutable slice containing a Flattened Device Tree.
633 ///
634 /// # Safety
635 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000636 /// 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 +0000637 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000638 let self_mut_ptr = fdt as *mut _ as *mut _;
639 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
640 unsafe { &mut *self_mut_ptr }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000641 }
642
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000643 /// Updates this FDT from another FDT.
644 pub fn clone_from(&mut self, other: &Self) -> Result<()> {
645 let new_len = other.buffer.len();
646 if self.buffer.len() < new_len {
647 return Err(FdtError::NoSpace);
Jiyong Parke9d87e82023-03-21 19:28:40 +0900648 }
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000649
650 let zeroed_len = self.totalsize().checked_sub(new_len);
651 let (cloned, zeroed) = self.buffer.split_at_mut(new_len);
652
653 cloned.clone_from_slice(&other.buffer);
654 if let Some(len) = zeroed_len {
655 zeroed[..len].fill(0);
656 }
657
658 Ok(())
Jiyong Parke9d87e82023-03-21 19:28:40 +0900659 }
660
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900661 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000662 pub fn unpack(&mut self) -> Result<()> {
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000663 self.open_into_self()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000664 }
665
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900666 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000667 ///
668 /// Doesn't shrink the underlying memory slice.
669 pub fn pack(&mut self) -> Result<()> {
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000670 LibfdtMut::pack(self)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000671 }
672
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000673 /// Applies a DT overlay on the base DT.
674 ///
675 /// # Safety
676 ///
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000677 /// As libfdt corrupts the input DT on failure, `self` should be discarded on error:
678 ///
679 /// let fdt = fdt.apply_overlay(overlay)?;
680 ///
681 /// Furthermore, `overlay` is _always_ corrupted by libfdt and will never refer to a valid
682 /// `Fdt` after this function returns and must therefore be discarded by the caller.
683 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &mut Fdt) -> Result<&'a mut Self> {
684 // SAFETY: Our caller will properly discard overlay and/or self as needed.
685 unsafe { self.overlay_apply(overlay) }?;
686
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000687 Ok(self)
688 }
689
Alice Wang2422bdc2023-06-12 08:37:55 +0000690 /// Returns an iterator of memory banks specified the "/memory" node.
691 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100692 ///
693 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +0000694 pub fn memory(&self) -> Result<MemRegIterator> {
Alan Stokesf46a17c2025-01-05 15:50:18 +0000695 let node = self.root().subnode(c"memory")?.ok_or(FdtError::NotFound)?;
696 if node.device_type()? != Some(c"memory") {
Alice Wang2422bdc2023-06-12 08:37:55 +0000697 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000698 }
Alice Wang2422bdc2023-06-12 08:37:55 +0000699 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
700 }
701
702 /// Returns the first memory range in the `/memory` node.
703 pub fn first_memory_range(&self) -> Result<Range<usize>> {
704 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +0100705 }
706
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900707 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000708 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Alan Stokesf46a17c2025-01-05 15:50:18 +0000709 self.root().subnode(c"chosen")
David Brazdil1baa9a92022-06-28 14:47:50 +0100710 }
711
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900712 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000713 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Alan Stokesf46a17c2025-01-05 15:50:18 +0000714 self.node_mut(c"/chosen")
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000715 }
716
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900717 /// Returns the root node of the tree.
Pierre-Clément Tosi244efea2024-02-16 14:48:14 +0000718 pub fn root(&self) -> FdtNode {
719 FdtNode { fdt: self, offset: NodeOffset::ROOT }
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000720 }
721
Jaewan Kimf163d762023-11-01 13:12:50 +0900722 /// Returns the standard /__symbols__ node.
723 pub fn symbols(&self) -> Result<Option<FdtNode>> {
Alan Stokesf46a17c2025-01-05 15:50:18 +0000724 self.root().subnode(c"__symbols__")
Jaewan Kimf163d762023-11-01 13:12:50 +0900725 }
726
727 /// Returns the standard /__symbols__ node as mutable
728 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Alan Stokesf46a17c2025-01-05 15:50:18 +0000729 self.node_mut(c"/__symbols__")
Jaewan Kimf163d762023-11-01 13:12:50 +0900730 }
731
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900732 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000733 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000734 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000735
736 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100737 }
738
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000739 /// Iterate over nodes with a given compatible string.
740 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
741 CompatibleIterator::new(self, compatible)
742 }
743
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900744 /// Returns max phandle in the tree.
745 pub fn max_phandle(&self) -> Result<Phandle> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000746 self.find_max_phandle()
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900747 }
748
749 /// Returns a node with the phandle
750 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000751 let offset = self.node_offset_by_phandle(phandle)?;
752
Jaewan Kimc63246d2023-11-09 15:41:01 +0900753 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
754 }
755
756 /// Returns a mutable node with the phandle
757 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000758 let offset = self.node_offset_by_phandle(phandle)?;
Jaewan Kimc63246d2023-11-09 15:41:01 +0900759
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000760 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900761 }
762
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900763 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi244efea2024-02-16 14:48:14 +0000764 pub fn root_mut(&mut self) -> FdtNodeMut {
765 FdtNodeMut { fdt: self, offset: NodeOffset::ROOT }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000766 }
767
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900768 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000769 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000770 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000771
772 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000773 }
774
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000775 fn next_node_skip_subnodes(
776 &self,
777 node: NodeOffset,
778 depth: usize,
779 ) -> Result<Option<(NodeOffset, usize)>> {
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000780 let mut iter = self.next_node(node, depth)?;
781 while let Some((offset, next_depth)) = iter {
782 if next_depth <= depth {
783 return Ok(Some((offset, next_depth)));
784 }
785 iter = self.next_node(offset, next_depth)?;
786 }
787
788 Ok(None)
789 }
790
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900791 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000792 pub fn as_slice(&self) -> &[u8] {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000793 self.as_fdt_slice()
David Brazdil1baa9a92022-06-28 14:47:50 +0100794 }
795
Jaewan Kimaa638702023-09-19 13:34:01 +0900796 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +0000797 get_slice_at_ptr(self.as_fdt_slice(), ptr.cast(), len).ok_or(FdtError::Internal)
Jaewan Kim72d10902023-10-12 21:59:26 +0900798 }
799
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900800 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +0000801 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000802 self.buffer.as_ptr().cast()
David Brazdil1baa9a92022-06-28 14:47:50 +0100803 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000804
Pierre-Clément Tosi566723a2024-01-24 13:01:54 +0000805 fn header(&self) -> &FdtHeader {
806 let p = self.as_ptr().cast::<libfdt_bindgen::fdt_header>();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000807 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi566723a2024-01-24 13:01:54 +0000808 let header = unsafe { &*p };
809 header.as_ref()
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000810 }
811
812 fn totalsize(&self) -> usize {
Pierre-Clément Tosi566723a2024-01-24 13:01:54 +0000813 self.header().totalsize.get().try_into().unwrap()
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000814 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100815}