1use core::{iter, ptr::NonNull};
2
3use crate::{
4 chosen::Chosen, error::*, memory::Memory, meta::MetaData, node::Node, read::FdtReader,
5 FdtHeader, MemoryRegion, Phandle, Token,
6};
7
8#[derive(Clone)]
10pub struct Fdt<'a> {
11 pub(crate) header: FdtHeader,
12 pub(crate) data: &'a [u8],
13}
14
15impl<'a> Fdt<'a> {
16
17 pub fn as_slice(&self) -> &'a [u8] {
19 self.data
20 }
21
22 pub fn from_bytes(data: &'a [u8]) -> FdtResult<'a, Self> {
24 let header = FdtHeader::from_bytes(data)?;
25
26 header.valid_magic()?;
27
28 Ok(Self { header, data })
29 }
30
31 pub fn from_ptr(ptr: NonNull<u8>) -> FdtResult<'a, Self> {
33 let tmp_header =
34 unsafe { core::slice::from_raw_parts(ptr.as_ptr(), core::mem::size_of::<FdtHeader>()) };
35 let real_size = FdtHeader::from_bytes(tmp_header)?.totalsize.get() as usize;
36
37 Self::from_bytes(unsafe { core::slice::from_raw_parts(ptr.as_ptr(), real_size) })
38 }
39
40 fn reader(&'a self, offset: usize) -> FdtReader<'a> {
41 FdtReader::new(&self.data[offset..])
42 }
43
44 pub fn total_size(&self) -> usize {
45 self.header.totalsize.get() as _
46 }
47
48 pub fn version(&self) -> usize {
49 self.header.version.get() as _
50 }
51
52 pub fn boot_cpuid_phys(&self) -> u32 {
55 self.header.boot_cpuid_phys.get()
56 }
57
58 pub fn memory_reservation_block(&self) -> impl Iterator<Item = MemoryRegion> + '_ {
62 let mut reader = self.reader(self.header.off_mem_rsvmap.get() as _);
63 iter::from_fn(move || match reader.reserved_memory() {
64 Some(region) => {
65 if region.address == 0 && region.size == 0 {
66 None
67 } else {
68 Some(region.into())
69 }
70 }
71 None => None,
72 })
73 }
74
75 pub fn reserved_memory(&self) -> impl Iterator<Item = Node<'a>> + 'a {
79 self.find_nodes("/reserved-memory")
80 }
81
82 pub(crate) fn get_str(&self, offset: usize) -> FdtResult<'a, &'a str> {
83 let string_bytes = &self.data[self.header.strings_range()];
84 let reader = FdtReader::new(&string_bytes[offset..]);
85 reader.peek_str()
86 }
87
88 pub fn all_nodes(&self) -> impl Iterator<Item = Node<'a>> {
89 self.new_fdt_itr()
90 }
91
92 fn new_fdt_itr(&self) -> FdtIter<'a> {
93 let struct_bytes = &self.data[self.header.struct_range()];
94
95 let reader = FdtReader::new(struct_bytes);
96 FdtIter {
97 fdt: self.clone(),
98 current_level: 0,
99 reader,
100 stack: Default::default(),
101 node_reader: None,
102 node_name: "",
103 }
104 }
105
106 pub fn chosen(&'a self) -> Option<Chosen<'a>> {
107 self.find_nodes("/chosen").next().map(Chosen::new)
108 }
109
110 pub fn get_node_by_phandle(&self, phandle: Phandle) -> Option<Node<'a>> {
111 self.all_nodes()
112 .find(|x| match x.phandle() {
113 Some(p) => p.eq(&phandle),
114 None => false,
115 })
116 .clone()
117 }
118
119 pub fn get_node_by_name(&'a self, name: &str) -> Option<Node<'a>> {
120 self.all_nodes().find(|x| x.name().eq(name)).clone()
121 }
122
123 pub fn find_compatible(&'a self, with: &'a [&'a str]) -> impl Iterator<Item = Node<'a>> + 'a {
124 let mut all = self.all_nodes();
125
126 iter::from_fn(move || loop {
127 let node = all.next()?;
128 let caps = node.compatibles();
129 for cap in caps {
130 for want in with {
131 if cap.eq(*want) {
132 return Some(node);
133 }
134 }
135 }
136 })
137 }
138
139 pub fn find_nodes(&self, path: &'a str) -> impl Iterator<Item = Node<'a>> + 'a {
141 let path = if path.starts_with("/") {
142 path
143 } else {
144 self.find_aliase(path).expect("aliase not found")
145 };
146
147 IterFindNode::new(self.new_fdt_itr(), path)
148 }
149
150 pub fn find_aliase(&self, name: &str) -> Option<&'a str> {
151 let aliases = self.find_nodes("/aliases").next()?;
152 for prop in aliases.propertys() {
153 if prop.name.eq(name) {
154 return Some(prop.str());
155 }
156 }
157 None
158 }
159
160 pub fn memory(&'a self) -> impl Iterator<Item = Memory<'a>> + 'a {
161 self.find_nodes("/memory").map(Memory::new)
162 }
163}
164
165pub struct FdtIter<'a> {
166 fdt: Fdt<'a>,
167 current_level: usize,
168 reader: FdtReader<'a>,
169 stack: [MetaData<'a>; 12],
170 node_reader: Option<FdtReader<'a>>,
171 node_name: &'a str,
172}
173
174impl<'a> FdtIter<'a> {
175 fn get_meta_parent(&self) -> MetaData<'a> {
176 let mut meta = MetaData::default();
177 let level = match self.level_parent_index() {
178 Some(l) => l,
179 None => return MetaData::default(),
180 } + 1;
181 macro_rules! get_field {
182 ($cell:ident) => {{
183 let mut size = None;
184 for i in (0..level).rev() {
185 if let Some(cell_size) = &self.stack[i].$cell {
186 size = Some(cell_size.clone());
187 break;
188 }
189 }
190 meta.$cell = size;
191 }};
192 }
193
194 get_field!(address_cells);
195 get_field!(size_cells);
196 get_field!(clock_cells);
197 get_field!(interrupt_cells);
198 get_field!(gpio_cells);
199 get_field!(dma_cells);
200 get_field!(cooling_cells);
201 get_field!(range);
202 get_field!(interrupt_parent);
203
204 meta
205 }
206 fn level_current_index(&self) -> usize {
207 self.current_level - 1
208 }
209 fn level_parent_index(&self) -> Option<usize> {
210 if self.level_current_index() > 0 {
211 Some(self.level_current_index() - 1)
212 } else {
213 None
214 }
215 }
216
217 fn handle_node_begin(&mut self) {
218 self.current_level += 1;
219 let i = self.level_current_index();
220 self.stack[i] = MetaData::default();
221 self.node_name = self.reader.take_unit_name().unwrap();
222 self.node_reader = Some(self.reader.clone());
223 }
224
225 fn finish_node(&mut self) -> Option<Node<'a>> {
226 let reader = self.node_reader.take()?;
227 let level = self.current_level;
228 let meta = self.stack[self.level_current_index()].clone();
229 let meta_parent = self.get_meta_parent();
230
231 let mut node = Node::new(&self.fdt, level, self.node_name, reader, meta_parent, meta);
232 let ranges = node.node_ranges();
233 self.stack[self.level_current_index()].range = ranges.clone();
234 let ph = node.node_interrupt_parent();
235 self.stack[self.level_current_index()].interrupt_parent = ph;
236
237 node.meta = self.stack[self.level_current_index()].clone();
238
239 Some(node)
240 }
241}
242
243impl<'a> Iterator for FdtIter<'a> {
244 type Item = Node<'a>;
245
246 fn next(&mut self) -> Option<Self::Item> {
247 loop {
248 let token = self.reader.take_token()?;
249
250 match token {
251 Token::BeginNode => {
252 let node = self.finish_node();
253 self.handle_node_begin();
254 if node.is_some() {
255 return node;
256 }
257 }
258 Token::EndNode => {
259 let node = self.finish_node();
260 self.current_level -= 1;
261 if node.is_some() {
262 return node;
263 }
264 }
265 Token::Prop => {
266 let prop = self.reader.take_prop(&self.fdt)?;
267 let index = self.level_current_index();
268 macro_rules! update_cell {
269 ($cell:ident) => {
270 self.stack[index].$cell = Some(prop.u32() as _)
271 };
272 }
273 match prop.name {
274 "#address-cells" => update_cell!(address_cells),
275 "#size-cells" => update_cell!(size_cells),
276 "#clock-cells" => update_cell!(clock_cells),
277 "#interrupt-cells" => update_cell!(interrupt_cells),
278 "#gpio-cells" => update_cell!(gpio_cells),
279 "#dma-cells" => update_cell!(dma_cells),
280 "#cooling-cells" => update_cell!(cooling_cells),
281 _ => {}
282 }
283 }
284 Token::End => {
285 return self.finish_node();
286 }
287 _ => {}
288 }
289 }
290 }
291}
292
293struct IterFindNode<'a> {
294 itr: FdtIter<'a>,
295 want: &'a str,
296 want_itr: usize,
297 is_path_last: bool,
298}
299
300impl<'a> IterFindNode<'a> {
301 fn new(itr: FdtIter<'a>, want: &'a str) -> Self {
302 IterFindNode {
303 itr,
304 want,
305 want_itr: 0,
306 is_path_last: false,
307 }
308 }
309}
310
311impl<'a> Iterator for IterFindNode<'a> {
312 type Item = Node<'a>;
313
314 fn next(&mut self) -> Option<Self::Item> {
315 let mut out = None;
316 loop {
317 let mut parts = self.want.split("/").filter(|o| !o.is_empty());
318 let mut want_part = "/";
319 for _ in 0..self.want_itr {
320 if let Some(part) = parts.next() {
321 want_part = part;
322 } else {
323 self.is_path_last = true;
324 if let Some(out) = out {
325 return Some(out);
326 }
327 }
328 }
329 let node = self.itr.next()?;
330
331 let eq = if want_part.contains("@") {
332 node.name.eq(want_part)
333 } else {
334 let name = node.name.split("@").next().unwrap();
335 name.eq(want_part)
336 };
337 if eq {
338 self.want_itr += 1;
339 out = Some(node);
340 }
341 }
342 }
343}