blob: 299b1d30d280c4dc77d752e92acdecb98f7e996c [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 Tosi60282ae2023-12-21 16:00:02 +000035use libfdt::get_slice_at_ptr;
Pierre-Clément Tosi99a76902023-12-21 10:30:37 +000036use result::{fdt_err, fdt_err_expect_zero, fdt_err_or_option};
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +000037use zerocopy::AsBytes as _;
David Brazdil1baa9a92022-06-28 14:47:50 +010038
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +000039use crate::libfdt::{Libfdt, LibfdtMut};
40
David Brazdil1baa9a92022-06-28 14:47:50 +010041/// Value of a #address-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +000042#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +010043enum AddrCells {
44 Single = 1,
45 Double = 2,
Andrew Walbranb39e6922022-12-05 17:01:20 +000046 Triple = 3,
David Brazdil1baa9a92022-06-28 14:47:50 +010047}
48
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000049impl TryFrom<usize> for AddrCells {
David Brazdil1baa9a92022-06-28 14:47:50 +010050 type Error = FdtError;
51
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000052 fn try_from(value: usize) -> Result<Self> {
53 match value {
54 x if x == Self::Single as _ => Ok(Self::Single),
55 x if x == Self::Double as _ => Ok(Self::Double),
56 x if x == Self::Triple as _ => Ok(Self::Triple),
David Brazdil1baa9a92022-06-28 14:47:50 +010057 _ => Err(FdtError::BadNCells),
58 }
59 }
60}
61
62/// Value of a #size-cells property.
Andrew Walbranb39e6922022-12-05 17:01:20 +000063#[derive(Copy, Clone, Debug, Eq, PartialEq)]
David Brazdil1baa9a92022-06-28 14:47:50 +010064enum SizeCells {
65 None = 0,
66 Single = 1,
67 Double = 2,
68}
69
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000070impl TryFrom<usize> for SizeCells {
David Brazdil1baa9a92022-06-28 14:47:50 +010071 type Error = FdtError;
72
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +000073 fn try_from(value: usize) -> Result<Self> {
74 match value {
75 x if x == Self::None as _ => Ok(Self::None),
76 x if x == Self::Single as _ => Ok(Self::Single),
77 x if x == Self::Double as _ => Ok(Self::Double),
David Brazdil1baa9a92022-06-28 14:47:50 +010078 _ => Err(FdtError::BadNCells),
79 }
80 }
81}
82
Jaewan Kim72d10902023-10-12 21:59:26 +090083/// DT property wrapper to abstract endianess changes
84#[repr(transparent)]
85#[derive(Debug)]
86struct FdtPropertyStruct(libfdt_bindgen::fdt_property);
87
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +000088impl AsRef<FdtPropertyStruct> for libfdt_bindgen::fdt_property {
89 fn as_ref(&self) -> &FdtPropertyStruct {
90 let ptr = self as *const _ as *const _;
91 // SAFETY: Types have the same layout (transparent) so the valid reference remains valid.
92 unsafe { &*ptr }
93 }
94}
95
Jaewan Kim72d10902023-10-12 21:59:26 +090096impl FdtPropertyStruct {
97 fn from_offset(fdt: &Fdt, offset: c_int) -> Result<&Self> {
98 let mut len = 0;
99 let prop =
100 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
101 unsafe { libfdt_bindgen::fdt_get_property_by_offset(fdt.as_ptr(), offset, &mut len) };
102 if prop.is_null() {
103 fdt_err(len)?;
104 return Err(FdtError::Internal); // shouldn't happen.
105 }
106 // SAFETY: prop is only returned when it points to valid libfdt_bindgen.
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000107 let prop = unsafe { &*prop };
108 Ok(prop.as_ref())
Jaewan Kim72d10902023-10-12 21:59:26 +0900109 }
110
111 fn name_offset(&self) -> c_int {
112 u32::from_be(self.0.nameoff).try_into().unwrap()
113 }
114
115 fn data_len(&self) -> usize {
116 u32::from_be(self.0.len).try_into().unwrap()
117 }
118
119 fn data_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000120 self.0.data.as_ptr().cast()
Jaewan Kim72d10902023-10-12 21:59:26 +0900121 }
122}
123
124/// DT property.
125#[derive(Clone, Copy, Debug)]
126pub struct FdtProperty<'a> {
127 fdt: &'a Fdt,
128 offset: c_int,
129 property: &'a FdtPropertyStruct,
130}
131
132impl<'a> FdtProperty<'a> {
133 fn new(fdt: &'a Fdt, offset: c_int) -> Result<Self> {
134 let property = FdtPropertyStruct::from_offset(fdt, offset)?;
135 Ok(Self { fdt, offset, property })
136 }
137
138 /// Returns the property name
139 pub fn name(&self) -> Result<&'a CStr> {
140 self.fdt.string(self.property.name_offset())
141 }
142
143 /// Returns the property value
144 pub fn value(&self) -> Result<&'a [u8]> {
145 self.fdt.get_from_ptr(self.property.data_ptr(), self.property.data_len())
146 }
147
148 fn next_property(&self) -> Result<Option<Self>> {
149 let ret =
150 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
151 unsafe { libfdt_bindgen::fdt_next_property_offset(self.fdt.as_ptr(), self.offset) };
152
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000153 if let Some(offset) = fdt_err_or_option(ret)? {
154 Ok(Some(Self::new(self.fdt, offset)?))
155 } else {
156 Ok(None)
157 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900158 }
159}
160
David Brazdil1baa9a92022-06-28 14:47:50 +0100161/// DT node.
Alice Wang9d4df702023-05-25 14:14:12 +0000162#[derive(Clone, Copy, Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100163pub struct FdtNode<'a> {
164 fdt: &'a Fdt,
165 offset: c_int,
166}
167
168impl<'a> FdtNode<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900169 /// Returns parent node.
David Brazdil1baa9a92022-06-28 14:47:50 +0100170 pub fn parent(&self) -> Result<Self> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000171 let offset = self.fdt.parent_offset(self.offset)?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100172
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000173 Ok(Self { fdt: self.fdt, offset })
David Brazdil1baa9a92022-06-28 14:47:50 +0100174 }
175
Jaewan Kim5b057772023-10-19 01:02:17 +0900176 /// Returns supernode with depth. Note that root is at depth 0.
177 pub fn supernode_at_depth(&self, depth: usize) -> Result<Self> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000178 let offset = self.fdt.supernode_atdepth_offset(self.offset, depth)?;
Jaewan Kim5b057772023-10-19 01:02:17 +0900179
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000180 Ok(Self { fdt: self.fdt, offset })
Jaewan Kim5b057772023-10-19 01:02:17 +0900181 }
182
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900183 /// Returns the standard (deprecated) device_type <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000184 pub fn device_type(&self) -> Result<Option<&CStr>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900185 self.getprop_str(cstr!("device_type"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100186 }
187
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900188 /// Returns the standard reg <prop-encoded-array> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000189 pub fn reg(&self) -> Result<Option<RegIterator<'a>>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000190 if let Some(cells) = self.getprop_cells(cstr!("reg"))? {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000191 let parent = self.parent()?;
David Brazdil1baa9a92022-06-28 14:47:50 +0100192
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000193 let addr_cells = parent.address_cells()?;
194 let size_cells = parent.size_cells()?;
195
196 Ok(Some(RegIterator::new(cells, addr_cells, size_cells)))
197 } else {
198 Ok(None)
199 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100200 }
201
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900202 /// Returns the standard ranges property.
Andrew Walbranb39e6922022-12-05 17:01:20 +0000203 pub fn ranges<A, P, S>(&self) -> Result<Option<RangesIterator<'a, A, P, S>>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000204 if let Some(cells) = self.getprop_cells(cstr!("ranges"))? {
Andrew Walbranb39e6922022-12-05 17:01:20 +0000205 let parent = self.parent()?;
206 let addr_cells = self.address_cells()?;
207 let parent_addr_cells = parent.address_cells()?;
208 let size_cells = self.size_cells()?;
209 Ok(Some(RangesIterator::<A, P, S>::new(
210 cells,
211 addr_cells,
212 parent_addr_cells,
213 size_cells,
214 )))
215 } else {
216 Ok(None)
217 }
218 }
219
Jaewan Kimaa638702023-09-19 13:34:01 +0900220 /// Returns the node name.
221 pub fn name(&self) -> Result<&'a CStr> {
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +0000222 let name = self.fdt.get_name(self.offset)?;
Jaewan Kimaa638702023-09-19 13:34:01 +0900223 CStr::from_bytes_with_nul(name).map_err(|_| FdtError::Internal)
224 }
225
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900226 /// Returns the value of a given <string> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000227 pub fn getprop_str(&self, name: &CStr) -> Result<Option<&CStr>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000228 if let Some(bytes) = self.getprop(name)? {
229 Ok(Some(CStr::from_bytes_with_nul(bytes).map_err(|_| FdtError::BadValue)?))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000230 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000231 Ok(None)
232 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100233 }
234
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900235 /// Returns the value of a given property as an array of cells.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000236 pub fn getprop_cells(&self, name: &CStr) -> Result<Option<CellIterator<'a>>> {
237 if let Some(cells) = self.getprop(name)? {
238 Ok(Some(CellIterator::new(cells)))
239 } else {
240 Ok(None)
241 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100242 }
243
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900244 /// Returns the value of a given <u32> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000245 pub fn getprop_u32(&self, name: &CStr) -> Result<Option<u32>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000246 if let Some(bytes) = self.getprop(name)? {
247 Ok(Some(u32::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000248 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000249 Ok(None)
250 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100251 }
252
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900253 /// Returns the value of a given <u64> property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000254 pub fn getprop_u64(&self, name: &CStr) -> Result<Option<u64>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000255 if let Some(bytes) = self.getprop(name)? {
256 Ok(Some(u64::from_be_bytes(bytes.try_into().map_err(|_| FdtError::BadValue)?)))
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000257 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000258 Ok(None)
259 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100260 }
261
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900262 /// Returns the value of a given property.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000263 pub fn getprop(&self, name: &CStr) -> Result<Option<&'a [u8]>> {
Jiyong Park9c63cd12023-03-21 17:53:07 +0900264 if let Some((prop, len)) = Self::getprop_internal(self.fdt, self.offset, name)? {
Jaewan Kimaa638702023-09-19 13:34:01 +0900265 Ok(Some(self.fdt.get_from_ptr(prop, len)?))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900266 } else {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000267 Ok(None)
Jiyong Park9c63cd12023-03-21 17:53:07 +0900268 }
269 }
270
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900271 /// Returns the pointer and size of the property named `name`, in a node at offset `offset`, in
Jiyong Park9c63cd12023-03-21 17:53:07 +0900272 /// a device tree `fdt`. The pointer is guaranteed to be non-null, in which case error returns.
273 fn getprop_internal(
274 fdt: &'a Fdt,
275 offset: c_int,
276 name: &CStr,
277 ) -> Result<Option<(*const c_void, usize)>> {
David Brazdil1baa9a92022-06-28 14:47:50 +0100278 let mut len: i32 = 0;
Andrew Walbran84b9a232023-07-05 14:01:40 +0000279 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) and the
David Brazdil1baa9a92022-06-28 14:47:50 +0100280 // function respects the passed number of characters.
281 let prop = unsafe {
282 libfdt_bindgen::fdt_getprop_namelen(
Jiyong Park9c63cd12023-03-21 17:53:07 +0900283 fdt.as_ptr(),
284 offset,
David Brazdil1baa9a92022-06-28 14:47:50 +0100285 name.as_ptr(),
286 // *_namelen functions don't include the trailing nul terminator in 'len'.
287 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
288 &mut len as *mut i32,
289 )
290 } as *const u8;
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000291
292 let Some(len) = fdt_err_or_option(len)? else {
293 return Ok(None); // Property was not found.
294 };
Jaewan Kimaa638702023-09-19 13:34:01 +0900295 let len = usize::try_from(len).unwrap();
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000296
David Brazdil1baa9a92022-06-28 14:47:50 +0100297 if prop.is_null() {
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000298 // We expected an error code in len but still received a valid value?!
299 return Err(FdtError::Internal);
David Brazdil1baa9a92022-06-28 14:47:50 +0100300 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900301 Ok(Some((prop.cast::<c_void>(), len)))
David Brazdil1baa9a92022-06-28 14:47:50 +0100302 }
303
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900304 /// Returns reference to the containing device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100305 pub fn fdt(&self) -> &Fdt {
306 self.fdt
307 }
308
Alice Wang474c0ee2023-09-14 12:52:33 +0000309 /// Returns the compatible node of the given name that is next after this node.
310 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000311 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000312
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000313 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000314 }
315
Alice Wang474c0ee2023-09-14 12:52:33 +0000316 /// Returns the first range of `reg` in this node.
317 pub fn first_reg(&self) -> Result<Reg<u64>> {
318 self.reg()?.ok_or(FdtError::NotFound)?.next().ok_or(FdtError::NotFound)
319 }
320
David Brazdil1baa9a92022-06-28 14:47:50 +0100321 fn address_cells(&self) -> Result<AddrCells> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000322 self.fdt.address_cells(self.offset)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100323 }
324
325 fn size_cells(&self) -> Result<SizeCells> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000326 self.fdt.size_cells(self.offset)?.try_into()
David Brazdil1baa9a92022-06-28 14:47:50 +0100327 }
Jaewan Kimbc828d72023-09-19 15:52:08 +0900328
329 /// Returns an iterator of subnodes
Jaewan Kim4a34b0d2024-01-19 13:17:47 +0900330 pub fn subnodes(&self) -> Result<SubnodeIterator<'a>> {
Jaewan Kimbc828d72023-09-19 15:52:08 +0900331 SubnodeIterator::new(self)
332 }
333
334 fn first_subnode(&self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000335 let offset = self.fdt.first_subnode(self.offset)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900336
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000337 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900338 }
339
340 fn next_subnode(&self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000341 let offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kimbc828d72023-09-19 15:52:08 +0900342
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000343 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kimbc828d72023-09-19 15:52:08 +0900344 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900345
Jaewan Kimc9e14112023-12-04 17:05:27 +0900346 /// Returns an iterator of descendants
Jaewan Kim1eab7232024-01-04 09:46:16 +0900347 pub fn descendants(&self) -> DescendantsIterator<'a> {
Jaewan Kimc9e14112023-12-04 17:05:27 +0900348 DescendantsIterator::new(self)
349 }
350
351 fn next_node(&self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000352 if let Some((offset, depth)) = self.fdt.next_node(self.offset, depth)? {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000353 Ok(Some((Self { fdt: self.fdt, offset }, depth)))
354 } else {
355 Ok(None)
356 }
Jaewan Kimc9e14112023-12-04 17:05:27 +0900357 }
358
Jaewan Kim72d10902023-10-12 21:59:26 +0900359 /// Returns an iterator of properties
360 pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
361 PropertyIterator::new(self)
362 }
363
364 fn first_property(&self) -> Result<Option<FdtProperty<'a>>> {
365 let ret =
366 // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
367 unsafe { libfdt_bindgen::fdt_first_property_offset(self.fdt.as_ptr(), self.offset) };
368
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000369 if let Some(offset) = fdt_err_or_option(ret)? {
370 Ok(Some(FdtProperty::new(self.fdt, offset)?))
371 } else {
372 Ok(None)
373 }
Jaewan Kim72d10902023-10-12 21:59:26 +0900374 }
Jaewan Kimf34f4b82023-11-03 19:38:38 +0900375
376 /// Returns the phandle
377 pub fn get_phandle(&self) -> Result<Option<Phandle>> {
378 // This rewrites the fdt_get_phandle() because it doesn't return error code.
379 if let Some(prop) = self.getprop_u32(cstr!("phandle"))? {
380 Ok(Some(prop.try_into()?))
381 } else if let Some(prop) = self.getprop_u32(cstr!("linux,phandle"))? {
382 Ok(Some(prop.try_into()?))
383 } else {
384 Ok(None)
385 }
386 }
Jaewan Kim52026012023-12-13 13:49:28 +0900387
388 /// Returns the subnode of the given name. The name doesn't need to be nul-terminated.
389 pub fn subnode(&self, name: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000390 let name = name.to_bytes();
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000391 let offset = self.fdt.subnode_offset_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000392
Jaewan Kim52026012023-12-13 13:49:28 +0900393 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
394 }
395
396 /// Returns the subnode of the given name bytes
397 pub fn subnode_with_name_bytes(&self, name: &[u8]) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000398 let offset = self.fdt.subnode_offset_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000399
Jaewan Kim52026012023-12-13 13:49:28 +0900400 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
401 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100402}
403
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000404impl<'a> PartialEq for FdtNode<'a> {
405 fn eq(&self, other: &Self) -> bool {
406 self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
407 }
408}
409
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000410/// Mutable FDT node.
Pierre-Clément Tosi504b4302023-10-30 12:22:50 +0000411#[derive(Debug)]
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000412pub struct FdtNodeMut<'a> {
413 fdt: &'a mut Fdt,
414 offset: c_int,
415}
416
417impl<'a> FdtNodeMut<'a> {
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900418 /// Appends a property name-value (possibly empty) pair to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000419 pub fn appendprop<T: AsRef<[u8]>>(&mut self, name: &CStr, value: &T) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000420 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000421 let ret = unsafe {
422 libfdt_bindgen::fdt_appendprop(
423 self.fdt.as_mut_ptr(),
424 self.offset,
425 name.as_ptr(),
426 value.as_ref().as_ptr().cast::<c_void>(),
427 value.as_ref().len().try_into().map_err(|_| FdtError::BadValue)?,
428 )
429 };
430
431 fdt_err_expect_zero(ret)
432 }
433
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900434 /// Appends a (address, size) pair property to the given node.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000435 pub fn appendprop_addrrange(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000436 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor).
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000437 let ret = unsafe {
438 libfdt_bindgen::fdt_appendprop_addrrange(
439 self.fdt.as_mut_ptr(),
440 self.parent()?.offset,
441 self.offset,
442 name.as_ptr(),
443 addr,
444 size,
445 )
446 };
447
448 fdt_err_expect_zero(ret)
449 }
450
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900451 /// Sets a property name-value pair to the given node.
452 ///
453 /// This may create a new prop or replace existing value.
Jaewan Kimba8929b2023-01-13 11:13:29 +0900454 pub fn setprop(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000455 // SAFETY: New value size is constrained to the DT totalsize
Jaewan Kimba8929b2023-01-13 11:13:29 +0900456 // (validated by underlying libfdt).
457 let ret = unsafe {
458 libfdt_bindgen::fdt_setprop(
459 self.fdt.as_mut_ptr(),
460 self.offset,
461 name.as_ptr(),
462 value.as_ptr().cast::<c_void>(),
463 value.len().try_into().map_err(|_| FdtError::BadValue)?,
464 )
465 };
466
467 fdt_err_expect_zero(ret)
468 }
469
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900470 /// Sets the value of the given property with the given value, and ensure that the given
471 /// value has the same length as the current value length.
472 ///
473 /// This can only be used to replace existing value.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900474 pub fn setprop_inplace(&mut self, name: &CStr, value: &[u8]) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000475 // SAFETY: fdt size is not altered
Jiyong Park9c63cd12023-03-21 17:53:07 +0900476 let ret = unsafe {
477 libfdt_bindgen::fdt_setprop_inplace(
478 self.fdt.as_mut_ptr(),
479 self.offset,
480 name.as_ptr(),
481 value.as_ptr().cast::<c_void>(),
482 value.len().try_into().map_err(|_| FdtError::BadValue)?,
483 )
484 };
485
486 fdt_err_expect_zero(ret)
487 }
488
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900489 /// Sets the value of the given (address, size) pair property with the given value, and
490 /// ensure that the given value has the same length as the current value length.
491 ///
492 /// This can only be used to replace existing value.
Pierre-Clément Tosic27c4272023-05-19 15:46:26 +0000493 pub fn setprop_addrrange_inplace(&mut self, name: &CStr, addr: u64, size: u64) -> Result<()> {
494 let pair = [addr.to_be(), size.to_be()];
495 self.setprop_inplace(name, pair.as_bytes())
496 }
497
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900498 /// Sets a flag-like empty property.
499 ///
500 /// This may create a new prop or replace existing value.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000501 pub fn setprop_empty(&mut self, name: &CStr) -> Result<()> {
502 self.setprop(name, &[])
503 }
504
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900505 /// Deletes the given property.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000506 pub fn delprop(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000507 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000508 // library locates the node's property. Removing the property may shift the offsets of
509 // other nodes and properties but the borrow checker should prevent this function from
510 // being called when FdtNode instances are in use.
511 let ret = unsafe {
512 libfdt_bindgen::fdt_delprop(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
513 };
514
515 fdt_err_expect_zero(ret)
516 }
517
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900518 /// Deletes the given property effectively from DT, by setting it with FDT_NOP.
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000519 pub fn nop_property(&mut self, name: &CStr) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000520 // SAFETY: Accesses are constrained to the DT totalsize (validated by ctor) when the
Pierre-Clément Tosibe3a97b2023-05-19 14:56:23 +0000521 // library locates the node's property.
522 let ret = unsafe {
523 libfdt_bindgen::fdt_nop_property(self.fdt.as_mut_ptr(), self.offset, name.as_ptr())
524 };
525
526 fdt_err_expect_zero(ret)
527 }
528
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900529 /// Trims the size of the given property to new_size.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900530 pub fn trimprop(&mut self, name: &CStr, new_size: usize) -> Result<()> {
Pierre-Clément Tosi843845d2024-01-23 23:35:01 +0000531 let prop = self.as_node().getprop(name)?.ok_or(FdtError::NotFound)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900532
Pierre-Clément Tosi843845d2024-01-23 23:35:01 +0000533 match prop.len() {
534 x if x == new_size => Ok(()),
535 x if x < new_size => Err(FdtError::NoSpace),
536 _ => self.fdt.setprop_placeholder(self.offset, name, new_size).map(|_| ()),
537 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900538 }
539
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900540 /// Returns reference to the containing device tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000541 pub fn fdt(&mut self) -> &mut Fdt {
542 self.fdt
543 }
544
Jaewan Kimf72f4f22023-11-03 19:21:34 +0900545 /// Returns immutable FdtNode of this node.
546 pub fn as_node(&self) -> FdtNode {
547 FdtNode { fdt: self.fdt, offset: self.offset }
548 }
549
Jaewan Kime6363422024-01-19 14:00:00 +0900550 /// Adds new subnodes to the given node.
551 pub fn add_subnodes(&mut self, names: &[&CStr]) -> Result<()> {
552 for name in names {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000553 self.fdt.add_subnode_namelen(self.offset, name.to_bytes())?;
Jaewan Kime6363422024-01-19 14:00:00 +0900554 }
555 Ok(())
556 }
557
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900558 /// 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 +0000559 pub fn add_subnode(&'a mut self, name: &CStr) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000560 let name = name.to_bytes();
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000561 let offset = self.fdt.add_subnode_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000562
Jaewan Kim5ab13582023-10-20 20:56:27 +0900563 Ok(Self { fdt: self.fdt, offset })
564 }
565
566 /// Adds a new subnode to the given node with name and namelen, and returns it as a FdtNodeMut
567 /// on success.
568 pub fn add_subnode_with_namelen(&'a mut self, name: &CStr, namelen: usize) -> Result<Self> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000569 let name = &name.to_bytes()[..namelen];
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000570 let offset = self.fdt.add_subnode_namelen(self.offset, name)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000571
Jaewan Kim5ab13582023-10-20 20:56:27 +0900572 Ok(Self { fdt: self.fdt, offset })
573 }
574
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900575 /// Returns the first subnode of this
576 pub fn first_subnode(&'a mut self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000577 let offset = self.fdt.first_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900578
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000579 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900580 }
581
582 /// Returns the next subnode that shares the same parent with this
583 pub fn next_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000584 let offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900585
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000586 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900587 }
588
589 /// Deletes the current node and returns the next subnode
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000590 pub fn delete_and_next_subnode(self) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000591 let next_offset = self.fdt.next_subnode(self.offset)?;
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900592
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000593 self.delete_and_next(next_offset)
Jaewan Kim5f1a6032023-12-18 15:17:58 +0900594 }
595
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900596 /// Returns the next node
597 pub fn next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000598 let next = self.fdt.next_node(self.offset, depth)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000599
600 Ok(next.map(|(offset, depth)| (Self { fdt: self.fdt, offset }, depth)))
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900601 }
602
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000603 /// Deletes this and returns the next node
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000604 pub fn delete_and_next_node(self, depth: usize) -> Result<Option<(Self, usize)>> {
605 let next_node = self.fdt.next_node_skip_subnodes(self.offset, depth)?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000606 if let Some((offset, depth)) = next_node {
607 let next_node = self.delete_and_next(Some(offset))?.unwrap();
608 Ok(Some((next_node, depth)))
609 } else {
610 Ok(None)
611 }
Jaewan Kim28a13ea2024-01-04 09:22:40 +0900612 }
613
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000614 fn parent(&'a self) -> Result<FdtNode<'a>> {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000615 self.as_node().parent()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000616 }
Jiyong Park9c63cd12023-03-21 17:53:07 +0900617
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900618 /// Returns the compatible node of the given name that is next after this node.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900619 pub fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000620 let offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900621
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000622 Ok(offset.map(|offset| Self { fdt: self.fdt, offset }))
Jiyong Park9c63cd12023-03-21 17:53:07 +0900623 }
624
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900625 /// Deletes the node effectively by overwriting this node and its subtree with nop tags.
626 /// Returns the next compatible node of the given name.
Jiyong Park9c63cd12023-03-21 17:53:07 +0900627 // Side note: without this, filterint out excessive compatible nodes from the DT is impossible.
628 // The reason is that libfdt ensures that the node from where the search for the next
629 // compatible node is started is always a valid one -- except for the special case of offset =
630 // -1 which is to find the first compatible node. So, we can't delete a node and then find the
631 // next compatible node from it.
632 //
633 // We can't do in the opposite direction either. If we call next_compatible to find the next
634 // node, and delete the current node, the Rust borrow checker kicks in. The next node has a
635 // mutable reference to DT, so we can't use current node (which also has a mutable reference to
636 // DT).
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000637 pub fn delete_and_next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000638 let next_offset = self.fdt.node_offset_by_compatible(self.offset, compatible)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900639
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000640 self.delete_and_next(next_offset)
641 }
642
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000643 fn delete_and_next(self, next_offset: Option<c_int>) -> Result<Option<Self>> {
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900644 if Some(self.offset) == next_offset {
645 return Err(FdtError::Internal);
646 }
647
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000648 self.fdt.nop_node(self.offset)?;
Jiyong Park9c63cd12023-03-21 17:53:07 +0900649
650 Ok(next_offset.map(|offset| Self { fdt: self.fdt, offset }))
651 }
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900652
653 /// Deletes this node effectively from DT, by setting it with FDT_NOP
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000654 pub fn nop(self) -> Result<()> {
655 self.fdt.nop_node(self.offset)
Jaewan Kim4ae0e712023-10-19 14:16:17 +0900656 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000657}
658
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000659/// Wrapper around low-level libfdt functions.
Alice Wang9d4df702023-05-25 14:14:12 +0000660#[derive(Debug)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100661#[repr(transparent)]
662pub struct Fdt {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000663 buffer: [u8],
David Brazdil1baa9a92022-06-28 14:47:50 +0100664}
665
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000666// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
667// methods to be called on invalid device trees.
668unsafe impl Libfdt for Fdt {
669 fn as_fdt_slice(&self) -> &[u8] {
670 &self.buffer[..self.totalsize()]
671 }
672}
673
674// SAFETY: Fdt calls check_full() before safely returning a &Self, making it impossible for trait
675// methods to be called on invalid device trees.
676unsafe impl LibfdtMut for Fdt {
677 fn as_fdt_slice_mut(&mut self) -> &mut [u8] {
678 &mut self.buffer
679 }
680}
681
David Brazdil1baa9a92022-06-28 14:47:50 +0100682impl Fdt {
683 /// Wraps a slice containing a Flattened Device Tree.
684 ///
685 /// Fails if the FDT does not pass validation.
686 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000687 libfdt::check_full(fdt)?;
688 // SAFETY: The FDT was validated.
David Brazdil1baa9a92022-06-28 14:47:50 +0100689 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000690
David Brazdil1baa9a92022-06-28 14:47:50 +0100691 Ok(fdt)
692 }
693
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000694 /// Wraps a mutable slice containing a Flattened Device Tree.
695 ///
696 /// Fails if the FDT does not pass validation.
697 pub fn from_mut_slice(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000698 libfdt::check_full(fdt)?;
699 // SAFETY: The FDT was validated.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000700 let fdt = unsafe { Self::unchecked_from_mut_slice(fdt) };
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000701
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000702 Ok(fdt)
703 }
704
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900705 /// Creates an empty Flattened Device Tree with a mutable slice.
706 pub fn create_empty_tree(fdt: &mut [u8]) -> Result<&mut Self> {
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000707 libfdt::create_empty_tree(fdt)?;
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900708
Pierre-Clément Tosifbb5ee22023-12-21 13:49:59 +0000709 Self::from_mut_slice(fdt)
Jaewan Kim4cf20aa2023-04-03 10:25:38 +0900710 }
711
David Brazdil1baa9a92022-06-28 14:47:50 +0100712 /// Wraps a slice containing a Flattened Device Tree.
713 ///
714 /// # Safety
715 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000716 /// 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 +0100717 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000718 let self_ptr = fdt as *const _ as *const _;
719 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
720 unsafe { &*self_ptr }
David Brazdil1baa9a92022-06-28 14:47:50 +0100721 }
722
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000723 /// Wraps a mutable slice containing a Flattened Device Tree.
724 ///
725 /// # Safety
726 ///
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000727 /// 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 +0000728 pub unsafe fn unchecked_from_mut_slice(fdt: &mut [u8]) -> &mut Self {
Pierre-Clément Tosidf3037f2024-01-22 15:41:43 +0000729 let self_mut_ptr = fdt as *mut _ as *mut _;
730 // SAFETY: The pointer is non-null, dereferenceable, and points to allocated memory.
731 unsafe { &mut *self_mut_ptr }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000732 }
733
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000734 /// Updates this FDT from another FDT.
735 pub fn clone_from(&mut self, other: &Self) -> Result<()> {
736 let new_len = other.buffer.len();
737 if self.buffer.len() < new_len {
738 return Err(FdtError::NoSpace);
Jiyong Parke9d87e82023-03-21 19:28:40 +0900739 }
Pierre-Clément Tosice0b36d2024-01-26 10:50:05 +0000740
741 let zeroed_len = self.totalsize().checked_sub(new_len);
742 let (cloned, zeroed) = self.buffer.split_at_mut(new_len);
743
744 cloned.clone_from_slice(&other.buffer);
745 if let Some(len) = zeroed_len {
746 zeroed[..len].fill(0);
747 }
748
749 Ok(())
Jiyong Parke9d87e82023-03-21 19:28:40 +0900750 }
751
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900752 /// Unpacks the DT to cover the whole slice it is contained in.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000753 pub fn unpack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000754 // SAFETY: "Opens" the DT in-place (supported use-case) by updating its header and
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000755 // internal structures to make use of the whole self.fdt slice but performs no accesses
756 // outside of it and leaves the DT in a state that will be detected by other functions.
757 let ret = unsafe {
758 libfdt_bindgen::fdt_open_into(
759 self.as_ptr(),
760 self.as_mut_ptr(),
761 self.capacity().try_into().map_err(|_| FdtError::Internal)?,
762 )
763 };
764 fdt_err_expect_zero(ret)
765 }
766
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900767 /// Packs the DT to take a minimum amount of memory.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000768 ///
769 /// Doesn't shrink the underlying memory slice.
770 pub fn pack(&mut self) -> Result<()> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000771 // SAFETY: "Closes" the DT in-place by updating its header and relocating its structs.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000772 let ret = unsafe { libfdt_bindgen::fdt_pack(self.as_mut_ptr()) };
773 fdt_err_expect_zero(ret)
774 }
775
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000776 /// Applies a DT overlay on the base DT.
777 ///
778 /// # Safety
779 ///
780 /// On failure, the library corrupts the DT and overlay so both must be discarded.
781 pub unsafe fn apply_overlay<'a>(&'a mut self, overlay: &'a mut Fdt) -> Result<&'a mut Self> {
Andrew Walbran84b9a232023-07-05 14:01:40 +0000782 let ret =
783 // SAFETY: Both pointers are valid because they come from references, and fdt_overlay_apply
784 // doesn't keep them after it returns. It may corrupt their contents if there is an error,
785 // but that's our caller's responsibility.
786 unsafe { libfdt_bindgen::fdt_overlay_apply(self.as_mut_ptr(), overlay.as_mut_ptr()) };
787 fdt_err_expect_zero(ret)?;
Pierre-Clément Tosi90e19352022-11-21 17:11:48 +0000788 Ok(self)
789 }
790
Alice Wang2422bdc2023-06-12 08:37:55 +0000791 /// Returns an iterator of memory banks specified the "/memory" node.
792 /// Throws an error when the "/memory" is not found in the device tree.
David Brazdil1baa9a92022-06-28 14:47:50 +0100793 ///
794 /// NOTE: This does not support individual "/memory@XXXX" banks.
Alice Wang2422bdc2023-06-12 08:37:55 +0000795 pub fn memory(&self) -> Result<MemRegIterator> {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000796 let node = self.node(cstr!("/memory"))?.ok_or(FdtError::NotFound)?;
797 if node.device_type()? != Some(cstr!("memory")) {
Alice Wang2422bdc2023-06-12 08:37:55 +0000798 return Err(FdtError::BadValue);
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000799 }
Alice Wang2422bdc2023-06-12 08:37:55 +0000800 node.reg()?.ok_or(FdtError::BadValue).map(MemRegIterator::new)
801 }
802
803 /// Returns the first memory range in the `/memory` node.
804 pub fn first_memory_range(&self) -> Result<Range<usize>> {
805 self.memory()?.next().ok_or(FdtError::NotFound)
David Brazdil1baa9a92022-06-28 14:47:50 +0100806 }
807
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900808 /// Returns the standard /chosen node.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000809 pub fn chosen(&self) -> Result<Option<FdtNode>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900810 self.node(cstr!("/chosen"))
David Brazdil1baa9a92022-06-28 14:47:50 +0100811 }
812
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900813 /// Returns the standard /chosen node as mutable.
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000814 pub fn chosen_mut(&mut self) -> Result<Option<FdtNodeMut>> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900815 self.node_mut(cstr!("/chosen"))
Pierre-Clément Tosi4ba79662023-02-13 11:22:41 +0000816 }
817
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900818 /// Returns the root node of the tree.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000819 pub fn root(&self) -> Result<FdtNode> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900820 self.node(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000821 }
822
Jaewan Kimf163d762023-11-01 13:12:50 +0900823 /// Returns the standard /__symbols__ node.
824 pub fn symbols(&self) -> Result<Option<FdtNode>> {
825 self.node(cstr!("/__symbols__"))
826 }
827
828 /// Returns the standard /__symbols__ node as mutable
829 pub fn symbols_mut(&mut self) -> Result<Option<FdtNodeMut>> {
830 self.node_mut(cstr!("/__symbols__"))
831 }
832
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900833 /// Returns a tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000834 pub fn node(&self, path: &CStr) -> Result<Option<FdtNode>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000835 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000836
837 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
David Brazdil1baa9a92022-06-28 14:47:50 +0100838 }
839
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000840 /// Iterate over nodes with a given compatible string.
841 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
842 CompatibleIterator::new(self, compatible)
843 }
844
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900845 /// Returns max phandle in the tree.
846 pub fn max_phandle(&self) -> Result<Phandle> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000847 self.find_max_phandle()
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900848 }
849
850 /// Returns a node with the phandle
851 pub fn node_with_phandle(&self, phandle: Phandle) -> Result<Option<FdtNode>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000852 let offset = self.node_offset_by_phandle(phandle)?;
853
Jaewan Kimc63246d2023-11-09 15:41:01 +0900854 Ok(offset.map(|offset| FdtNode { fdt: self, offset }))
855 }
856
857 /// Returns a mutable node with the phandle
858 pub fn node_mut_with_phandle(&mut self, phandle: Phandle) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000859 let offset = self.node_offset_by_phandle(phandle)?;
Jaewan Kimc63246d2023-11-09 15:41:01 +0900860
Pierre-Clément Tosiecd5bbc2023-12-21 15:12:45 +0000861 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Jaewan Kim17ba7a32023-10-19 13:25:15 +0900862 }
863
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900864 /// Returns the mutable root node of the tree.
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000865 pub fn root_mut(&mut self) -> Result<FdtNodeMut> {
Jaewan Kimb635bb02023-11-01 13:00:34 +0900866 self.node_mut(cstr!("/"))?.ok_or(FdtError::Internal)
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000867 }
868
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900869 /// Returns a mutable tree node by its full path.
Pierre-Clément Tosib244d932022-11-24 16:45:53 +0000870 pub fn node_mut(&mut self, path: &CStr) -> Result<Option<FdtNodeMut>> {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000871 let offset = self.path_offset_namelen(path.to_bytes())?;
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000872
873 Ok(offset.map(|offset| FdtNodeMut { fdt: self, offset }))
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000874 }
875
Pierre-Clément Tosi81c5bc72024-01-29 13:39:07 +0000876 fn next_node_skip_subnodes(&self, node: c_int, depth: usize) -> Result<Option<(c_int, usize)>> {
877 let mut iter = self.next_node(node, depth)?;
878 while let Some((offset, next_depth)) = iter {
879 if next_depth <= depth {
880 return Ok(Some((offset, next_depth)));
881 }
882 iter = self.next_node(offset, next_depth)?;
883 }
884
885 Ok(None)
886 }
887
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900888 /// Returns the device tree as a slice (may be smaller than the containing buffer).
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000889 pub fn as_slice(&self) -> &[u8] {
Pierre-Clément Tosid83741d2024-02-02 10:44:55 +0000890 self.as_fdt_slice()
David Brazdil1baa9a92022-06-28 14:47:50 +0100891 }
892
Jaewan Kimaa638702023-09-19 13:34:01 +0900893 fn get_from_ptr(&self, ptr: *const c_void, len: usize) -> Result<&[u8]> {
Pierre-Clément Tosi60282ae2023-12-21 16:00:02 +0000894 get_slice_at_ptr(self.as_fdt_slice(), ptr.cast(), len).ok_or(FdtError::Internal)
Jaewan Kim72d10902023-10-12 21:59:26 +0900895 }
896
Jaewan Kimb3dcfc22023-09-20 10:20:52 +0900897 /// Returns a shared pointer to the device tree.
Pierre-Clément Tosi8036b4f2023-02-17 10:31:31 +0000898 pub fn as_ptr(&self) -> *const c_void {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000899 self.buffer.as_ptr().cast()
David Brazdil1baa9a92022-06-28 14:47:50 +0100900 }
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000901
902 fn as_mut_ptr(&mut self) -> *mut c_void {
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000903 self.buffer.as_mut_ptr().cast::<_>()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000904 }
905
906 fn capacity(&self) -> usize {
Pierre-Clément Tosief2030e2022-11-28 11:21:20 +0000907 self.buffer.len()
Pierre-Clément Tosi1b0d8902022-11-21 18:16:59 +0000908 }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000909
910 fn header(&self) -> &libfdt_bindgen::fdt_header {
Pierre-Clément Tosicb92b512024-01-22 15:55:25 +0000911 let p = self.as_ptr().cast();
Andrew Walbran84b9a232023-07-05 14:01:40 +0000912 // SAFETY: A valid FDT (verified by constructor) must contain a valid fdt_header.
Pierre-Clément Tosi0dcc75e2023-05-02 13:43:55 +0000913 unsafe { &*p }
Pierre-Clément Tosidb74cb12022-12-08 13:56:25 +0000914 }
915
916 fn totalsize(&self) -> usize {
917 u32::from_be(self.header().totalsize) as usize
918 }
David Brazdil1baa9a92022-06-28 14:47:50 +0100919}