blob: c0d8d550dc89ad34a467b256fad5d9901f0fa53d [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 Tosiee0a1eb2024-01-29 13:14:25 +000030pub use safe_types::{NodeOffset, Phandle};
Andrew Walbran55ad01b2022-12-05 17:00:40 +000031
David Brazdil1baa9a92022-06-28 14:47:50 +010032use core::ffi::{c_int, c_void, CStr};
Alice Wang2422bdc2023-06-12 08:37:55 +000033use core::ops::Range;
Pierre-Clément Tosi1bf532b2023-11-13 11:06:20 +000034use cstr::cstr;
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +000035use libfdt::get_slice_at_ptr;
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +000036use zerocopy::AsBytes as _;
David Brazdil1baa9a92022-06-28 14:47:50 +010037
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +000038use crate::libfdt::{Libfdt, LibfdtMut};
39
David Brazdil1baa9a92022-06-28 14:47:50 +010040/// Value of a #address-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +000041#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +010042enum AddrCells {
43 Single = 1,
44 Double = 2,
Andrew Walbranb39e6922022-12-05 17:01:20 +000045 Triple = 3,
David Brazdil1baa9a92022-06-28 14:47:50 +010046}
47
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000048impl TryFrom<usize> for AddrCells {
David Brazdil1baa9a92022-06-28 14:47:50 +010049 type Error = FdtError;
50
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000051 fn try_from(value: usize) -> Result<Self> {
52 match value {
53 x if x == Self::Single as _ => Ok(Self::Single),
54 x if x == Self::Double as _ => Ok(Self::Double),
55 x if x == Self::Triple as _ => Ok(Self::Triple),
David Brazdil1baa9a92022-06-28 14:47:50 +010056 _ => Err(FdtError::BadNCells),
57 }
58 }
59}
60
61/// Value of a #size-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +000062#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +010063enum SizeCells {
64 None = 0,
65 Single = 1,
66 Double = 2,
67}
68
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000069impl TryFrom<usize> for SizeCells {
David Brazdil1baa9a92022-06-28 14:47:50 +010070 type Error = FdtError;
71
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000072 fn try_from(value: usize) -> Result<Self> {
73 match value {
74 x if x == Self::None as _ => Ok(Self::None),
75 x if x == Self::Single as _ => Ok(Self::Single),
76 x if x == Self::Double as _ => Ok(Self::Double),
David Brazdil1baa9a92022-06-28 14:47:50 +010077 _ => Err(FdtError::BadNCells),
78 }
79 }
80}
81
Jaewan Kim72d10902023-10-12 21:59:26 +090082/// DT property wrapper to abstract endianess changes
83#[repr(transparent)]
84#[derive(Debug)]
85struct FdtPropertyStruct(libfdt_bindgen::fdt_property);
86
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +000087impl AsRef<FdtPropertyStruct> for libfdt_bindgen::fdt_property {
88 fn as_ref(&self) -> &FdtPropertyStruct {
89 let ptr = self as *const _ as *const _;
90 // SAFETY: Types have the same layout (transparent) so the valid reference remains valid.
91 unsafe { &*ptr }
92 }
93}
94
Jaewan Kim72d10902023-10-12 21:59:26 +090095impl FdtPropertyStruct {
96 fn from_offset(fdt: &Fdt, offset: c_int) -> Result<&Self> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +000097 Ok(fdt.get_property_by_offset(offset)?.as_ref())
Jaewan Kim72d10902023-10-12 21:59:26 +090098 }
99
100 fn name_offset(&self) -> c_int {
101 u32::from_be(self.0.nameoff).try_into().unwrap()
102 }
103
104 fn data_len(&self) -> usize {
105 u32::from_be(self.0.len).try_into().unwrap()
106 }
107
108 fn data_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000109 self.0.data.as_ptr().cast()
Jaewan Kim72d10902023-10-12 21:59:26 +0900110 }
111}
112
113/// DT property.
114#[derive(Clone, Copy, Debug)]
115pub struct FdtProperty<'a> {
116 fdt: &'a Fdt,
117 offset: c_int,
118 property: &'a FdtPropertyStruct,
119}
120
121impl<'a> FdtProperty<'a> {
122 fn new(fdt: &'a Fdt, offset: c_int) -> Result<Self> {
123 let property = FdtPropertyStruct::from_offset(fdt, offset)?;
124 Ok(Self { fdt, offset, property })
125 }
126
127 /// Returns the property name
128 pub fn name(&self) -> Result<&'a CStr> {
129 self.fdt.string(self.property.name_offset())
130 }
131
132 /// Returns the property value
133 pub fn value(&self) -> Result<&'a [u8]> {
134 self.fdt.get_from_ptr(self.property.data_ptr(), self.property.data_len())
135 }
136
137 fn next_property(&self) -> Result<Option<Self>> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000138 if let Some(offset) = self.fdt.next_property_offset(self.offset)? {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000139 Ok(Some(Self::new(self.fdt, offset)?))
140 } else {
141 Ok(None)
142 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900143 }
144}
145
David Brazdil1baa9a92022-06-28 14:47:50 +0100146/// DT node.
Alice Wang9d4df702023-05-25 14:14:12 +0000147#[derive(Clone, Copy, Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100148pub struct FdtNode<'a> {
149 fdt: &'a Fdt,
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000150 offset: NodeOffset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100151}
152
153impl<'a> FdtNode<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900154 /// Returns parent node.
David Brazdil1baa9a92022-06-28 14:47:50 +0100155 pub fn parent(&self) -> Result<Self> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000156 let offset = self.fdt.parent_offset(self.offset)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100157
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000158 Ok(Self { fdt: self.fdt, offset })
David Brazdil1baa9a92022-06-28 14:47:50 +0100159 }
160
Jaewan Kim5b057772023-10-19 01:02:17 +0900161 /// Returns supernode with depth. Note that root is at depth 0.
162 pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000163 let offset = self.fdt.supernode_atdepth_offset(self.offset, depth)?;
Jaewan Kim5b057772023-10-19 01:02:17 +0900164
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000165 Ok(Self { fdt: self.fdt, offset })
Jaewan Kim5b057772023-10-19 01:02:17 +0900166 }
167
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900168 /// Returns the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000169 pub fn device_type(&self) -> Result<Option<&CStr>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900170 self.getprop_str(cstr!("device_type"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100171 }
172
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900173 /// Returns the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000174 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000175 if let Some(cells) = self.getprop_cells(cstr!("reg"))? {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000176 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100177
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000178 let addr_cells = parent.address_cells()?;
179 let size_cells = parent.size_cells()?;
180
181 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
182 } else {
183 Ok(None)
184 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100185 }
186
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900187 /// Returns the standard ranges property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000188 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000189 if let Some(cells) = self.getprop_cells(cstr!("ranges"))? {
Andrew Walbranb39e6922022-12-05 17:01:20 +0000190 let parent = self.parent()?;
191 let addr_cells = self.address_cells()?;
192 let parent_addr_cells = parent.address_cells()?;
193 let size_cells = self.size_cells()?;
194 Ok(Some(RangesIterator::<A, P, S>::new(
195 cells,
196 addr_cells,
197 parent_addr_cells,
198 size_cells,
199 )))
200 } else {
201 Ok(None)
202 }
203 }
204
Jaewan Kimaa638702023-09-19 13:34:01 +0900205 /// Returns the node name.
206 pub fn name(&self) -> Result<&'a CStr> {
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +0000207 let name = self.fdt.get_name(self.offset)?;
Jaewan Kimaa638702023-09-19 13:34:01 +0900208 CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
209 }
210
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900211 /// Returns the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000212 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000213 if let Some(bytes) = self.getprop(name)? {
214 Ok(Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000215 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000216 Ok(None)
217 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100218 }
219
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900220 /// Returns the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000221 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
222 if let Some(cells) = self.getprop(name)? {
223 Ok(Some(CellIterator::new(cells)))
224 } else {
225 Ok(None)
226 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100227 }
228
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900229 /// Returns the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000230 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000231 if let Some(bytes) = self.getprop(name)? {
232 Ok(Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000233 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000234 Ok(None)
235 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100236 }
237
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900238 /// Returns the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000239 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000240 if let Some(bytes) = self.getprop(name)? {
241 Ok(Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000242 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000243 Ok(None)
244 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100245 }
246
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900247 /// Returns the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000248 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000249 self.fdt.getprop_namelen(self.offset, name.to_bytes())
David Brazdil1baa9a92022-06-28 14:47:50 +0100250 }
251
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900252 /// Returns reference to the containing device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100253 pub fn fdt(&self) -> &Fdt {
254 self.fdt
255 }
256
Alice Wang474c0ee2023-09-14 12:52:33 +0000257 /// Returns the compatible node of the given name that is next after this node.
258 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000259 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000260
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000261 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000262 }
263
Alice Wang474c0ee2023-09-14 12:52:33 +0000264 /// Returns the first range of `reg` in this node.
265 pub fn first_reg(&self) -> Result<Reg<u64>> {
266 self.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
267 }
268
David Brazdil1baa9a92022-06-28 14:47:50 +0100269 fn address_cells(&self) -> Result<AddrCells> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000270 self.fdt.address_cells(self.offset)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100271 }
272
273 fn size_cells(&self) -> Result<SizeCells> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000274 self.fdt.size_cells(self.offset)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100275 }
Jaewan Kimbc828d72023-09-19 15:52:08 +0900276
277 /// Returns an iterator of subnodes
Jaewan Kim4a34b0d2024-01-19 13:17:47 +0900278 pub fn subnodes(&self) -> Result<SubnodeIterator<'a>> {
Jaewan Kimbc828d72023-09-19 15:52:08 +0900279 SubnodeIterator::new(self)
280 }
281
282 fn first_subnode(&self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000283 let offset = self.fdt.first_subnode(self.offset)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900284
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000285 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900286 }
287
288 fn next_subnode(&self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000289 let offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900290
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000291 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900292 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900293
Jaewan Kimc9e14112023-12-04 17:05:27 +0900294 /// Returns an iterator of descendants
Jaewan Kim1eab7232024-01-04 09:46:16 +0900295 pub fn descendants(&self) -> DescendantsIterator<'a> {
Jaewan Kimc9e14112023-12-04 17:05:27 +0900296 DescendantsIterator::new(self)
297 }
298
299 fn next_node(&self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000300 if let Some((offset, depth)) = self.fdt.next_node(self.offset, depth)? {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000301 Ok(Some((Self { fdt: self.fdt, offset }, depth)))
302 } else {
303 Ok(None)
304 }
Jaewan Kimc9e14112023-12-04 17:05:27 +0900305 }
306
Jaewan Kim72d10902023-10-12 21:59:26 +0900307 /// Returns an iterator of properties
308 pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
309 PropertyIterator::new(self)
310 }
311
312 fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000313 if let Some(offset) = self.fdt.first_property_offset(self.offset)? {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000314 Ok(Some(FdtProperty::new(self.fdt, offset)?))
315 } else {
316 Ok(None)
317 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900318 }
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900319
320 /// Returns the phandle
321 pub fn get_phandle(&self) -> Result<Option<Phandle>> {
322 // This rewrites the fdt_get_phandle() because it doesn't return error code.
323 if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
324 Ok(Some(prop.try_into()?))
325 } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
326 Ok(Some(prop.try_into()?))
327 } else {
328 Ok(None)
329 }
330 }
Jaewan Kim52026012023-12-13 13:49:28 +0900331
332 /// Returns the subnode of the given name. The name doesn't need to be nul-terminated.
333 pub fn subnode(&self, name: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000334 let name = name.to_bytes();
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000335 let offset = self.fdt.subnode_offset_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000336
Jaewan Kim52026012023-12-13 13:49:28 +0900337 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
338 }
339
340 /// Returns the subnode of the given name bytes
341 pub fn subnode_with_name_bytes(&self, name: &[u8]) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000342 let offset = self.fdt.subnode_offset_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000343
Jaewan Kim52026012023-12-13 13:49:28 +0900344 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
345 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100346}
347
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000348impl<'a> PartialEq for FdtNode<'a> {
349 fn eq(&self, other: &Self) -> bool {
350 self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
351 }
352}
353
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000354/// Mutable FDT node.
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000355#[derive(Debug)]
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000356pub struct FdtNodeMut<'a> {
357 fdt: &'a mut Fdt,
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000358 offset: NodeOffset,
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000359}
360
361impl<'a> FdtNodeMut<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900362 /// Appends a property name-value (possibly empty) pair to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000363 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000364 self.fdt.appendprop(self.offset, name, value.as_ref())
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000365 }
366
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900367 /// Appends a (address, size) pair property to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000368 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000369 let parent = self.parent()?.offset;
370 self.fdt.appendprop_addrrange(parent, self.offset, name, addr, size)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000371 }
372
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900373 /// Sets a property name-value pair to the given node.
374 ///
375 /// This may create a new prop or replace existing value.
Jaewan Kimba8929b2023-01-13 11:13:29 +0900376 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000377 self.fdt.setprop(self.offset, name, value)
Jaewan Kimba8929b2023-01-13 11:13:29 +0900378 }
379
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900380 /// Sets the value of the given property with the given value, and ensure that the given
381 /// value has the same length as the current value length.
382 ///
383 /// This can only be used to replace existing value.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900384 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000385 self.fdt.setprop_inplace(self.offset, name, value)
Jiyong Park9c63cd12023-03-21 17:53:07 +0900386 }
387
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900388 /// Sets the value of the given (address, size) pair property with the given value, and
389 /// ensure that the given value has the same length as the current value length.
390 ///
391 /// This can only be used to replace existing value.
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000392 pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
393 let pair = [addr.to_be(), size.to_be()];
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000394 self.fdt.setprop_inplace(self.offset, name, pair.as_bytes())
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000395 }
396
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900397 /// Sets a flag-like empty property.
398 ///
399 /// This may create a new prop or replace existing value.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000400 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000401 self.fdt.setprop(self.offset, name, &[])
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000402 }
403
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900404 /// Deletes the given property.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000405 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000406 self.fdt.delprop(self.offset, name)
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000407 }
408
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900409 /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000410 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
Pierre-Clément Tosi410e46a2023-12-24 11:33:11 +0000411 self.fdt.nop_property(self.offset, name)
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000412 }
413
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900414 /// Trims the size of the given property to new_size.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900415 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
Pierre-Clément Tosi843845d2024-01-23 23:35:01 +0000416 let prop = self.as_node().getprop(name)?.ok_or(FdtError::NotFound)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900417
Pierre-Clément Tosi843845d2024-01-23 23:35:01 +0000418 match prop.len() {
419 x if x == new_size => Ok(()),
420 x if x < new_size => Err(FdtError::NoSpace),
421 _ => self.fdt.setprop_placeholder(self.offset, name, new_size).map(|_| ()),
422 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900423 }
424
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900425 /// Returns reference to the containing device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000426 pub fn fdt(&mut self) -> &mut Fdt {
427 self.fdt
428 }
429
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900430 /// Returns immutable FdtNode of this node.
431 pub fn as_node(&self) -> FdtNode {
432 FdtNode { fdt: self.fdt, offset: self.offset }
433 }
434
Jaewan Kime6363422024-01-19 14:00:00 +0900435 /// Adds new subnodes to the given node.
436 pub fn add_subnodes(&mut self, names: &[&CStr]) -> Result<()> {
437 for name in names {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000438 self.fdt.add_subnode_namelen(self.offset, name.to_bytes())?;
Jaewan Kime6363422024-01-19 14:00:00 +0900439 }
440 Ok(())
441 }
442
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900443 /// 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 +0000444 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000445 let name = name.to_bytes();
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000446 let offset = self.fdt.add_subnode_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000447
Jaewan Kim5ab13582023-10-20 20:56:27 +0900448 Ok(Self { fdt: self.fdt, offset })
449 }
450
451 /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
452 /// on success.
453 pub fn add_subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000454 let name = &name.to_bytes()[..namelen];
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000455 let offset = self.fdt.add_subnode_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000456
Jaewan Kim5ab13582023-10-20 20:56:27 +0900457 Ok(Self { fdt: self.fdt, offset })
458 }
459
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900460 /// Returns the first subnode of this
461 pub fn first_subnode(&'a mut self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000462 let offset = self.fdt.first_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900463
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000464 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900465 }
466
467 /// Returns the next subnode that shares the same parent with this
468 pub fn next_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000469 let offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900470
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000471 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900472 }
473
474 /// Deletes the current node and returns the next subnode
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000475 pub fn delete_and_next_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000476 let next_offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900477
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000478 self.delete_and_next(next_offset)
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900479 }
480
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900481 /// Returns the next node
482 pub fn next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000483 let next = self.fdt.next_node(self.offset, depth)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000484
485 Ok(next.map(|(offset, depth)| (Self { fdt: self.fdt, offset }, depth)))
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900486 }
487
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000488 /// Deletes this and returns the next node
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000489 pub fn delete_and_next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
490 let next_node = self.fdt.next_node_skip_subnodes(self.offset, depth)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000491 if let Some((offset, depth)) = next_node {
492 let next_node = self.delete_and_next(Some(offset))?.unwrap();
493 Ok(Some((next_node, depth)))
494 } else {
495 Ok(None)
496 }
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900497 }
498
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000499 fn parent(&'a self) -> Result<FdtNode<'a>> {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000500 self.as_node().parent()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000501 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900502
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900503 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900504 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000505 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900506
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000507 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900508 }
509
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900510 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
511 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900512 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
513 // The reason is that libfdt ensures that the node from where the search for the next
514 // compatible node is started is always a valid one -- except for the special case of offset =
515 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
516 // next compatible node from it.
517 //
518 // We can't do in the opposite direction either. If we call next_compatible to find the next
519 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
520 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
521 // DT).
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000522 pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000523 let next_offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900524
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000525 self.delete_and_next(next_offset)
526 }
527
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000528 fn delete_and_next(self, next_offset: Option<NodeOffset>) -> Result<Option<Self>> {
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900529 if Some(self.offset) == next_offset {
530 return Err(FdtError::Internal);
531 }
532
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000533 self.fdt.nop_node(self.offset)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900534
535 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
536 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900537
538 /// Deletes this node effectively from DT, by setting it with FDT_NOP
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000539 pub fn nop(self) -> Result<()> {
540 self.fdt.nop_node(self.offset)
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900541 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000542}
543
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000544/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000545#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100546#[repr(transparent)]
547pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000548 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100549}
550
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000551// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
552// methods to be called on invalid device trees.
553unsafe impl Libfdt for Fdt {
554 fn as_fdt_slice(&self) -> &[u8] {
555 &self.buffer[..self.totalsize()]
556 }
557}
558
559// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
560// methods to be called on invalid device trees.
561unsafe impl LibfdtMut for Fdt {
562 fn as_fdt_slice_mut(&mut self) -> &mut [u8] {
563 &mut self.buffer
564 }
565}
566
David Brazdil1baa9a92022-06-28 14:47:50 +0100567impl Fdt {
568 /// Wraps a slice containing a Flattened Device Tree.
569 ///
570 /// Fails if the FDT does not pass validation.
571 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000572 libfdt::check_full(fdt)?;
573 // SAFETY: The FDT was validated.
David Brazdil1baa9a92022-06-28 14:47:50 +0100574 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000575
David Brazdil1baa9a92022-06-28 14:47:50 +0100576 Ok(fdt)
577 }
578
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000579 /// Wraps a mutable slice containing a Flattened Device Tree.
580 ///
581 /// Fails if the FDT does not pass validation.
582 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000583 libfdt::check_full(fdt)?;
584 // SAFETY: The FDT was validated.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000585 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000586
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000587 Ok(fdt)
588 }
589
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900590 /// Creates an empty Flattened Device Tree with a mutable slice.
591 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000592 libfdt::create_empty_tree(fdt)?;
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900593
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000594 Self::from_mut_slice(fdt)
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900595 }
596
David Brazdil1baa9a92022-06-28 14:47:50 +0100597 /// Wraps a slice containing a Flattened Device Tree.
598 ///
599 /// # Safety
600 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000601 /// It is undefined to call this function on a slice that does not contain a valid device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100602 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000603 let self_ptr = fdt as *const _ as *const _;
604 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
605 unsafe { &*self_ptr }
David Brazdil1baa9a92022-06-28 14:47:50 +0100606 }
607
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000608 /// Wraps a mutable slice containing a Flattened Device Tree.
609 ///
610 /// # Safety
611 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000612 /// 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 +0000613 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000614 let self_mut_ptr = fdt as *mut _ as *mut _;
615 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
616 unsafe { &mut *self_mut_ptr }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000617 }
618
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000619 /// Updates this FDT from another FDT.
620 pub fn clone_from(&mut self, other: &Self) -> Result<()> {
621 let new_len = other.buffer.len();
622 if self.buffer.len() < new_len {
623 return Err(FdtError::NoSpace);
Jiyong Parke9d87e82023-03-21 19:28:40 +0900624 }
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000625
626 let zeroed_len = self.totalsize().checked_sub(new_len);
627 let (cloned, zeroed) = self.buffer.split_at_mut(new_len);
628
629 cloned.clone_from_slice(&other.buffer);
630 if let Some(len) = zeroed_len {
631 zeroed[..len].fill(0);
632 }
633
634 Ok(())
Jiyong Parke9d87e82023-03-21 19:28:40 +0900635 }
636
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900637 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000638 pub fn unpack(&mut self) -> Result<()> {
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000639 self.open_into_self()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000640 }
641
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900642 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000643 ///
644 /// Doesn't shrink the underlying memory slice.
645 pub fn pack(&mut self) -> Result<()> {
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000646 LibfdtMut::pack(self)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000647 }
648
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000649 /// Applies a DT overlay on the base DT.
650 ///
651 /// # Safety
652 ///
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000653 /// As libfdt corrupts the input DT on failure, `self` should be discarded on error:
654 ///
655 /// let fdt = fdt.apply_overlay(overlay)?;
656 ///
657 /// Furthermore, `overlay` is _always_ corrupted by libfdt and will never refer to a valid
658 /// `Fdt` after this function returns and must therefore be discarded by the caller.
659 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &mut Fdt) -> Result<&'a mut Self> {
660 // SAFETY: Our caller will properly discard overlay and/or self as needed.
661 unsafe { self.overlay_apply(overlay) }?;
662
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000663 Ok(self)
664 }
665
Alice Wang2422bdc2023-06-12 08:37:55 +0000666 /// Returns an iterator of memory banks specified the "/memory" node.
667 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100668 ///
669 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +0000670 pub fn memory(&self) -> Result<MemRegIterator> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000671 let node = self.node(cstr!("/memory"))?.ok_or(FdtError::NotFound)?;
672 if node.device_type()? != Some(cstr!("memory")) {
Alice Wang2422bdc2023-06-12 08:37:55 +0000673 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000674 }
Alice Wang2422bdc2023-06-12 08:37:55 +0000675 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
676 }
677
678 /// Returns the first memory range in the `/memory` node.
679 pub fn first_memory_range(&self) -> Result<Range<usize>> {
680 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +0100681 }
682
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900683 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000684 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900685 self.node(cstr!("/chosen"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100686 }
687
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900688 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000689 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900690 self.node_mut(cstr!("/chosen"))
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000691 }
692
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900693 /// Returns the root node of the tree.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000694 pub fn root(&self) -> Result<FdtNode> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900695 self.node(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000696 }
697
Jaewan Kimf163d762023-11-01 13:12:50 +0900698 /// Returns the standard /__symbols__ node.
699 pub fn symbols(&self) -> Result<Option<FdtNode>> {
700 self.node(cstr!("/__symbols__"))
701 }
702
703 /// Returns the standard /__symbols__ node as mutable
704 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
705 self.node_mut(cstr!("/__symbols__"))
706 }
707
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900708 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000709 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000710 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000711
712 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100713 }
714
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000715 /// Iterate over nodes with a given compatible string.
716 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
717 CompatibleIterator::new(self, compatible)
718 }
719
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900720 /// Returns max phandle in the tree.
721 pub fn max_phandle(&self) -> Result<Phandle> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000722 self.find_max_phandle()
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900723 }
724
725 /// Returns a node with the phandle
726 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000727 let offset = self.node_offset_by_phandle(phandle)?;
728
Jaewan Kimc63246d2023-11-09 15:41:01 +0900729 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
730 }
731
732 /// Returns a mutable node with the phandle
733 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000734 let offset = self.node_offset_by_phandle(phandle)?;
Jaewan Kimc63246d2023-11-09 15:41:01 +0900735
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000736 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900737 }
738
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900739 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000740 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900741 self.node_mut(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000742 }
743
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900744 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000745 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000746 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000747
748 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000749 }
750
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000751 fn next_node_skip_subnodes(
752 &self,
753 node: NodeOffset,
754 depth: usize,
755 ) -> Result<Option<(NodeOffset, usize)>> {
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000756 let mut iter = self.next_node(node, depth)?;
757 while let Some((offset, next_depth)) = iter {
758 if next_depth <= depth {
759 return Ok(Some((offset, next_depth)));
760 }
761 iter = self.next_node(offset, next_depth)?;
762 }
763
764 Ok(None)
765 }
766
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900767 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000768 pub fn as_slice(&self) -> &[u8] {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000769 self.as_fdt_slice()
David Brazdil1baa9a92022-06-28 14:47:50 +0100770 }
771
Jaewan Kimaa638702023-09-19 13:34:01 +0900772 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +0000773 get_slice_at_ptr(self.as_fdt_slice(), ptr.cast(), len).ok_or(FdtError::Internal)
Jaewan Kim72d10902023-10-12 21:59:26 +0900774 }
775
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900776 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +0000777 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000778 self.buffer.as_ptr().cast()
David Brazdil1baa9a92022-06-28 14:47:50 +0100779 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000780
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000781 fn header(&self) -> &libfdt_bindgen::fdt_header {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000782 let p = self.as_ptr().cast();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000783 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000784 unsafe { &*p }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000785 }
786
787 fn totalsize(&self) -> usize {
788 u32::from_be(self.header().totalsize) as usize
789 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100790}