blob: d5013ca253b6141df70d1f6c7f253ec21b98d4f2 [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
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +000020mod ctypes;
Andrew Walbran55ad01b2022-12-05 17:00:40 +000021mod iterators;
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +000022mod libfdt;
Pierre-Clément Tosi99a76902023-12-21 10:30:37 +000023mod result;
Andrew Walbran55ad01b2022-12-05 17:00:40 +000024
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +000025pub use ctypes::Phandle;
Jaewan Kimfe06c852023-10-05 23:40:06 +090026pub use iterators::{
Jaewan Kimc9e14112023-12-04 17:05:27 +090027 AddressRange, CellIterator, CompatibleIterator, DescendantsIterator, MemRegIterator,
28 PropertyIterator, RangesIterator, Reg, RegIterator, SubnodeIterator,
Jaewan Kimfe06c852023-10-05 23:40:06 +090029};
Pierre-Clément Tosi99a76902023-12-21 10:30:37 +000030pub use result::{FdtError, Result};
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 Tosi99a76902023-12-21 10:30:37 +000035use result::{fdt_err, fdt_err_expect_zero, fdt_err_or_option};
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> {
97 let mut len = 0;
98 let prop =
99 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
100 unsafe { libfdt_bindgen::fdt_get_property_by_offset(fdt.as_ptr(), offset, &mut len) };
101 if prop.is_null() {
102 fdt_err(len)?;
103 return Err(FdtError::Internal); // shouldn't happen.
104 }
105 // SAFETY: prop is only returned when it points to valid libfdt_bindgen.
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000106 let prop = unsafe { &*prop };
107 Ok(prop.as_ref())
Jaewan Kim72d10902023-10-12 21:59:26 +0900108 }
109
110 fn name_offset(&self) -> c_int {
111 u32::from_be(self.0.nameoff).try_into().unwrap()
112 }
113
114 fn data_len(&self) -> usize {
115 u32::from_be(self.0.len).try_into().unwrap()
116 }
117
118 fn data_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000119 self.0.data.as_ptr().cast()
Jaewan Kim72d10902023-10-12 21:59:26 +0900120 }
121}
122
123/// DT property.
124#[derive(Clone, Copy, Debug)]
125pub struct FdtProperty<'a> {
126 fdt: &'a Fdt,
127 offset: c_int,
128 property: &'a FdtPropertyStruct,
129}
130
131impl<'a> FdtProperty<'a> {
132 fn new(fdt: &'a Fdt, offset: c_int) -> Result<Self> {
133 let property = FdtPropertyStruct::from_offset(fdt, offset)?;
134 Ok(Self { fdt, offset, property })
135 }
136
137 /// Returns the property name
138 pub fn name(&self) -> Result<&'a CStr> {
139 self.fdt.string(self.property.name_offset())
140 }
141
142 /// Returns the property value
143 pub fn value(&self) -> Result<&'a [u8]> {
144 self.fdt.get_from_ptr(self.property.data_ptr(), self.property.data_len())
145 }
146
147 fn next_property(&self) -> Result<Option<Self>> {
148 let ret =
149 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
150 unsafe { libfdt_bindgen::fdt_next_property_offset(self.fdt.as_ptr(), self.offset) };
151
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000152 if let Some(offset) = fdt_err_or_option(ret)? {
153 Ok(Some(Self::new(self.fdt, offset)?))
154 } else {
155 Ok(None)
156 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900157 }
158}
159
David Brazdil1baa9a92022-06-28 14:47:50 +0100160/// DT node.
Alice Wang9d4df702023-05-25 14:14:12 +0000161#[derive(Clone, Copy, Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100162pub struct FdtNode<'a> {
163 fdt: &'a Fdt,
164 offset: c_int,
165}
166
167impl<'a> FdtNode<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900168 /// Returns parent node.
David Brazdil1baa9a92022-06-28 14:47:50 +0100169 pub fn parent(&self) -> Result<Self> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000170 let offset = self.fdt.parent_offset(self.offset)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100171
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000172 Ok(Self { fdt: self.fdt, offset })
David Brazdil1baa9a92022-06-28 14:47:50 +0100173 }
174
Jaewan Kim5b057772023-10-19 01:02:17 +0900175 /// Returns supernode with depth. Note that root is at depth 0.
176 pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000177 let offset = self.fdt.supernode_atdepth_offset(self.offset, depth)?;
Jaewan Kim5b057772023-10-19 01:02:17 +0900178
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000179 Ok(Self { fdt: self.fdt, offset })
Jaewan Kim5b057772023-10-19 01:02:17 +0900180 }
181
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900182 /// Returns the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000183 pub fn device_type(&self) -> Result<Option<&CStr>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900184 self.getprop_str(cstr!("device_type"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100185 }
186
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900187 /// Returns the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000188 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000189 if let Some(cells) = self.getprop_cells(cstr!("reg"))? {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000190 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100191
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000192 let addr_cells = parent.address_cells()?;
193 let size_cells = parent.size_cells()?;
194
195 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
196 } else {
197 Ok(None)
198 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100199 }
200
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900201 /// Returns the standard ranges property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000202 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000203 if let Some(cells) = self.getprop_cells(cstr!("ranges"))? {
Andrew Walbranb39e6922022-12-05 17:01:20 +0000204 let parent = self.parent()?;
205 let addr_cells = self.address_cells()?;
206 let parent_addr_cells = parent.address_cells()?;
207 let size_cells = self.size_cells()?;
208 Ok(Some(RangesIterator::<A, P, S>::new(
209 cells,
210 addr_cells,
211 parent_addr_cells,
212 size_cells,
213 )))
214 } else {
215 Ok(None)
216 }
217 }
218
Jaewan Kimaa638702023-09-19 13:34:01 +0900219 /// Returns the node name.
220 pub fn name(&self) -> Result<&'a CStr> {
221 let mut len: c_int = 0;
222 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor). On success, the
223 // function returns valid null terminating string and otherwise returned values are dropped.
224 let name = unsafe { libfdt_bindgen::fdt_get_name(self.fdt.as_ptr(), self.offset, &mut len) }
225 as *const c_void;
226 let len = usize::try_from(fdt_err(len)?).unwrap();
227 let name = self.fdt.get_from_ptr(name, len + 1)?;
228 CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
229 }
230
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900231 /// Returns the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000232 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000233 if let Some(bytes) = self.getprop(name)? {
234 Ok(Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000235 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000236 Ok(None)
237 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100238 }
239
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900240 /// Returns the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000241 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
242 if let Some(cells) = self.getprop(name)? {
243 Ok(Some(CellIterator::new(cells)))
244 } else {
245 Ok(None)
246 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100247 }
248
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900249 /// Returns the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000250 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000251 if let Some(bytes) = self.getprop(name)? {
252 Ok(Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000253 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000254 Ok(None)
255 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100256 }
257
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900258 /// Returns the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000259 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000260 if let Some(bytes) = self.getprop(name)? {
261 Ok(Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000262 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000263 Ok(None)
264 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100265 }
266
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900267 /// Returns the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000268 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900269 if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
Jaewan Kimaa638702023-09-19 13:34:01 +0900270 Ok(Some(self.fdt.get_from_ptr(prop, len)?))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900271 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000272 Ok(None)
Jiyong Park9c63cd12023-03-21 17:53:07 +0900273 }
274 }
275
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900276 /// Returns the pointer and size of the property named `name`, in a node at offset `offset`, in
Jiyong Park9c63cd12023-03-21 17:53:07 +0900277 /// a device tree `fdt`. The pointer is guaranteed to be non-null, in which case error returns.
278 fn getprop_internal(
279 fdt: &'a Fdt,
280 offset: c_int,
281 name: &CStr,
282 ) -> Result<Option<(*const c_void, usize)>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100283 let mut len: i32 = 0;
Andrew Walbran84b9a232023-07-05 14:01:40 +0000284 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +0100285 // function respects the passed number of characters.
286 let prop = unsafe {
287 libfdt_bindgen::fdt_getprop_namelen(
Jiyong Park9c63cd12023-03-21 17:53:07 +0900288 fdt.as_ptr(),
289 offset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100290 name.as_ptr(),
291 // *_namelen functions don't include the trailing nul terminator in 'len'.
292 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
293 &mut len as *mut i32,
294 )
295 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000296
297 let Some(len) = fdt_err_or_option(len)? else {
298 return Ok(None); // Property was not found.
299 };
Jaewan Kimaa638702023-09-19 13:34:01 +0900300 let len = usize::try_from(len).unwrap();
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000301
David Brazdil1baa9a92022-06-28 14:47:50 +0100302 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000303 // We expected an error code in len but still received a valid value?!
304 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100305 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900306 Ok(Some((prop.cast::<c_void>(), len)))
David Brazdil1baa9a92022-06-28 14:47:50 +0100307 }
308
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900309 /// Returns reference to the containing device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100310 pub fn fdt(&self) -> &Fdt {
311 self.fdt
312 }
313
Alice Wang474c0ee2023-09-14 12:52:33 +0000314 /// Returns the compatible node of the given name that is next after this node.
315 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000316 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000317
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000318 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000319 }
320
Alice Wang474c0ee2023-09-14 12:52:33 +0000321 /// Returns the first range of `reg` in this node.
322 pub fn first_reg(&self) -> Result<Reg<u64>> {
323 self.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
324 }
325
David Brazdil1baa9a92022-06-28 14:47:50 +0100326 fn address_cells(&self) -> Result<AddrCells> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000327 self.fdt.address_cells(self.offset)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100328 }
329
330 fn size_cells(&self) -> Result<SizeCells> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000331 self.fdt.size_cells(self.offset)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100332 }
Jaewan Kimbc828d72023-09-19 15:52:08 +0900333
334 /// Returns an iterator of subnodes
Jaewan Kim4a34b0d2024-01-19 13:17:47 +0900335 pub fn subnodes(&self) -> Result<SubnodeIterator<'a>> {
Jaewan Kimbc828d72023-09-19 15:52:08 +0900336 SubnodeIterator::new(self)
337 }
338
339 fn first_subnode(&self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000340 let offset = self.fdt.first_subnode(self.offset)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900341
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000342 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900343 }
344
345 fn next_subnode(&self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000346 let offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900347
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000348 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900349 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900350
Jaewan Kimc9e14112023-12-04 17:05:27 +0900351 /// Returns an iterator of descendants
Jaewan Kim1eab7232024-01-04 09:46:16 +0900352 pub fn descendants(&self) -> DescendantsIterator<'a> {
Jaewan Kimc9e14112023-12-04 17:05:27 +0900353 DescendantsIterator::new(self)
354 }
355
356 fn next_node(&self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000357 if let Some((offset, depth)) = self.fdt.next_node(self.offset, depth)? {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000358 Ok(Some((Self { fdt: self.fdt, offset }, depth)))
359 } else {
360 Ok(None)
361 }
Jaewan Kimc9e14112023-12-04 17:05:27 +0900362 }
363
Jaewan Kim72d10902023-10-12 21:59:26 +0900364 /// Returns an iterator of properties
365 pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
366 PropertyIterator::new(self)
367 }
368
369 fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
370 let ret =
371 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
372 unsafe { libfdt_bindgen::fdt_first_property_offset(self.fdt.as_ptr(), self.offset) };
373
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000374 if let Some(offset) = fdt_err_or_option(ret)? {
375 Ok(Some(FdtProperty::new(self.fdt, offset)?))
376 } else {
377 Ok(None)
378 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900379 }
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900380
381 /// Returns the phandle
382 pub fn get_phandle(&self) -> Result<Option<Phandle>> {
383 // This rewrites the fdt_get_phandle() because it doesn't return error code.
384 if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
385 Ok(Some(prop.try_into()?))
386 } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
387 Ok(Some(prop.try_into()?))
388 } else {
389 Ok(None)
390 }
391 }
Jaewan Kim52026012023-12-13 13:49:28 +0900392
393 /// Returns the subnode of the given name. The name doesn't need to be nul-terminated.
394 pub fn subnode(&self, name: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000395 let name = name.to_bytes();
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000396 let offset = self.fdt.subnode_offset_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000397
Jaewan Kim52026012023-12-13 13:49:28 +0900398 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
399 }
400
401 /// Returns the subnode of the given name bytes
402 pub fn subnode_with_name_bytes(&self, name: &[u8]) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000403 let offset = self.fdt.subnode_offset_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000404
Jaewan Kim52026012023-12-13 13:49:28 +0900405 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
406 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100407}
408
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000409impl<'a> PartialEq for FdtNode<'a> {
410 fn eq(&self, other: &Self) -> bool {
411 self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
412 }
413}
414
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000415/// Mutable FDT node.
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000416#[derive(Debug)]
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000417pub struct FdtNodeMut<'a> {
418 fdt: &'a mut Fdt,
419 offset: c_int,
420}
421
422impl<'a> FdtNodeMut<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900423 /// Appends a property name-value (possibly empty) pair to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000424 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000425 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000426 let ret = unsafe {
427 libfdt_bindgen::fdt_appendprop(
428 self.fdt.as_mut_ptr(),
429 self.offset,
430 name.as_ptr(),
431 value.as_ref().as_ptr().cast::<c_void>(),
432 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
433 )
434 };
435
436 fdt_err_expect_zero(ret)
437 }
438
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900439 /// Appends a (address, size) pair property to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000440 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000441 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000442 let ret = unsafe {
443 libfdt_bindgen::fdt_appendprop_addrrange(
444 self.fdt.as_mut_ptr(),
445 self.parent()?.offset,
446 self.offset,
447 name.as_ptr(),
448 addr,
449 size,
450 )
451 };
452
453 fdt_err_expect_zero(ret)
454 }
455
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900456 /// Sets a property name-value pair to the given node.
457 ///
458 /// This may create a new prop or replace existing value.
Jaewan Kimba8929b2023-01-13 11:13:29 +0900459 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000460 // SAFETY: New value size is constrained to the DT totalsize
Jaewan Kimba8929b2023-01-13 11:13:29 +0900461 // (validated by underlying libfdt).
462 let ret = unsafe {
463 libfdt_bindgen::fdt_setprop(
464 self.fdt.as_mut_ptr(),
465 self.offset,
466 name.as_ptr(),
467 value.as_ptr().cast::<c_void>(),
468 value.len().try_into().map_err(|_| FdtError::BadValue)?,
469 )
470 };
471
472 fdt_err_expect_zero(ret)
473 }
474
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900475 /// Sets the value of the given property with the given value, and ensure that the given
476 /// value has the same length as the current value length.
477 ///
478 /// This can only be used to replace existing value.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900479 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000480 // SAFETY: fdt size is not altered
Jiyong Park9c63cd12023-03-21 17:53:07 +0900481 let ret = unsafe {
482 libfdt_bindgen::fdt_setprop_inplace(
483 self.fdt.as_mut_ptr(),
484 self.offset,
485 name.as_ptr(),
486 value.as_ptr().cast::<c_void>(),
487 value.len().try_into().map_err(|_| FdtError::BadValue)?,
488 )
489 };
490
491 fdt_err_expect_zero(ret)
492 }
493
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900494 /// Sets the value of the given (address, size) pair property with the given value, and
495 /// ensure that the given value has the same length as the current value length.
496 ///
497 /// This can only be used to replace existing value.
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000498 pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
499 let pair = [addr.to_be(), size.to_be()];
500 self.setprop_inplace(name, pair.as_bytes())
501 }
502
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900503 /// Sets a flag-like empty property.
504 ///
505 /// This may create a new prop or replace existing value.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000506 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
507 self.setprop(name, &[])
508 }
509
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900510 /// Deletes the given property.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000511 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000512 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000513 // library locates the node's property. Removing the property may shift the offsets of
514 // other nodes and properties but the borrow checker should prevent this function from
515 // being called when FdtNode instances are in use.
516 let ret = unsafe {
517 libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
518 };
519
520 fdt_err_expect_zero(ret)
521 }
522
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900523 /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000524 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000525 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000526 // library locates the node's property.
527 let ret = unsafe {
528 libfdt_bindgen::fdt_nop_property(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
529 };
530
531 fdt_err_expect_zero(ret)
532 }
533
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900534 /// Trims the size of the given property to new_size.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900535 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
536 let (prop, len) =
537 FdtNode::getprop_internal(self.fdt, self.offset, name)?.ok_or(FdtError::NotFound)?;
538 if len == new_size {
539 return Ok(());
540 }
541 if new_size > len {
542 return Err(FdtError::NoSpace);
543 }
544
Andrew Walbran84b9a232023-07-05 14:01:40 +0000545 // SAFETY: new_size is smaller than the old size
Jiyong Park9c63cd12023-03-21 17:53:07 +0900546 let ret = unsafe {
547 libfdt_bindgen::fdt_setprop(
548 self.fdt.as_mut_ptr(),
549 self.offset,
550 name.as_ptr(),
551 prop.cast::<c_void>(),
552 new_size.try_into().map_err(|_| FdtError::BadValue)?,
553 )
554 };
555
556 fdt_err_expect_zero(ret)
557 }
558
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900559 /// Returns reference to the containing device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000560 pub fn fdt(&mut self) -> &mut Fdt {
561 self.fdt
562 }
563
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900564 /// Returns immutable FdtNode of this node.
565 pub fn as_node(&self) -> FdtNode {
566 FdtNode { fdt: self.fdt, offset: self.offset }
567 }
568
Jaewan Kime6363422024-01-19 14:00:00 +0900569 /// Adds new subnodes to the given node.
570 pub fn add_subnodes(&mut self, names: &[&CStr]) -> Result<()> {
571 for name in names {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000572 self.fdt.add_subnode_namelen(self.offset, name.to_bytes())?;
Jaewan Kime6363422024-01-19 14:00:00 +0900573 }
574 Ok(())
575 }
576
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900577 /// 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 +0000578 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000579 let name = name.to_bytes();
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000580 let offset = self.fdt.add_subnode_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000581
Jaewan Kim5ab13582023-10-20 20:56:27 +0900582 Ok(Self { fdt: self.fdt, offset })
583 }
584
585 /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
586 /// on success.
587 pub fn add_subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000588 let name = &name.to_bytes()[..namelen];
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000589 let offset = self.fdt.add_subnode_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000590
Jaewan Kim5ab13582023-10-20 20:56:27 +0900591 Ok(Self { fdt: self.fdt, offset })
592 }
593
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900594 /// Returns the first subnode of this
595 pub fn first_subnode(&'a mut self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000596 let offset = self.fdt.first_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900597
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000598 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900599 }
600
601 /// Returns the next subnode that shares the same parent with this
602 pub fn next_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000603 let offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900604
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000605 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900606 }
607
608 /// Deletes the current node and returns the next subnode
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000609 pub fn delete_and_next_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000610 let next_offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900611
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000612 self.delete_and_next(next_offset)
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900613 }
614
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900615 /// Returns the next node
616 pub fn next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000617 let next = self.fdt.next_node(self.offset, depth)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000618
619 Ok(next.map(|(offset, depth)| (Self { fdt: self.fdt, offset }, depth)))
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900620 }
621
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000622 /// Deletes this and returns the next node
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000623 pub fn delete_and_next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
624 let next_node = self.fdt.next_node_skip_subnodes(self.offset, depth)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000625 if let Some((offset, depth)) = next_node {
626 let next_node = self.delete_and_next(Some(offset))?.unwrap();
627 Ok(Some((next_node, depth)))
628 } else {
629 Ok(None)
630 }
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900631 }
632
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000633 fn parent(&'a self) -> Result<FdtNode<'a>> {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000634 self.as_node().parent()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000635 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900636
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900637 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900638 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000639 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900640
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000641 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900642 }
643
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900644 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
645 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900646 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
647 // The reason is that libfdt ensures that the node from where the search for the next
648 // compatible node is started is always a valid one -- except for the special case of offset =
649 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
650 // next compatible node from it.
651 //
652 // We can't do in the opposite direction either. If we call next_compatible to find the next
653 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
654 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
655 // DT).
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000656 pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000657 let next_offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900658
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000659 self.delete_and_next(next_offset)
660 }
661
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000662 fn delete_and_next(self, next_offset: Option<c_int>) -> Result<Option<Self>> {
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900663 if Some(self.offset) == next_offset {
664 return Err(FdtError::Internal);
665 }
666
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000667 self.fdt.nop_node(self.offset)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900668
669 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
670 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900671
672 /// Deletes this node effectively from DT, by setting it with FDT_NOP
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000673 pub fn nop(self) -> Result<()> {
674 self.fdt.nop_node(self.offset)
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900675 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000676}
677
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000678/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000679#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100680#[repr(transparent)]
681pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000682 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100683}
684
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000685// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
686// methods to be called on invalid device trees.
687unsafe impl Libfdt for Fdt {
688 fn as_fdt_slice(&self) -> &[u8] {
689 &self.buffer[..self.totalsize()]
690 }
691}
692
693// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
694// methods to be called on invalid device trees.
695unsafe impl LibfdtMut for Fdt {
696 fn as_fdt_slice_mut(&mut self) -> &mut [u8] {
697 &mut self.buffer
698 }
699}
700
David Brazdil1baa9a92022-06-28 14:47:50 +0100701impl Fdt {
702 /// Wraps a slice containing a Flattened Device Tree.
703 ///
704 /// Fails if the FDT does not pass validation.
705 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000706 libfdt::check_full(fdt)?;
707 // SAFETY: The FDT was validated.
David Brazdil1baa9a92022-06-28 14:47:50 +0100708 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000709
David Brazdil1baa9a92022-06-28 14:47:50 +0100710 Ok(fdt)
711 }
712
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000713 /// Wraps a mutable slice containing a Flattened Device Tree.
714 ///
715 /// Fails if the FDT does not pass validation.
716 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000717 libfdt::check_full(fdt)?;
718 // SAFETY: The FDT was validated.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000719 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000720
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000721 Ok(fdt)
722 }
723
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900724 /// Creates an empty Flattened Device Tree with a mutable slice.
725 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000726 libfdt::create_empty_tree(fdt)?;
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900727
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000728 Self::from_mut_slice(fdt)
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900729 }
730
David Brazdil1baa9a92022-06-28 14:47:50 +0100731 /// Wraps a slice containing a Flattened Device Tree.
732 ///
733 /// # Safety
734 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000735 /// 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 +0100736 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000737 let self_ptr = fdt as *const _ as *const _;
738 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
739 unsafe { &*self_ptr }
David Brazdil1baa9a92022-06-28 14:47:50 +0100740 }
741
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000742 /// Wraps a mutable slice containing a Flattened Device Tree.
743 ///
744 /// # Safety
745 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000746 /// 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 +0000747 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000748 let self_mut_ptr = fdt as *mut _ as *mut _;
749 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
750 unsafe { &mut *self_mut_ptr }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000751 }
752
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000753 /// Updates this FDT from another FDT.
754 pub fn clone_from(&mut self, other: &Self) -> Result<()> {
755 let new_len = other.buffer.len();
756 if self.buffer.len() < new_len {
757 return Err(FdtError::NoSpace);
Jiyong Parke9d87e82023-03-21 19:28:40 +0900758 }
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000759
760 let zeroed_len = self.totalsize().checked_sub(new_len);
761 let (cloned, zeroed) = self.buffer.split_at_mut(new_len);
762
763 cloned.clone_from_slice(&other.buffer);
764 if let Some(len) = zeroed_len {
765 zeroed[..len].fill(0);
766 }
767
768 Ok(())
Jiyong Parke9d87e82023-03-21 19:28:40 +0900769 }
770
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900771 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000772 pub fn unpack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000773 // SAFETY: "Opens" the DT in-place (supported use-case) by updating its header and
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000774 // internal structures to make use of the whole self.fdt slice but performs no accesses
775 // outside of it and leaves the DT in a state that will be detected by other functions.
776 let ret = unsafe {
777 libfdt_bindgen::fdt_open_into(
778 self.as_ptr(),
779 self.as_mut_ptr(),
780 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
781 )
782 };
783 fdt_err_expect_zero(ret)
784 }
785
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900786 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000787 ///
788 /// Doesn't shrink the underlying memory slice.
789 pub fn pack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000790 // SAFETY: "Closes" the DT in-place by updating its header and relocating its structs.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000791 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
792 fdt_err_expect_zero(ret)
793 }
794
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000795 /// Applies a DT overlay on the base DT.
796 ///
797 /// # Safety
798 ///
799 /// On failure, the library corrupts the DT and overlay so both must be discarded.
800 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000801 let ret =
802 // SAFETY: Both pointers are valid because they come from references, and fdt_overlay_apply
803 // doesn't keep them after it returns. It may corrupt their contents if there is an error,
804 // but that's our caller's responsibility.
805 unsafe { libfdt_bindgen::fdt_overlay_apply(self.as_mut_ptr(), overlay.as_mut_ptr()) };
806 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000807 Ok(self)
808 }
809
Alice Wang2422bdc2023-06-12 08:37:55 +0000810 /// Returns an iterator of memory banks specified the "/memory" node.
811 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100812 ///
813 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +0000814 pub fn memory(&self) -> Result<MemRegIterator> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000815 let node = self.node(cstr!("/memory"))?.ok_or(FdtError::NotFound)?;
816 if node.device_type()? != Some(cstr!("memory")) {
Alice Wang2422bdc2023-06-12 08:37:55 +0000817 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000818 }
Alice Wang2422bdc2023-06-12 08:37:55 +0000819 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
820 }
821
822 /// Returns the first memory range in the `/memory` node.
823 pub fn first_memory_range(&self) -> Result<Range<usize>> {
824 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +0100825 }
826
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900827 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000828 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900829 self.node(cstr!("/chosen"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100830 }
831
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900832 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000833 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900834 self.node_mut(cstr!("/chosen"))
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000835 }
836
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900837 /// Returns the root node of the tree.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000838 pub fn root(&self) -> Result<FdtNode> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900839 self.node(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000840 }
841
Jaewan Kimf163d762023-11-01 13:12:50 +0900842 /// Returns the standard /__symbols__ node.
843 pub fn symbols(&self) -> Result<Option<FdtNode>> {
844 self.node(cstr!("/__symbols__"))
845 }
846
847 /// Returns the standard /__symbols__ node as mutable
848 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
849 self.node_mut(cstr!("/__symbols__"))
850 }
851
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900852 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000853 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000854 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000855
856 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100857 }
858
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000859 /// Iterate over nodes with a given compatible string.
860 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
861 CompatibleIterator::new(self, compatible)
862 }
863
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900864 /// Returns max phandle in the tree.
865 pub fn max_phandle(&self) -> Result<Phandle> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000866 self.find_max_phandle()
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900867 }
868
869 /// Returns a node with the phandle
870 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000871 let offset = self.node_offset_by_phandle(phandle)?;
872
Jaewan Kimc63246d2023-11-09 15:41:01 +0900873 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
874 }
875
876 /// Returns a mutable node with the phandle
877 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000878 let offset = self.node_offset_by_phandle(phandle)?;
Jaewan Kimc63246d2023-11-09 15:41:01 +0900879
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000880 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900881 }
882
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900883 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000884 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900885 self.node_mut(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000886 }
887
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900888 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000889 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000890 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000891
892 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000893 }
894
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000895 fn next_node_skip_subnodes(&self, node: c_int, depth: usize) -> Result<Option<(c_int, usize)>> {
896 let mut iter = self.next_node(node, depth)?;
897 while let Some((offset, next_depth)) = iter {
898 if next_depth <= depth {
899 return Ok(Some((offset, next_depth)));
900 }
901 iter = self.next_node(offset, next_depth)?;
902 }
903
904 Ok(None)
905 }
906
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900907 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000908 pub fn as_slice(&self) -> &[u8] {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000909 self.as_fdt_slice()
David Brazdil1baa9a92022-06-28 14:47:50 +0100910 }
911
Jaewan Kimaa638702023-09-19 13:34:01 +0900912 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
913 let ptr = ptr as usize;
914 let offset = ptr.checked_sub(self.as_ptr() as usize).ok_or(FdtError::Internal)?;
915 self.buffer.get(offset..(offset + len)).ok_or(FdtError::Internal)
916 }
917
Jaewan Kim72d10902023-10-12 21:59:26 +0900918 fn string(&self, offset: c_int) -> Result<&CStr> {
919 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
920 let res = unsafe { libfdt_bindgen::fdt_string(self.as_ptr(), offset) };
921 if res.is_null() {
922 return Err(FdtError::Internal);
923 }
924
925 // SAFETY: Non-null return from fdt_string() is valid null-terminating string within FDT.
926 Ok(unsafe { CStr::from_ptr(res) })
927 }
928
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900929 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +0000930 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000931 self.buffer.as_ptr().cast()
David Brazdil1baa9a92022-06-28 14:47:50 +0100932 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000933
934 fn as_mut_ptr(&mut self) -> *mut c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000935 self.buffer.as_mut_ptr().cast::<_>()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000936 }
937
938 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000939 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000940 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000941
942 fn header(&self) -> &libfdt_bindgen::fdt_header {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000943 let p = self.as_ptr().cast();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000944 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000945 unsafe { &*p }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000946 }
947
948 fn totalsize(&self) -> usize {
949 u32::from_be(self.header().totalsize) as usize
950 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100951}