blob: 01f7b360e538083d7b66571dcb84529f38a4b981 [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
20use core::ffi::{c_int, c_void, CStr};
21use core::fmt;
22use core::mem;
23use core::ops::Range;
24use core::result;
25use core::slice;
26
27/// Error type corresponding to libfdt error codes.
28#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29pub enum FdtError {
30 /// FDT_ERR_NOTFOUND
31 NotFound,
32 /// FDT_ERR_EXISTS
33 Exists,
34 /// FDT_ERR_NOSPACE
35 NoSpace,
36 /// FDT_ERR_BADOFFSET
37 BadOffset,
38 /// FDT_ERR_BADPATH
39 BadPath,
40 /// FDT_ERR_BADPHANDLE
41 BadPhandle,
42 /// FDT_ERR_BADSTATE
43 BadState,
44 /// FDT_ERR_TRUNCATED
45 Truncated,
46 /// FDT_ERR_BADMAGIC
47 BadMagic,
48 /// FDT_ERR_BADVERSION
49 BadVersion,
50 /// FDT_ERR_BADSTRUCTURE
51 BadStructure,
52 /// FDT_ERR_BADLAYOUT
53 BadLayout,
54 /// FDT_ERR_INTERNAL
55 Internal,
56 /// FDT_ERR_BADNCELLS
57 BadNCells,
58 /// FDT_ERR_BADVALUE
59 BadValue,
60 /// FDT_ERR_BADOVERLAY
61 BadOverlay,
62 /// FDT_ERR_NOPHANDLES
63 NoPhandles,
64 /// FDT_ERR_BADFLAGS
65 BadFlags,
66 /// FDT_ERR_ALIGNMENT
67 Alignment,
68 /// Unexpected error code
69 Unknown(i32),
70}
71
72impl fmt::Display for FdtError {
73 /// Prints error messages from libfdt.h documentation.
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 match self {
76 Self::NotFound => write!(f, "The requested node or property does not exist"),
77 Self::Exists => write!(f, "Attempted to create an existing node or property"),
78 Self::NoSpace => write!(f, "Insufficient buffer space to contain the expanded tree"),
79 Self::BadOffset => write!(f, "Structure block offset is out-of-bounds or invalid"),
80 Self::BadPath => write!(f, "Badly formatted path"),
81 Self::BadPhandle => write!(f, "Invalid phandle length or value"),
82 Self::BadState => write!(f, "Received incomplete device tree"),
83 Self::Truncated => write!(f, "Device tree or sub-block is improperly terminated"),
84 Self::BadMagic => write!(f, "Device tree header missing its magic number"),
85 Self::BadVersion => write!(f, "Device tree has a version which can't be handled"),
86 Self::BadStructure => write!(f, "Device tree has a corrupt structure block"),
87 Self::BadLayout => write!(f, "Device tree sub-blocks in unsupported order"),
88 Self::Internal => write!(f, "libfdt has failed an internal assertion"),
89 Self::BadNCells => write!(f, "Bad format or value of #address-cells or #size-cells"),
90 Self::BadValue => write!(f, "Unexpected property value"),
91 Self::BadOverlay => write!(f, "Overlay cannot be applied"),
92 Self::NoPhandles => write!(f, "Device tree doesn't have any phandle available anymore"),
93 Self::BadFlags => write!(f, "Invalid flag or invalid combination of flags"),
94 Self::Alignment => write!(f, "Device tree base address is not 8-byte aligned"),
95 Self::Unknown(e) => write!(f, "Unknown libfdt error '{e}'"),
96 }
97 }
98}
99
100/// Result type with FdtError enum.
101pub type Result<T> = result::Result<T, FdtError>;
102
103fn fdt_err(val: c_int) -> Result<c_int> {
104 if val >= 0 {
105 Ok(val)
106 } else {
107 Err(match -val as _ {
108 libfdt_bindgen::FDT_ERR_NOTFOUND => FdtError::NotFound,
109 libfdt_bindgen::FDT_ERR_EXISTS => FdtError::Exists,
110 libfdt_bindgen::FDT_ERR_NOSPACE => FdtError::NoSpace,
111 libfdt_bindgen::FDT_ERR_BADOFFSET => FdtError::BadOffset,
112 libfdt_bindgen::FDT_ERR_BADPATH => FdtError::BadPath,
113 libfdt_bindgen::FDT_ERR_BADPHANDLE => FdtError::BadPhandle,
114 libfdt_bindgen::FDT_ERR_BADSTATE => FdtError::BadState,
115 libfdt_bindgen::FDT_ERR_TRUNCATED => FdtError::Truncated,
116 libfdt_bindgen::FDT_ERR_BADMAGIC => FdtError::BadMagic,
117 libfdt_bindgen::FDT_ERR_BADVERSION => FdtError::BadVersion,
118 libfdt_bindgen::FDT_ERR_BADSTRUCTURE => FdtError::BadStructure,
119 libfdt_bindgen::FDT_ERR_BADLAYOUT => FdtError::BadLayout,
120 libfdt_bindgen::FDT_ERR_INTERNAL => FdtError::Internal,
121 libfdt_bindgen::FDT_ERR_BADNCELLS => FdtError::BadNCells,
122 libfdt_bindgen::FDT_ERR_BADVALUE => FdtError::BadValue,
123 libfdt_bindgen::FDT_ERR_BADOVERLAY => FdtError::BadOverlay,
124 libfdt_bindgen::FDT_ERR_NOPHANDLES => FdtError::NoPhandles,
125 libfdt_bindgen::FDT_ERR_BADFLAGS => FdtError::BadFlags,
126 libfdt_bindgen::FDT_ERR_ALIGNMENT => FdtError::Alignment,
127 _ => FdtError::Unknown(val),
128 })
129 }
130}
131
132fn fdt_err_expect_zero(val: c_int) -> Result<()> {
133 match fdt_err(val)? {
134 0 => Ok(()),
135 _ => Err(FdtError::Unknown(val)),
136 }
137}
138
139/// Value of a #address-cells property.
140#[derive(Copy, Clone, Debug)]
141enum AddrCells {
142 Single = 1,
143 Double = 2,
144}
145
146impl TryFrom<c_int> for AddrCells {
147 type Error = FdtError;
148
149 fn try_from(res: c_int) -> Result<Self> {
150 match fdt_err(res)? {
151 x if x == Self::Single as c_int => Ok(Self::Single),
152 x if x == Self::Double as c_int => Ok(Self::Double),
153 _ => Err(FdtError::BadNCells),
154 }
155 }
156}
157
158/// Value of a #size-cells property.
159#[derive(Copy, Clone, Debug)]
160enum SizeCells {
161 None = 0,
162 Single = 1,
163 Double = 2,
164}
165
166impl TryFrom<c_int> for SizeCells {
167 type Error = FdtError;
168
169 fn try_from(res: c_int) -> Result<Self> {
170 match fdt_err(res)? {
171 x if x == Self::None as c_int => Ok(Self::None),
172 x if x == Self::Single as c_int => Ok(Self::Single),
173 x if x == Self::Double as c_int => Ok(Self::Double),
174 _ => Err(FdtError::BadNCells),
175 }
176 }
177}
178
179/// Iterator over cells of a DT property.
180#[derive(Debug)]
181pub struct CellIterator<'a> {
182 chunks: slice::ChunksExact<'a, u8>,
183}
184
185impl<'a> CellIterator<'a> {
186 fn new(bytes: &'a [u8]) -> Self {
187 const CHUNK_SIZE: usize = mem::size_of::<<CellIterator as Iterator>::Item>();
188
189 Self { chunks: bytes.chunks_exact(CHUNK_SIZE) }
190 }
191}
192
193impl<'a> Iterator for CellIterator<'a> {
194 type Item = u32;
195
196 fn next(&mut self) -> Option<Self::Item> {
197 Some(Self::Item::from_be_bytes(self.chunks.next()?.try_into().ok()?))
198 }
199}
200
201/// Iterator over a 'reg' property of a DT node.
202#[derive(Debug)]
203pub struct RegIterator<'a> {
204 cells: CellIterator<'a>,
205 addr_cells: AddrCells,
206 size_cells: SizeCells,
207}
208
209/// Represents a contiguous region within the address space defined by the parent bus.
210/// Commonly means the offsets and lengths of MMIO blocks, but may have a different meaning on some
211/// bus types. Addresses in the address space defined by the root node are CPU real addresses.
212#[derive(Copy, Clone, Debug)]
213pub struct Reg<T> {
214 /// Base address of the region.
215 pub addr: T,
216 /// Size of the region (optional).
217 pub size: Option<T>,
218}
219
220impl<'a> RegIterator<'a> {
221 fn new(cells: CellIterator<'a>, addr_cells: AddrCells, size_cells: SizeCells) -> Self {
222 Self { cells, addr_cells, size_cells }
223 }
224}
225
226impl<'a> Iterator for RegIterator<'a> {
227 type Item = Reg<u64>;
228
229 fn next(&mut self) -> Option<Self::Item> {
230 let make_double = |a, b| (u64::from(a) << 32) | u64::from(b);
231
232 let addr = match self.addr_cells {
233 AddrCells::Single => self.cells.next()?.into(),
234 AddrCells::Double => make_double(self.cells.next()?, self.cells.next()?),
235 };
236 // If the parent node specifies a value of 0 for #size-cells, 'size' shall be omitted.
237 let size = match self.size_cells {
238 SizeCells::None => None,
239 SizeCells::Single => Some(self.cells.next()?.into()),
240 SizeCells::Double => Some(make_double(self.cells.next()?, self.cells.next()?)),
241 };
242
243 Some(Self::Item { addr, size })
244 }
245}
246
247/// Iterator over the address ranges defined by the /memory/ node.
248#[derive(Debug)]
249pub struct MemRegIterator<'a> {
250 reg: RegIterator<'a>,
251}
252
253impl<'a> MemRegIterator<'a> {
254 fn new(reg: RegIterator<'a>) -> Result<Self> {
255 Ok(Self { reg })
256 }
257}
258
259impl<'a> Iterator for MemRegIterator<'a> {
260 type Item = Range<usize>;
261
262 fn next(&mut self) -> Option<Self::Item> {
263 let next = self.reg.next()?;
264 let addr = usize::try_from(next.addr).ok()?;
265 let size = usize::try_from(next.size?).ok()?;
266
267 Some(addr..addr.checked_add(size)?)
268 }
269}
270
271/// DT node.
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000272#[derive(Clone, Copy)]
David Brazdil1baa9a92022-06-28 14:47:50 +0100273pub struct FdtNode<'a> {
274 fdt: &'a Fdt,
275 offset: c_int,
276}
277
278impl<'a> FdtNode<'a> {
279 /// Find parent node.
280 pub fn parent(&self) -> Result<Self> {
281 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
282 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
283
284 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
285 }
286
287 /// Retrieve the standard (deprecated) device_type <string> property.
288 pub fn device_type(&self) -> Result<&CStr> {
289 self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
290 }
291
292 /// Retrieve the standard reg <prop-encoded-array> property.
293 pub fn reg(&self) -> Result<RegIterator<'a>> {
294 let parent = self.parent()?;
295
296 let addr_cells = parent.address_cells()?;
297 let size_cells = parent.size_cells()?;
298 let cells = self.getprop_cells(CStr::from_bytes_with_nul(b"reg\0").unwrap())?;
299
300 Ok(RegIterator::new(cells, addr_cells, size_cells))
301 }
302
303 /// Retrieve the value of a given <string> property.
304 pub fn getprop_str(&self, name: &CStr) -> Result<&CStr> {
305 CStr::from_bytes_with_nul(self.getprop(name)?).map_err(|_| FdtError::BadValue)
306 }
307
308 /// Retrieve the value of a given property as an array of cells.
309 pub fn getprop_cells(&self, name: &CStr) -> Result<CellIterator<'a>> {
310 Ok(CellIterator::new(self.getprop(name)?))
311 }
312
313 /// Retrieve the value of a given <u32> property.
314 pub fn getprop_u32(&self, name: &CStr) -> Result<u32> {
315 let prop = self.getprop(name)?.try_into().map_err(|_| FdtError::BadValue)?;
316 Ok(u32::from_be_bytes(prop))
317 }
318
319 /// Retrieve the value of a given <u64> property.
320 pub fn getprop_u64(&self, name: &CStr) -> Result<u64> {
321 let prop = self.getprop(name)?.try_into().map_err(|_| FdtError::BadValue)?;
322 Ok(u64::from_be_bytes(prop))
323 }
324
325 /// Retrieve the value of a given property.
326 pub fn getprop(&self, name: &CStr) -> Result<&'a [u8]> {
327 let mut len: i32 = 0;
328 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
329 // function respects the passed number of characters.
330 let prop = unsafe {
331 libfdt_bindgen::fdt_getprop_namelen(
332 self.fdt.as_ptr(),
333 self.offset,
334 name.as_ptr(),
335 // *_namelen functions don't include the trailing nul terminator in 'len'.
336 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
337 &mut len as *mut i32,
338 )
339 } as *const u8;
340 if prop.is_null() {
341 return fdt_err(len).and(Err(FdtError::Internal));
342 }
343 let len = usize::try_from(fdt_err(len)?).map_err(|_| FdtError::Internal)?;
344 let base =
345 (prop as usize).checked_sub(self.fdt.as_ptr() as usize).ok_or(FdtError::Internal)?;
346
347 self.fdt.bytes.get(base..(base + len)).ok_or(FdtError::Internal)
348 }
349
350 /// Get reference to the containing device tree.
351 pub fn fdt(&self) -> &Fdt {
352 self.fdt
353 }
354
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000355 fn next_compatible(self, compatible: &CStr) -> Result<Option<Self>> {
356 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
357 let ret = unsafe {
358 libfdt_bindgen::fdt_node_offset_by_compatible(
359 self.fdt.as_ptr(),
360 self.offset,
361 compatible.as_ptr(),
362 )
363 };
364
365 match fdt_err(ret) {
366 Ok(offset) => Ok(Some(Self { fdt: self.fdt, offset })),
367 Err(FdtError::NotFound) => Ok(None),
368 Err(e) => Err(e),
369 }
370 }
371
David Brazdil1baa9a92022-06-28 14:47:50 +0100372 fn address_cells(&self) -> Result<AddrCells> {
373 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
374 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
375 .try_into()
376 .map_err(|_| FdtError::Internal)
377 }
378
379 fn size_cells(&self) -> Result<SizeCells> {
380 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
381 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
382 .try_into()
383 .map_err(|_| FdtError::Internal)
384 }
385}
386
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000387/// Iterator over nodes sharing a same compatible string.
388pub struct CompatibleIterator<'a> {
389 node: FdtNode<'a>,
390 compatible: &'a CStr,
391}
392
393impl<'a> CompatibleIterator<'a> {
394 fn new(fdt: &'a Fdt, compatible: &'a CStr) -> Result<Self> {
395 let node = fdt.root()?;
396 Ok(Self { node, compatible })
397 }
398}
399
400impl<'a> Iterator for CompatibleIterator<'a> {
401 type Item = FdtNode<'a>;
402
403 fn next(&mut self) -> Option<Self::Item> {
404 let next = self.node.next_compatible(self.compatible).ok()?;
405
406 if let Some(node) = next {
407 self.node = node;
408 }
409
410 next
411 }
412}
413
David Brazdil1baa9a92022-06-28 14:47:50 +0100414/// Wrapper around low-level read-only libfdt functions.
415#[repr(transparent)]
416pub struct Fdt {
417 bytes: [u8],
418}
419
420impl Fdt {
421 /// Wraps a slice containing a Flattened Device Tree.
422 ///
423 /// Fails if the FDT does not pass validation.
424 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
425 // SAFETY - The FDT will be validated before it is returned.
426 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
427 fdt.check_full()?;
428 Ok(fdt)
429 }
430
431 /// Wraps a slice containing a Flattened Device Tree.
432 ///
433 /// # Safety
434 ///
435 /// The returned FDT might be invalid, only use on slices containing a valid DT.
436 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
437 mem::transmute::<&[u8], &Self>(fdt)
438 }
439
440 /// Return an iterator of memory banks specified the "/memory" node.
441 ///
442 /// NOTE: This does not support individual "/memory@XXXX" banks.
443 pub fn memory(&self) -> Result<MemRegIterator> {
444 let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
445 let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
446
447 let node = self.node(memory)?;
448 if node.device_type()? != device_type {
449 return Err(FdtError::BadValue);
450 }
451
452 MemRegIterator::new(node.reg()?)
453 }
454
455 /// Retrieve the standard /chosen node.
456 pub fn chosen(&self) -> Result<FdtNode> {
457 self.node(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
458 }
459
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000460 /// Get the root node of the tree.
461 pub fn root(&self) -> Result<FdtNode> {
462 self.node(CStr::from_bytes_with_nul(b"/\0").unwrap())
463 }
464
David Brazdil1baa9a92022-06-28 14:47:50 +0100465 /// Find a tree node by its full path.
466 pub fn node(&self, path: &CStr) -> Result<FdtNode> {
467 let offset = self.path_offset(path)?;
468 Ok(FdtNode { fdt: self, offset })
469 }
470
Pierre-Clément Tosi41c158e2022-11-21 19:16:25 +0000471 /// Iterate over nodes with a given compatible string.
472 pub fn compatible_nodes<'a>(&'a self, compatible: &'a CStr) -> Result<CompatibleIterator<'a>> {
473 CompatibleIterator::new(self, compatible)
474 }
475
David Brazdil1baa9a92022-06-28 14:47:50 +0100476 fn path_offset(&self, path: &CStr) -> Result<c_int> {
477 let len = path.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?;
478 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
479 // function respects the passed number of characters.
480 let ret = unsafe {
481 // *_namelen functions don't include the trailing nul terminator in 'len'.
482 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr(), len)
483 };
484
485 fdt_err(ret)
486 }
487
488 fn check_full(&self) -> Result<()> {
489 let len = self.bytes.len();
490 // SAFETY - Only performs read accesses within the limits of the slice. If successful, this
491 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
492 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
493 // checking. The library doesn't maintain an internal state (such as pointers) between
494 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
495 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), len) };
496 fdt_err_expect_zero(ret)
497 }
498
499 fn as_ptr(&self) -> *const c_void {
500 self as *const _ as *const c_void
501 }
502}