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