blob: 333926240c70b2eadefb0128beaef34910fe2499 [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 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 {
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +000096 fn from_offset(fdt: &Fdt, offset: PropOffset) -> 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
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +0000100 fn name_offset(&self) -> StringOffset {
101 StringOffset(u32::from_be(self.0.nameoff).try_into().unwrap())
Jaewan Kim72d10902023-10-12 21:59:26 +0900102 }
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,
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +0000117 offset: PropOffset,
Jaewan Kim72d10902023-10-12 21:59:26 +0900118 property: &'a FdtPropertyStruct,
119}
120
121impl<'a> FdtProperty<'a> {
Pierre-Clément Tosi0606f702024-01-19 16:25:16 +0000122 fn new(fdt: &'a Fdt, offset: PropOffset) -> Result<Self> {
Jaewan Kim72d10902023-10-12 21:59:26 +0900123 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.
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +0000436 pub fn add_subnodes(self, names: &[&CStr]) -> Result<()> {
Jaewan Kime6363422024-01-19 14:00:00 +0900437 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 Tosia3c4ec32024-02-15 20:05:15 +0000444 pub fn add_subnode(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.
Pierre-Clément Tosia3c4ec32024-02-15 20:05:15 +0000453 pub fn add_subnode_with_namelen(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
Pierre-Clément Tosi973dda32024-02-14 16:08:28 +0000461 pub fn first_subnode(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 {
Jaewan Kima5bc8922024-02-20 01:15:37 +0900495 self.delete_and_next(None)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000496 Ok(None)
497 }
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900498 }
499
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000500 fn parent(&'a self) -> Result<FdtNode<'a>> {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000501 self.as_node().parent()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000502 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900503
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900504 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900505 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000506 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900507
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000508 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900509 }
510
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900511 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
512 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900513 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
514 // The reason is that libfdt ensures that the node from where the search for the next
515 // compatible node is started is always a valid one -- except for the special case of offset =
516 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
517 // next compatible node from it.
518 //
519 // We can't do in the opposite direction either. If we call next_compatible to find the next
520 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
521 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
522 // DT).
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000523 pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000524 let next_offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900525
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000526 self.delete_and_next(next_offset)
527 }
528
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000529 fn delete_and_next(self, next_offset: Option<NodeOffset>) -> Result<Option<Self>> {
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900530 if Some(self.offset) == next_offset {
531 return Err(FdtError::Internal);
532 }
533
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000534 self.fdt.nop_node(self.offset)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900535
536 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
537 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900538
539 /// Deletes this node effectively from DT, by setting it with FDT_NOP
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000540 pub fn nop(self) -> Result<()> {
541 self.fdt.nop_node(self.offset)
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900542 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000543}
544
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000545/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000546#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100547#[repr(transparent)]
548pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000549 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100550}
551
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000552// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
553// methods to be called on invalid device trees.
554unsafe impl Libfdt for Fdt {
555 fn as_fdt_slice(&self) -> &[u8] {
556 &self.buffer[..self.totalsize()]
557 }
558}
559
560// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
561// methods to be called on invalid device trees.
562unsafe impl LibfdtMut for Fdt {
563 fn as_fdt_slice_mut(&mut self) -> &mut [u8] {
564 &mut self.buffer
565 }
566}
567
David Brazdil1baa9a92022-06-28 14:47:50 +0100568impl Fdt {
569 /// Wraps a slice containing a Flattened Device Tree.
570 ///
571 /// Fails if the FDT does not pass validation.
572 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000573 libfdt::check_full(fdt)?;
574 // SAFETY: The FDT was validated.
David Brazdil1baa9a92022-06-28 14:47:50 +0100575 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000576
David Brazdil1baa9a92022-06-28 14:47:50 +0100577 Ok(fdt)
578 }
579
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000580 /// Wraps a mutable slice containing a Flattened Device Tree.
581 ///
582 /// Fails if the FDT does not pass validation.
583 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000584 libfdt::check_full(fdt)?;
585 // SAFETY: The FDT was validated.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000586 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000587
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000588 Ok(fdt)
589 }
590
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900591 /// Creates an empty Flattened Device Tree with a mutable slice.
592 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000593 libfdt::create_empty_tree(fdt)?;
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900594
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000595 Self::from_mut_slice(fdt)
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900596 }
597
David Brazdil1baa9a92022-06-28 14:47:50 +0100598 /// Wraps a slice containing a Flattened Device Tree.
599 ///
600 /// # Safety
601 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000602 /// 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 +0100603 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000604 let self_ptr = fdt as *const _ as *const _;
605 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
606 unsafe { &*self_ptr }
David Brazdil1baa9a92022-06-28 14:47:50 +0100607 }
608
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000609 /// Wraps a mutable slice containing a Flattened Device Tree.
610 ///
611 /// # Safety
612 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000613 /// 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 +0000614 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000615 let self_mut_ptr = fdt as *mut _ as *mut _;
616 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
617 unsafe { &mut *self_mut_ptr }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000618 }
619
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000620 /// Updates this FDT from another FDT.
621 pub fn clone_from(&mut self, other: &Self) -> Result<()> {
622 let new_len = other.buffer.len();
623 if self.buffer.len() < new_len {
624 return Err(FdtError::NoSpace);
Jiyong Parke9d87e82023-03-21 19:28:40 +0900625 }
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000626
627 let zeroed_len = self.totalsize().checked_sub(new_len);
628 let (cloned, zeroed) = self.buffer.split_at_mut(new_len);
629
630 cloned.clone_from_slice(&other.buffer);
631 if let Some(len) = zeroed_len {
632 zeroed[..len].fill(0);
633 }
634
635 Ok(())
Jiyong Parke9d87e82023-03-21 19:28:40 +0900636 }
637
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900638 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000639 pub fn unpack(&mut self) -> Result<()> {
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000640 self.open_into_self()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000641 }
642
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900643 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000644 ///
645 /// Doesn't shrink the underlying memory slice.
646 pub fn pack(&mut self) -> Result<()> {
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000647 LibfdtMut::pack(self)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000648 }
649
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000650 /// Applies a DT overlay on the base DT.
651 ///
652 /// # Safety
653 ///
Pierre-Clément Tosie21ed3f2024-01-23 18:16:13 +0000654 /// As libfdt corrupts the input DT on failure, `self` should be discarded on error:
655 ///
656 /// let fdt = fdt.apply_overlay(overlay)?;
657 ///
658 /// Furthermore, `overlay` is _always_ corrupted by libfdt and will never refer to a valid
659 /// `Fdt` after this function returns and must therefore be discarded by the caller.
660 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &mut Fdt) -> Result<&'a mut Self> {
661 // SAFETY: Our caller will properly discard overlay and/or self as needed.
662 unsafe { self.overlay_apply(overlay) }?;
663
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000664 Ok(self)
665 }
666
Alice Wang2422bdc2023-06-12 08:37:55 +0000667 /// Returns an iterator of memory banks specified the "/memory" node.
668 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100669 ///
670 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +0000671 pub fn memory(&self) -> Result<MemRegIterator> {
Pierre-Clément Tosi7f2658d2024-01-22 15:56:07 +0000672 let node = self.root()?.subnode(cstr!("memory"))?.ok_or(FdtError::NotFound)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000673 if node.device_type()? != Some(cstr!("memory")) {
Alice Wang2422bdc2023-06-12 08:37:55 +0000674 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000675 }
Alice Wang2422bdc2023-06-12 08:37:55 +0000676 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
677 }
678
679 /// Returns the first memory range in the `/memory` node.
680 pub fn first_memory_range(&self) -> Result<Range<usize>> {
681 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +0100682 }
683
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900684 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000685 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Pierre-Clément Tosi7f2658d2024-01-22 15:56:07 +0000686 self.root()?.subnode(cstr!("chosen"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100687 }
688
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900689 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000690 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900691 self.node_mut(cstr!("/chosen"))
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000692 }
693
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900694 /// Returns the root node of the tree.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000695 pub fn root(&self) -> Result<FdtNode> {
Pierre-Clément Tosi7f2658d2024-01-22 15:56:07 +0000696 Ok(FdtNode { fdt: self, offset: NodeOffset::ROOT })
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000697 }
698
Jaewan Kimf163d762023-11-01 13:12:50 +0900699 /// Returns the standard /__symbols__ node.
700 pub fn symbols(&self) -> Result<Option<FdtNode>> {
Pierre-Clément Tosi7f2658d2024-01-22 15:56:07 +0000701 self.root()?.subnode(cstr!("__symbols__"))
Jaewan Kimf163d762023-11-01 13:12:50 +0900702 }
703
704 /// Returns the standard /__symbols__ node as mutable
705 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
706 self.node_mut(cstr!("/__symbols__"))
707 }
708
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900709 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000710 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000711 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000712
713 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100714 }
715
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000716 /// Iterate over nodes with a given compatible string.
717 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
718 CompatibleIterator::new(self, compatible)
719 }
720
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900721 /// Returns max phandle in the tree.
722 pub fn max_phandle(&self) -> Result<Phandle> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000723 self.find_max_phandle()
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900724 }
725
726 /// Returns a node with the phandle
727 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000728 let offset = self.node_offset_by_phandle(phandle)?;
729
Jaewan Kimc63246d2023-11-09 15:41:01 +0900730 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
731 }
732
733 /// Returns a mutable node with the phandle
734 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000735 let offset = self.node_offset_by_phandle(phandle)?;
Jaewan Kimc63246d2023-11-09 15:41:01 +0900736
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000737 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900738 }
739
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900740 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000741 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
Pierre-Clément Tosi7f2658d2024-01-22 15:56:07 +0000742 Ok(FdtNodeMut { fdt: self, offset: NodeOffset::ROOT })
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000743 }
744
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900745 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000746 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000747 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000748
749 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000750 }
751
Pierre-Clément Tosiee0a1eb2024-01-29 13:14:25 +0000752 fn next_node_skip_subnodes(
753 &self,
754 node: NodeOffset,
755 depth: usize,
756 ) -> Result<Option<(NodeOffset, usize)>> {
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000757 let mut iter = self.next_node(node, depth)?;
758 while let Some((offset, next_depth)) = iter {
759 if next_depth <= depth {
760 return Ok(Some((offset, next_depth)));
761 }
762 iter = self.next_node(offset, next_depth)?;
763 }
764
765 Ok(None)
766 }
767
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900768 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000769 pub fn as_slice(&self) -> &[u8] {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000770 self.as_fdt_slice()
David Brazdil1baa9a92022-06-28 14:47:50 +0100771 }
772
Jaewan Kimaa638702023-09-19 13:34:01 +0900773 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +0000774 get_slice_at_ptr(self.as_fdt_slice(), ptr.cast(), len).ok_or(FdtError::Internal)
Jaewan Kim72d10902023-10-12 21:59:26 +0900775 }
776
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900777 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +0000778 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000779 self.buffer.as_ptr().cast()
David Brazdil1baa9a92022-06-28 14:47:50 +0100780 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000781
Pierre-Clément Tosi566723a2024-01-24 13:01:54 +0000782 fn header(&self) -> &FdtHeader {
783 let p = self.as_ptr().cast::<libfdt_bindgen::fdt_header>();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000784 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi566723a2024-01-24 13:01:54 +0000785 let header = unsafe { &*p };
786 header.as_ref()
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000787 }
788
789 fn totalsize(&self) -> usize {
Pierre-Clément Tosi566723a2024-01-24 13:01:54 +0000790 self.header().totalsize.get().try_into().unwrap()
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000791 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100792}