blob: d15f3c4c8adc189f18fcd0337490f852e506afa6 [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.
272pub struct FdtNode<'a> {
273 fdt: &'a Fdt,
274 offset: c_int,
275}
276
277impl<'a> FdtNode<'a> {
278 /// Find parent node.
279 pub fn parent(&self) -> Result<Self> {
280 // SAFETY - Accesses (read-only) are constrained to the DT totalsize.
281 let ret = unsafe { libfdt_bindgen::fdt_parent_offset(self.fdt.as_ptr(), self.offset) };
282
283 Ok(Self { fdt: self.fdt, offset: fdt_err(ret)? })
284 }
285
286 /// Retrieve the standard (deprecated) device_type <string> property.
287 pub fn device_type(&self) -> Result<&CStr> {
288 self.getprop_str(CStr::from_bytes_with_nul(b"device_type\0").unwrap())
289 }
290
291 /// Retrieve the standard reg <prop-encoded-array> property.
292 pub fn reg(&self) -> Result<RegIterator<'a>> {
293 let parent = self.parent()?;
294
295 let addr_cells = parent.address_cells()?;
296 let size_cells = parent.size_cells()?;
297 let cells = self.getprop_cells(CStr::from_bytes_with_nul(b"reg\0").unwrap())?;
298
299 Ok(RegIterator::new(cells, addr_cells, size_cells))
300 }
301
302 /// Retrieve the value of a given <string> property.
303 pub fn getprop_str(&self, name: &CStr) -> Result<&CStr> {
304 CStr::from_bytes_with_nul(self.getprop(name)?).map_err(|_| FdtError::BadValue)
305 }
306
307 /// Retrieve the value of a given property as an array of cells.
308 pub fn getprop_cells(&self, name: &CStr) -> Result<CellIterator<'a>> {
309 Ok(CellIterator::new(self.getprop(name)?))
310 }
311
312 /// Retrieve the value of a given <u32> property.
313 pub fn getprop_u32(&self, name: &CStr) -> Result<u32> {
314 let prop = self.getprop(name)?.try_into().map_err(|_| FdtError::BadValue)?;
315 Ok(u32::from_be_bytes(prop))
316 }
317
318 /// Retrieve the value of a given <u64> property.
319 pub fn getprop_u64(&self, name: &CStr) -> Result<u64> {
320 let prop = self.getprop(name)?.try_into().map_err(|_| FdtError::BadValue)?;
321 Ok(u64::from_be_bytes(prop))
322 }
323
324 /// Retrieve the value of a given property.
325 pub fn getprop(&self, name: &CStr) -> Result<&'a [u8]> {
326 let mut len: i32 = 0;
327 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
328 // function respects the passed number of characters.
329 let prop = unsafe {
330 libfdt_bindgen::fdt_getprop_namelen(
331 self.fdt.as_ptr(),
332 self.offset,
333 name.as_ptr(),
334 // *_namelen functions don't include the trailing nul terminator in 'len'.
335 name.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?,
336 &mut len as *mut i32,
337 )
338 } as *const u8;
339 if prop.is_null() {
340 return fdt_err(len).and(Err(FdtError::Internal));
341 }
342 let len = usize::try_from(fdt_err(len)?).map_err(|_| FdtError::Internal)?;
343 let base =
344 (prop as usize).checked_sub(self.fdt.as_ptr() as usize).ok_or(FdtError::Internal)?;
345
346 self.fdt.bytes.get(base..(base + len)).ok_or(FdtError::Internal)
347 }
348
349 /// Get reference to the containing device tree.
350 pub fn fdt(&self) -> &Fdt {
351 self.fdt
352 }
353
354 fn address_cells(&self) -> Result<AddrCells> {
355 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
356 unsafe { libfdt_bindgen::fdt_address_cells(self.fdt.as_ptr(), self.offset) }
357 .try_into()
358 .map_err(|_| FdtError::Internal)
359 }
360
361 fn size_cells(&self) -> Result<SizeCells> {
362 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor).
363 unsafe { libfdt_bindgen::fdt_size_cells(self.fdt.as_ptr(), self.offset) }
364 .try_into()
365 .map_err(|_| FdtError::Internal)
366 }
367}
368
369/// Wrapper around low-level read-only libfdt functions.
370#[repr(transparent)]
371pub struct Fdt {
372 bytes: [u8],
373}
374
375impl Fdt {
376 /// Wraps a slice containing a Flattened Device Tree.
377 ///
378 /// Fails if the FDT does not pass validation.
379 pub fn from_slice(fdt: &[u8]) -> Result<&Self> {
380 // SAFETY - The FDT will be validated before it is returned.
381 let fdt = unsafe { Self::unchecked_from_slice(fdt) };
382 fdt.check_full()?;
383 Ok(fdt)
384 }
385
386 /// Wraps a slice containing a Flattened Device Tree.
387 ///
388 /// # Safety
389 ///
390 /// The returned FDT might be invalid, only use on slices containing a valid DT.
391 pub unsafe fn unchecked_from_slice(fdt: &[u8]) -> &Self {
392 mem::transmute::<&[u8], &Self>(fdt)
393 }
394
395 /// Return an iterator of memory banks specified the "/memory" node.
396 ///
397 /// NOTE: This does not support individual "/memory@XXXX" banks.
398 pub fn memory(&self) -> Result<MemRegIterator> {
399 let memory = CStr::from_bytes_with_nul(b"/memory\0").unwrap();
400 let device_type = CStr::from_bytes_with_nul(b"memory\0").unwrap();
401
402 let node = self.node(memory)?;
403 if node.device_type()? != device_type {
404 return Err(FdtError::BadValue);
405 }
406
407 MemRegIterator::new(node.reg()?)
408 }
409
410 /// Retrieve the standard /chosen node.
411 pub fn chosen(&self) -> Result<FdtNode> {
412 self.node(CStr::from_bytes_with_nul(b"/chosen\0").unwrap())
413 }
414
415 /// Find a tree node by its full path.
416 pub fn node(&self, path: &CStr) -> Result<FdtNode> {
417 let offset = self.path_offset(path)?;
418 Ok(FdtNode { fdt: self, offset })
419 }
420
421 fn path_offset(&self, path: &CStr) -> Result<c_int> {
422 let len = path.to_bytes().len().try_into().map_err(|_| FdtError::BadPath)?;
423 // SAFETY - Accesses are constrained to the DT totalsize (validated by ctor) and the
424 // function respects the passed number of characters.
425 let ret = unsafe {
426 // *_namelen functions don't include the trailing nul terminator in 'len'.
427 libfdt_bindgen::fdt_path_offset_namelen(self.as_ptr(), path.as_ptr(), len)
428 };
429
430 fdt_err(ret)
431 }
432
433 fn check_full(&self) -> Result<()> {
434 let len = self.bytes.len();
435 // SAFETY - Only performs read accesses within the limits of the slice. If successful, this
436 // call guarantees to other unsafe calls that the header contains a valid totalsize (w.r.t.
437 // 'len' i.e. the self.fdt slice) that those C functions can use to perform bounds
438 // checking. The library doesn't maintain an internal state (such as pointers) between
439 // calls as it expects the client code to keep track of the objects (DT, nodes, ...).
440 let ret = unsafe { libfdt_bindgen::fdt_check_full(self.as_ptr(), len) };
441 fdt_err_expect_zero(ret)
442 }
443
444 fn as_ptr(&self) -> *const c_void {
445 self as *const _ as *const c_void
446 }
447}