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 find_by_path(&self, path: &str) -> Option<Node<'a>> {
101 let path = self.normalize_path(path)?;
102 let split = path.trim_matches('/').split('/');
103
104 let mut current_iter = self.all_nodes();
105 let mut found_node: Option<Node<'a>> = None;
106
107 for part in split {
108 let mut found = false;
109 for node in current_iter.by_ref() {
110 let node_name = node.name();
111 if node_name == part {
112 found = true;
113 found_node = Some(node);
114 break;
115 }
116 }
117 if !found {
118 return None;
119 }
120 }
121
122 found_node
123 }
124
125 fn resolve_alias(&self, alias: &str) -> Option<&'a str> {
126 let aliases_node = self.find_by_path("/aliases")?;
127 aliases_node.find_property_str(alias)
128 }
129
130 fn normalize_path(&self, path: &'a str) -> Option<&'a str> {
131 if path.starts_with('/') {
132 Some(path)
133 } else {
134 self.resolve_alias(path)
135 }
136 }
137
138 pub fn translate_address(&self, path: &'a str, address: u64) -> u64 {
152 let path = match self.normalize_path(path) {
153 Some(p) => p,
154 None => return address,
155 };
156
157 let path_parts: heapless::Vec<&str, 16> = path
159 .trim_matches('/')
160 .split('/')
161 .filter(|s| !s.is_empty())
162 .collect();
163
164 if path_parts.is_empty() {
165 return address;
166 }
167
168 let mut current_address = address;
169
170 for depth in (0..path_parts.len()).rev() {
173 let parent_parts = &path_parts[..depth];
175 if parent_parts.is_empty() {
176 break;
178 }
179
180 let mut parent_path = heapless::String::<256>::new();
182 parent_path.push('/').ok();
183 for (i, part) in parent_parts.iter().enumerate() {
184 if i > 0 {
185 parent_path.push('/').ok();
186 }
187 parent_path.push_str(part).ok();
188 }
189
190 let parent_node = match self.find_by_path(parent_path.as_str()) {
191 Some(node) => node,
192 None => continue,
193 };
194
195 let ranges = match parent_node.ranges() {
197 Some(r) => r,
198 None => {
199 break;
201 }
202 };
203
204 let mut found = false;
206 for range in ranges.iter() {
207 if current_address >= range.child_address
209 && current_address < range.child_address + range.length
210 {
211 let offset = current_address - range.child_address;
213 current_address = range.parent_address + offset;
215 found = true;
216 break;
217 }
218 }
219
220 if !found {
221 }
224 }
225
226 current_address
227 }
228
229 pub fn memory_reservations(&self) -> MemoryReservationIter<'a> {
231 MemoryReservationIter {
232 data: self.data.as_slice(),
233 offset: self.header.off_mem_rsvmap as usize,
234 }
235 }
236
237 pub fn chosen(&self) -> Option<Chosen<'a>> {
238 for node in self.all_nodes() {
239 if let Node::Chosen(c) = node {
240 return Some(c);
241 }
242 }
243 None
244 }
245
246 pub fn memory(&self) -> Option<Memory<'a>> {
247 for node in self.all_nodes() {
248 if let Node::Memory(m) = node {
249 return Some(m);
250 }
251 }
252 None
253 }
254}
255
256impl fmt::Display for Fdt<'_> {
257 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
258 writeln!(f, "/dts-v1/;")?;
259 writeln!(f)?;
260
261 let mut prev_level = 0;
262
263 for node in self.all_nodes() {
264 let level = node.level();
265
266 while prev_level > level {
268 prev_level -= 1;
269 write_indent(f, prev_level, " ")?;
270 writeln!(f, "}};\n")?;
271 }
272
273 write_indent(f, level, " ")?;
274 let name = if node.name().is_empty() {
275 "/"
276 } else {
277 node.name()
278 };
279
280 writeln!(f, "{} {{", name)?;
282
283 for prop in node.properties() {
285 write_indent(f, level + 1, " ")?;
286 writeln!(f, "{};", prop)?;
287 }
288
289 prev_level = level + 1;
290 }
291
292 while prev_level > 0 {
294 prev_level -= 1;
295 write_indent(f, prev_level, " ")?;
296 writeln!(f, "}};\n")?;
297 }
298
299 Ok(())
300 }
301}
302
303impl fmt::Debug for Fdt<'_> {
304 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305 writeln!(f, "Fdt {{")?;
306 writeln!(f, "\theader: {:?}", self.header)?;
307 writeln!(f, "\tnodes:")?;
308
309 for node in self.all_nodes() {
310 let level = node.level();
311 write_indent(f, level + 2, "\t")?;
313
314 let name = if node.name().is_empty() {
315 "/"
316 } else {
317 node.name()
318 };
319
320 writeln!(
322 f,
323 "[{}] address_cells={}, size_cells={}",
324 name, node.address_cells, node.size_cells
325 )?;
326
327 for prop in node.properties() {
329 write_indent(f, level + 3, "\t")?;
330 if let Some(v) = prop.as_address_cells() {
331 writeln!(f, "#address-cells: {}", v)?;
332 } else if let Some(v) = prop.as_size_cells() {
333 writeln!(f, "#size-cells: {}", v)?;
334 } else if let Some(v) = prop.as_interrupt_cells() {
335 writeln!(f, "#interrupt-cells: {}", v)?;
336 } else if let Some(s) = prop.as_status() {
337 writeln!(f, "status: {:?}", s)?;
338 } else if let Some(p) = prop.as_phandle() {
339 writeln!(f, "phandle: {}", p)?;
340 } else {
341 if prop.is_empty() {
343 writeln!(f, "{}", prop.name())?;
344 } else if let Some(s) = prop.as_str() {
345 writeln!(f, "{}: \"{}\"", prop.name(), s)?;
346 } else if prop.len() == 4 {
347 let v = u32::from_be_bytes(prop.data().as_slice().try_into().unwrap());
348 writeln!(f, "{}: {:#x}", prop.name(), v)?;
349 } else {
350 writeln!(f, "{}: <{} bytes>", prop.name(), prop.len())?;
351 }
352 }
353 }
354 }
355
356 writeln!(f, "}}")
357 }
358}
359
360#[cfg(test)]
361mod tests {
362 use super::*;
363 use heapless::Vec;
364
365 #[test]
366 fn test_memory_reservation_iterator() {
367 let mut test_data = [0u8; 32];
369
370 test_data[0..8].copy_from_slice(&0x80000000u64.to_be_bytes());
372 test_data[8..16].copy_from_slice(&0x10000000u64.to_be_bytes());
373 test_data[16..24].copy_from_slice(&0u64.to_be_bytes());
375 test_data[24..32].copy_from_slice(&0u64.to_be_bytes());
376
377 let iter = MemoryReservationIter {
378 data: &test_data,
379 offset: 0,
380 };
381
382 let reservations: Vec<MemoryReservation, 4> = iter.collect();
383 assert_eq!(reservations.len(), 1);
384 assert_eq!(reservations[0].address, 0x80000000);
385 assert_eq!(reservations[0].size, 0x10000000);
386 }
387
388 #[test]
389 fn test_empty_memory_reservation_iterator() {
390 let mut test_data = [0u8; 16];
392 test_data[0..8].copy_from_slice(&0u64.to_be_bytes());
393 test_data[8..16].copy_from_slice(&0u64.to_be_bytes());
394
395 let iter = MemoryReservationIter {
396 data: &test_data,
397 offset: 0,
398 };
399
400 let reservations: Vec<MemoryReservation, 4> = iter.collect();
401 assert_eq!(reservations.len(), 0);
402 }
403}