1use core::fmt;
2
3use crate::{
4 Chosen, FdtError, Memory, MemoryReservation, Node, data::Bytes, header::Header, iter::FdtIter,
5};
6
7pub struct MemoryReservationIter<'a> {
9 data: &'a [u8],
10 offset: usize,
11}
12
13impl<'a> Iterator for MemoryReservationIter<'a> {
14 type Item = MemoryReservation;
15
16 fn next(&mut self) -> Option<Self::Item> {
17 if self.offset + 16 > self.data.len() {
19 return None;
20 }
21
22 let address_bytes = &self.data[self.offset..self.offset + 8];
24 let address = u64::from_be_bytes(address_bytes.try_into().unwrap());
25 self.offset += 8;
26
27 let size_bytes = &self.data[self.offset..self.offset + 8];
29 let size = u64::from_be_bytes(size_bytes.try_into().unwrap());
30 self.offset += 8;
31
32 if address == 0 && size == 0 {
34 return None;
35 }
36
37 Some(MemoryReservation { address, size })
38 }
39}
40
41fn write_indent(f: &mut fmt::Formatter<'_>, count: usize, ch: &str) -> fmt::Result {
43 for _ in 0..count {
44 write!(f, "{}", ch)?;
45 }
46 Ok(())
47}
48
49#[derive(Clone)]
50pub struct Fdt<'a> {
51 header: Header,
52 pub(crate) data: Bytes<'a>,
53}
54
55impl<'a> Fdt<'a> {
56 pub fn from_bytes(data: &'a [u8]) -> Result<Fdt<'a>, FdtError> {
58 let header = Header::from_bytes(data)?;
59 if data.len() < header.totalsize as usize {
60 return Err(FdtError::BufferTooSmall {
61 pos: header.totalsize as usize,
62 });
63 }
64 let buffer = Bytes::new(data);
65
66 Ok(Fdt {
67 header,
68 data: buffer,
69 })
70 }
71
72 pub unsafe fn from_ptr(ptr: *mut u8) -> Result<Fdt<'a>, FdtError> {
80 let header = unsafe { Header::from_ptr(ptr)? };
81
82 let data_slice = unsafe { core::slice::from_raw_parts(ptr, header.totalsize as _) };
83 let data = Bytes::new(data_slice);
84
85 Ok(Fdt { header, data })
86 }
87
88 pub fn header(&self) -> &Header {
89 &self.header
90 }
91
92 pub fn as_slice(&self) -> &'a [u8] {
93 self.data.as_slice()
94 }
95
96 pub fn all_nodes(&self) -> FdtIter<'a> {
97 FdtIter::new(self.clone())
98 }
99
100 pub fn memory_reservations(&self) -> MemoryReservationIter<'a> {
102 MemoryReservationIter {
103 data: self.data.as_slice(),
104 offset: self.header.off_mem_rsvmap as usize,
105 }
106 }
107
108 pub fn chosen(&self) -> Option<Chosen<'a>> {
109 for node in self.all_nodes() {
110 if let Node::Chosen(c) = node {
111 return Some(c);
112 }
113 }
114 None
115 }
116
117 pub fn memory(&self) -> Option<Memory<'a>> {
118 for node in self.all_nodes() {
119 if let Node::Memory(m) = node {
120 return Some(m);
121 }
122 }
123 None
124 }
125}
126
127impl fmt::Display for Fdt<'_> {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 writeln!(f, "/dts-v1/;")?;
130 writeln!(f)?;
131
132 let mut prev_level = 0;
133
134 for node in self.all_nodes() {
135 let level = node.level();
136
137 while prev_level > level {
139 prev_level -= 1;
140 write_indent(f, prev_level, " ")?;
141 writeln!(f, "}};\n")?;
142 }
143
144 write_indent(f, level, " ")?;
145 let name = if node.name().is_empty() {
146 "/"
147 } else {
148 node.name()
149 };
150
151 writeln!(f, "{} {{", name)?;
153
154 for prop in node.properties() {
156 write_indent(f, level + 1, " ")?;
157 writeln!(f, "{};", prop)?;
158 }
159
160 prev_level = level + 1;
161 }
162
163 while prev_level > 0 {
165 prev_level -= 1;
166 write_indent(f, prev_level, " ")?;
167 writeln!(f, "}};\n")?;
168 }
169
170 Ok(())
171 }
172}
173
174impl fmt::Debug for Fdt<'_> {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 writeln!(f, "Fdt {{")?;
177 writeln!(f, "\theader: {:?}", self.header)?;
178 writeln!(f, "\tnodes:")?;
179
180 for node in self.all_nodes() {
181 let level = node.level();
182 write_indent(f, level + 2, "\t")?;
184
185 let name = if node.name().is_empty() {
186 "/"
187 } else {
188 node.name()
189 };
190
191 writeln!(
193 f,
194 "[{}] address_cells={}, size_cells={}",
195 name, node.address_cells, node.size_cells
196 )?;
197
198 for prop in node.properties() {
200 write_indent(f, level + 3, "\t")?;
201 if let Some(v) = prop.as_address_cells() {
202 writeln!(f, "#address-cells: {}", v)?;
203 } else if let Some(v) = prop.as_size_cells() {
204 writeln!(f, "#size-cells: {}", v)?;
205 } else if let Some(v) = prop.as_interrupt_cells() {
206 writeln!(f, "#interrupt-cells: {}", v)?;
207 } else if let Some(s) = prop.as_status() {
208 writeln!(f, "status: {:?}", s)?;
209 } else if let Some(p) = prop.as_phandle() {
210 writeln!(f, "phandle: {}", p)?;
211 } else {
212 if prop.is_empty() {
214 writeln!(f, "{}", prop.name())?;
215 } else if let Some(s) = prop.as_str() {
216 writeln!(f, "{}: \"{}\"", prop.name(), s)?;
217 } else if prop.len() == 4 {
218 let v = u32::from_be_bytes(prop.data().as_slice().try_into().unwrap());
219 writeln!(f, "{}: {:#x}", prop.name(), v)?;
220 } else {
221 writeln!(f, "{}: <{} bytes>", prop.name(), prop.len())?;
222 }
223 }
224 }
225 }
226
227 writeln!(f, "}}")
228 }
229}
230
231#[cfg(test)]
232mod tests {
233 use super::*;
234 use heapless::Vec;
235
236 #[test]
237 fn test_memory_reservation_iterator() {
238 let mut test_data = [0u8; 32];
240
241 test_data[0..8].copy_from_slice(&0x80000000u64.to_be_bytes());
243 test_data[8..16].copy_from_slice(&0x10000000u64.to_be_bytes());
244 test_data[16..24].copy_from_slice(&0u64.to_be_bytes());
246 test_data[24..32].copy_from_slice(&0u64.to_be_bytes());
247
248 let iter = MemoryReservationIter {
249 data: &test_data,
250 offset: 0,
251 };
252
253 let reservations: Vec<MemoryReservation, 4> = iter.collect();
254 assert_eq!(reservations.len(), 1);
255 assert_eq!(reservations[0].address, 0x80000000);
256 assert_eq!(reservations[0].size, 0x10000000);
257 }
258
259 #[test]
260 fn test_empty_memory_reservation_iterator() {
261 let mut test_data = [0u8; 16];
263 test_data[0..8].copy_from_slice(&0u64.to_be_bytes());
264 test_data[8..16].copy_from_slice(&0u64.to_be_bytes());
265
266 let iter = MemoryReservationIter {
267 data: &test_data,
268 offset: 0,
269 };
270
271 let reservations: Vec<MemoryReservation, 4> = iter.collect();
272 assert_eq!(reservations.len(), 0);
273 }
274}