1#![no_std]
2#![deny(warnings)] mod header;
5mod indent;
6mod path;
7mod property;
8mod structure_block;
9mod walker;
10
11pub use path::Path;
12pub use property::{PHandle, Property, Reg, Str, StrList};
13pub mod utils {
14 pub use crate::indent::indent;
15}
16pub use header::HeaderError;
17
18use core::{fmt, mem, slice};
19use header::FdtHeader;
20use property::RegCfg;
21use structure_block::StructureBlock;
22use walker::Walker;
23
24pub struct Dtb<'a>(&'a [u8]);
26
27impl Dtb<'static> {
28 #[inline]
34 pub unsafe fn from_raw_parts(ptr: *const u8) -> Result<Self, HeaderError> {
35 (*ptr.cast::<FdtHeader>()).verify(|_| true)?;
36 Ok(Self::from_raw_parts_unchecked(ptr))
37 }
38
39 #[inline]
45 pub unsafe fn from_raw_parts_filtered(
46 ptr: *const u8,
47 f: impl Fn(&HeaderError) -> bool,
48 ) -> Result<Self, HeaderError> {
49 (*ptr.cast::<FdtHeader>()).verify(f)?;
50 Ok(Self::from_raw_parts_unchecked(ptr))
51 }
52
53 #[inline]
59 pub unsafe fn from_raw_parts_unchecked(ptr: *const u8) -> Self {
60 Self(slice::from_raw_parts(
61 ptr,
62 (*ptr.cast::<FdtHeader>()).totalsize.into_u32() as _,
63 ))
64 }
65}
66
67pub enum ConvertError {
68 Truncated,
69 Header(HeaderError),
70}
71
72impl<'a> Dtb<'a> {
73 pub fn from_slice(slice: &'a [u8]) -> Result<Self, ConvertError> {
75 if slice.len() < mem::size_of::<FdtHeader>() {
76 return Err(ConvertError::Truncated);
77 }
78 let header = unsafe { &*slice.as_ptr().cast::<FdtHeader>() };
79 match header.verify(|_| true) {
80 Ok(()) => {
81 let len = header.totalsize.into_u32() as usize;
82 if len <= slice.len() {
83 Ok(Self(&slice[..len]))
84 } else {
85 Err(ConvertError::Truncated)
86 }
87 }
88 Err(e) => Err(ConvertError::Header(e)),
89 }
90 }
91}
92
93impl Dtb<'_> {
94 #[inline]
96 pub const fn total_size(&self) -> usize {
97 self.0.len()
98 }
99
100 pub fn walk(&self, mut f: impl FnMut(&Path<'_>, DtbObj) -> WalkOperation) {
102 let header = self.header();
103 let off_struct = header.off_dt_struct.into_u32() as usize;
104 let len_struct = header.size_dt_struct.into_u32() as usize;
105 let off_strings = header.off_dt_strings.into_u32() as usize;
106 let len_strings = header.size_dt_strings.into_u32() as usize;
107 Walker {
108 tail: unsafe {
109 slice::from_raw_parts(
110 self.0[off_struct..]
111 .as_ptr()
112 .cast::<StructureBlock>()
113 .offset(2),
114 len_struct / StructureBlock::LEN - 3,
115 )
116 },
117 strings: &self.0[off_strings..][..len_strings],
118 }
119 .walk_inner(&mut f, &Path::ROOT, RegCfg::DEFAULT, false);
120 }
121
122 #[inline]
123 fn header(&self) -> &FdtHeader {
124 unsafe { &*self.0.as_ptr().cast() }
125 }
126}
127
128pub enum DtbObj<'a> {
130 SubNode { name: &'a [u8] },
132 Property(Property<'a>),
134}
135
136pub enum WalkOperation {
138 StepInto,
140 StepOver,
142 StepOut,
144 Terminate,
146}
147
148#[repr(transparent)]
149#[derive(Clone, Copy, PartialEq, Eq)]
150struct U32BigEndian(u32);
151
152impl U32BigEndian {
153 #[inline]
154 pub const fn from_u32(val: u32) -> Self {
155 Self(u32::to_be(val))
156 }
157
158 #[inline]
159 pub const fn into_u32(self) -> u32 {
160 u32::from_be(self.0)
161 }
162}
163
164impl fmt::Debug for U32BigEndian {
165 #[inline]
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 u32::from_be(self.0).fmt(f)
168 }
169}
170
171#[inline]
172fn is_aligned(val: usize, bits: usize) -> bool {
173 val & (bits - 1) == 0
174}