1use core::ffi::CStr;
8
9use crate::parsing::{BigEndianU32, BigEndianU64, FdtData};
10use crate::standard_nodes::{Compatible, MemoryRange, MemoryRegion};
11use crate::{Error, Fdt, Result};
12
13mod cell_size;
14
15pub use cell_size::*;
16
17const FDT_BEGIN_NODE: u32 = 1;
18const FDT_END_NODE: u32 = 2;
19const FDT_PROP: u32 = 3;
20pub(crate) const FDT_NOP: u32 = 4;
21const FDT_END: u32 = 5;
22
23#[derive(Debug, Clone, Copy)]
24#[repr(C)]
25struct FdtProperty {
26 len: BigEndianU32,
27 name_offset: BigEndianU32,
28}
29
30impl FdtProperty {
31 fn from_bytes(bytes: &mut FdtData<'_>) -> Option<Self> {
32 let len = bytes.u32()?;
33 let name_offset = bytes.u32()?;
34
35 Some(Self { len, name_offset })
36 }
37}
38
39#[derive(Debug, Clone, Copy)]
41pub struct FdtNode<'b, 'a: 'b> {
42 pub name: &'a str,
43 pub(crate) header: &'b Fdt<'a>,
44 props: &'a [u8],
45 parent_props: Option<&'a [u8]>,
46}
47
48#[cfg(feature = "pretty-printing")]
49impl core::fmt::Display for FdtNode<'_, '_> {
50 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51 crate::pretty_print::print_node(f, *self, 0)?;
52 Ok(())
53 }
54}
55
56impl<'b, 'a: 'b> FdtNode<'b, 'a> {
57 fn new(
58 name: &'a str,
59 header: &'b Fdt<'a>,
60 props: &'a [u8],
61 parent_props: Option<&'a [u8]>,
62 ) -> Self {
63 Self { name, header, props, parent_props }
64 }
65
66 pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> + 'b {
68 let mut stream = FdtData::new(self.props);
69 let mut done = false;
70
71 core::iter::from_fn(move || {
72 if stream.is_empty() || done {
73 return None;
74 }
75
76 while stream.peek_u32()?.get() == FDT_NOP {
77 stream.skip(4);
78 }
79
80 if stream.peek_u32()?.get() == FDT_PROP {
81 NodeProperty::parse(&mut stream, self.header).ok()
82 } else {
83 done = true;
84 None
85 }
86 })
87 }
88
89 pub fn property(self, name: &str) -> Option<NodeProperty<'a>> {
91 self.properties().find(|p| p.name == name)
92 }
93
94 pub fn children(self) -> impl Iterator<Item = FdtNode<'b, 'a>> {
96 let mut stream = FdtData::new(self.props);
97
98 while stream.peek_u32().unwrap_or_default().get() == FDT_NOP {
99 stream.skip(4);
100 }
101
102 while stream.peek_u32().unwrap_or_default().get() == FDT_PROP {
103 NodeProperty::parse(&mut stream, self.header).ok();
104 }
105
106 let mut done = false;
107
108 core::iter::from_fn(move || {
109 if stream.is_empty() || done {
110 return None;
111 }
112
113 while stream.peek_u32()?.get() == FDT_NOP {
114 stream.skip(4);
115 }
116
117 if stream.peek_u32()?.get() == FDT_BEGIN_NODE {
118 let origin = stream.remaining();
119 let ret = {
120 stream.skip(4);
121 let unit_name =
122 CStr::from_bytes_until_nul(stream.remaining()).ok()?.to_str().ok()?;
123 let full_name_len = unit_name.len() + 1;
124 stream.skip(full_name_len);
125
126 if full_name_len % 4 != 0 {
127 stream.skip(4 - (full_name_len % 4));
128 }
129
130 Some(Self::new(unit_name, self.header, stream.remaining(), Some(self.props)))
131 };
132
133 stream = FdtData::new(origin);
134
135 skip_current_node(&mut stream, self.header);
136
137 ret
138 } else {
139 done = true;
140 None
141 }
142 })
143 }
144
145 pub fn reg(self) -> impl Iterator<Item = MemoryRegion> + 'a {
159 let sizes = self.parent_cell_sizes();
160
161 let mut reg = self.properties().find(|p| p.name == "reg").map(|p| FdtData::new(p.value));
162
163 core::iter::from_fn(move || match reg.as_mut() {
164 Some(stream) => {
165 let starting_address = match sizes.address_cells {
166 CellSize::One => Some(stream.u32()?.get() as usize),
167 CellSize::Two => Some(stream.u64()?.get() as usize),
168 _ => None,
169 }? as *const u8;
170
171 let size = match sizes.size_cells {
172 CellSize::None => Some(None),
173 CellSize::One => Some(Some(stream.u32()?.get() as usize)),
174 CellSize::Two => Some(Some(stream.u64()?.get() as usize)),
175 _ => None,
176 }?;
177
178 Some(MemoryRegion { starting_address, size })
179 }
180 None => None,
181 })
182 }
183
184 pub fn ranges(self) -> impl Iterator<Item = MemoryRange> + 'a {
186 let sizes = self.cell_sizes();
187 let parent_sizes = self.parent_cell_sizes();
188
189 let mut ranges =
190 self.properties().find(|p| p.name == "ranges").map(|p| FdtData::new(p.value));
191
192 core::iter::from_fn(move || match ranges.as_mut() {
193 Some(stream) => {
194 let (child_bus_address_hi, child_bus_address) = match sizes.address_cells {
195 CellSize::One => Some((0, stream.u32()?.get() as usize)),
196 CellSize::Two => Some((0, stream.u64()?.get() as usize)),
197 CellSize::Three => Some((stream.u32()?.get(), stream.u64()?.get() as usize)),
198 _ => None,
199 }?;
200
201 let parent_bus_address = match parent_sizes.address_cells {
202 CellSize::One => Some(stream.u32()?.get() as usize),
203 CellSize::Two => Some(stream.u64()?.get() as usize),
204 _ => None,
205 }?;
206
207 let size = match sizes.size_cells {
208 CellSize::One => Some(stream.u32()?.get() as usize),
209 CellSize::Two => Some(stream.u64()?.get() as usize),
210 _ => None,
211 }?;
212
213 Some(MemoryRange {
214 child_bus_address,
215 child_bus_address_hi,
216 parent_bus_address,
217 size,
218 })
219 }
220 None => None,
221 })
222 }
223
224 pub fn raw_reg(self) -> impl Iterator<Item = RawReg<'a>> + 'a {
227 let sizes = self.parent_cell_sizes();
228
229 let mut reg = self.property("reg").map(|p| FdtData::new(p.value));
230 core::iter::from_fn(move || match reg.as_mut() {
231 Some(stream) => Some(RawReg {
232 address: stream.take(sizes.address_cells.to_usize() * 4)?,
233 size: stream.take(sizes.size_cells.to_usize() * 4)?,
234 }),
235 None => None,
236 })
237 }
238
239 pub fn compatible(self) -> Option<Compatible<'a>> {
241 let mut s = None;
242 for prop in self.properties() {
243 if prop.name == "compatible" {
244 s = Some(Compatible { data: prop.value });
245 }
246 }
247
248 s
249 }
250
251 pub fn cell_sizes(self) -> CellSizes {
253 let mut cell_sizes = CellSizes::default();
254
255 for property in self.properties() {
256 match property.name {
257 "#address-cells" => {
258 cell_sizes.address_cells =
259 BigEndianU32::from_bytes(property.value).unwrap_or_default().get().into();
260 }
261 "#size-cells" => {
262 cell_sizes.size_cells =
263 BigEndianU32::from_bytes(property.value).unwrap_or_default().get().into();
264 }
265 _ => {}
266 }
267 }
268
269 cell_sizes
270 }
271
272 pub fn interrupt_parent(self) -> Option<FdtNode<'b, 'a>> {
274 self.properties()
275 .find(|p| p.name == "interrupt-parent")
276 .and_then(|p| self.header.find_phandle(BigEndianU32::from_bytes(p.value)?.get()))
277 }
278
279 pub fn interrupt_cells(self) -> Option<usize> {
281 let mut interrupt_cells = None;
282
283 if let Some(prop) = self.property("#interrupt-cells") {
284 interrupt_cells = BigEndianU32::from_bytes(prop.value).map(|n| n.get() as usize)
285 }
286
287 interrupt_cells
288 }
289
290 pub fn interrupts(self) -> impl Iterator<Item = usize> + 'a {
292 let sizes = self.parent_interrupt_cells();
293
294 let mut interrupt =
295 self.properties().find(|p| p.name == "interrupts").map(|p| FdtData::new(p.value));
296
297 core::iter::from_fn(move || match interrupt.as_mut() {
298 Some(stream) => match sizes {
299 Some(1) => Some(stream.u32()?.get() as usize),
300 Some(2) => Some(stream.u64()?.get() as usize),
301 _ => None,
302 },
303 None => None,
304 })
305 }
306
307 pub(crate) fn parent_cell_sizes(self) -> CellSizes {
308 let mut cell_sizes = CellSizes::default();
309
310 if let Some(parent) = self.parent_props {
311 let parent =
312 FdtNode { name: "", props: parent, header: self.header, parent_props: None };
313 cell_sizes = parent.cell_sizes();
314 }
315
316 cell_sizes
317 }
318
319 pub(crate) fn parent_interrupt_cells(self) -> Option<usize> {
320 let mut interrupt_cells = None;
321 let parent = self
322 .property("interrupt-parent")
323 .and_then(|p| self.header.find_phandle(BigEndianU32::from_bytes(p.value)?.get()))
324 .or_else(|| {
325 let p = FdtNode::new("", self.header, self.parent_props?, None)
327 .property("interrupt-parent")?;
328 self.header.find_phandle(BigEndianU32::from_bytes(p.value)?.get())
329 });
330
331 if let Some(size) = parent.and_then(|parent| parent.interrupt_cells()) {
332 interrupt_cells = Some(size);
333 }
334
335 interrupt_cells
336 }
337}
338
339#[derive(Debug, Clone, Copy, Eq, PartialEq)]
341pub struct CellSizes {
342 pub address_cells: CellSize,
344 pub size_cells: CellSize,
346}
347
348impl CellSizes {
349 pub const fn new() -> Self {
351 Self { address_cells: CellSize::Two, size_cells: CellSize::One }
352 }
353}
354
355impl Default for CellSizes {
356 fn default() -> Self {
357 Self::new()
358 }
359}
360
361#[derive(Debug, Clone, Copy, PartialEq)]
363pub struct RawReg<'a> {
364 pub address: &'a [u8],
367 pub size: &'a [u8],
370}
371
372pub(crate) fn find_node<'b, 'a: 'b>(
373 stream: &mut FdtData<'a>,
374 name: &str,
375 header: &'b Fdt<'a>,
376 parent_props: Option<&'a [u8]>,
377) -> Option<FdtNode<'b, 'a>> {
378 let mut parts = name.splitn(2, '/');
379 let looking_for = parts.next()?;
380
381 stream.skip_nops();
382
383 let curr_data = stream.remaining();
384
385 match stream.u32()?.get() {
386 FDT_BEGIN_NODE => {}
387 _ => return None,
388 }
389
390 let unit_name = CStr::from_bytes_until_nul(stream.remaining()).ok()?.to_str().ok()?;
391
392 let full_name_len = unit_name.len() + 1;
393 skip_4_aligned(stream, full_name_len);
394
395 let looking_contains_addr = looking_for.contains('@');
396 let addr_name_same = unit_name == looking_for;
397 let base_name_same = unit_name.split('@').next()? == looking_for;
398
399 if (looking_contains_addr && !addr_name_same) || (!looking_contains_addr && !base_name_same) {
400 *stream = FdtData::new(curr_data);
401 skip_current_node(stream, header)?;
402
403 return None;
404 }
405
406 let next_part = match parts.next() {
407 None | Some("") => {
408 return Some(FdtNode::new(unit_name, header, stream.remaining(), parent_props))
409 }
410 Some(part) => part,
411 };
412
413 stream.skip_nops();
414
415 let parent_props = Some(stream.remaining());
416
417 while stream.peek_u32()?.get() == FDT_PROP {
418 let _ = NodeProperty::parse(stream, header);
419 }
420
421 while stream.peek_u32()?.get() == FDT_BEGIN_NODE {
422 if let Some(p) = find_node(stream, next_part, header, parent_props) {
423 return Some(p);
424 }
425 }
426
427 stream.skip_nops();
428
429 if stream.u32()?.get() != FDT_END_NODE {
430 return None;
431 }
432
433 None
434}
435
436pub(crate) fn all_nodes<'b, 'a: 'b>(header: &'b Fdt<'a>) -> impl Iterator<Item = FdtNode<'b, 'a>> {
438 let mut stream = FdtData::new(header.structs_block());
439 let mut done = false;
440 let mut parents: [&[u8]; 64] = [&[]; 64];
441 let mut parent_index = 0;
442
443 core::iter::from_fn(move || {
444 if stream.is_empty() || done {
445 return None;
446 }
447
448 while stream.peek_u32()?.get() == FDT_END_NODE {
449 parent_index -= 1;
450 stream.skip(4);
451 }
452
453 if stream.peek_u32()?.get() == FDT_END {
454 done = true;
455 return None;
456 }
457
458 while stream.peek_u32()?.get() == FDT_NOP {
459 stream.skip(4);
460 }
461
462 match stream.u32()?.get() {
463 FDT_BEGIN_NODE => {}
464 _ => return None,
465 }
466
467 let unit_name = CStr::from_bytes_until_nul(stream.remaining()).ok()?.to_str().ok()?;
468 let full_name_len = unit_name.len() + 1;
469 skip_4_aligned(&mut stream, full_name_len);
470
471 let curr_node = stream.remaining();
472
473 parent_index += 1;
474 parents[parent_index] = curr_node;
475
476 while stream.peek_u32()?.get() == FDT_NOP {
477 stream.skip(4);
478 }
479
480 while stream.peek_u32()?.get() == FDT_PROP {
481 NodeProperty::parse(&mut stream, header).ok()?;
482 }
483
484 Some(FdtNode {
485 name: if unit_name.is_empty() { "/" } else { unit_name },
486 header,
487 parent_props: match parent_index {
488 1 => None,
489 _ => parents.get(parent_index.saturating_sub(1)).copied(),
490 },
491 props: curr_node,
492 })
493 })
494}
495
496pub(crate) fn skip_current_node<'a>(stream: &mut FdtData<'a>, header: &Fdt<'a>) -> Option<()> {
497 if stream.u32()?.get() == FDT_BEGIN_NODE { Some(()) } else { None }?;
498
499 let unit_name = CStr::from_bytes_until_nul(stream.remaining()).ok()?.to_str().ok()?;
500 let full_name_len = unit_name.len().saturating_add(1);
501 skip_4_aligned(stream, full_name_len);
502
503 while stream.peek_u32()?.get() == FDT_PROP {
504 NodeProperty::parse(stream, header).ok()?;
505 }
506
507 while stream.peek_u32()?.get() == FDT_BEGIN_NODE {
508 skip_current_node(stream, header);
509 }
510
511 stream.skip_nops();
512
513 if stream.u32()?.get() == FDT_END_NODE {
514 Some(())
515 } else {
516 None
517 }
518}
519
520#[derive(Debug, Clone, Copy)]
522pub struct NodeProperty<'a> {
523 pub name: &'a str,
525 pub value: &'a [u8],
527}
528
529impl<'a> NodeProperty<'a> {
530 pub fn as_usize(self) -> Option<usize> {
532 match self.value.len() {
533 4 => BigEndianU32::from_bytes(self.value).map(|i| i.get() as usize),
534 8 => BigEndianU64::from_bytes(self.value).map(|i| i.get() as usize),
535 _ => None,
536 }
537 }
538
539 pub fn iter_cell_size(self, cell_size: CellSize) -> impl Iterator<Item = u64> + 'a {
545 let mut cells = FdtData::new(self.value);
546
547 core::iter::from_fn(move || match cell_size {
548 CellSize::One => Some(cells.u32()?.get() as u64),
549 CellSize::Two => Some(cells.u64()?.get()),
550 _ => None,
551 })
552 }
553
554 pub fn iter_prop_encoded(self, cell_sizes: CellSizes) -> impl Iterator<Item = (u64, u64)> + 'a {
556 let mut cells = FdtData::new(self.value);
557
558 core::iter::from_fn(move || {
559 let addr = match cell_sizes.address_cells {
560 CellSize::One => Some(cells.u32()?.get() as u64),
561 CellSize::Two => Some(cells.u64()?.get()),
562 _ => None,
563 }?;
564
565 let size = match cell_sizes.size_cells {
566 CellSize::One => Some(cells.u32()?.get() as u64),
567 CellSize::Two => Some(cells.u64()?.get()),
568 _ => None,
569 }?;
570
571 Some((addr, size))
572 })
573 }
574
575 pub fn as_str(self) -> Option<&'a str> {
577 core::str::from_utf8(self.value).map(|s| s.trim_end_matches('\0')).ok()
578 }
579
580 pub fn iter_str(self) -> impl Iterator<Item = &'a str> + 'a {
582 let mut strs = self.as_str().map(|s| s.split('\0'));
583
584 core::iter::from_fn(move || match strs.as_mut() {
585 Some(s) => s.next(),
586 None => None,
587 })
588 }
589
590 fn parse(stream: &mut FdtData<'a>, header: &Fdt<'a>) -> Result<Self> {
591 match stream.u32() {
592 Some(p) if p.get() == FDT_PROP => Ok(()),
593 Some(other) => Err(Error::BadPropTag((other.get(), FDT_PROP))),
594 None => Err(Error::BadPropTag((0, FDT_PROP))),
595 }?;
596
597 let prop = FdtProperty::from_bytes(stream).ok_or(Error::MissingProperty)?;
598 let data_len = prop.len.get() as usize;
599
600 let data = stream.remaining().get(..data_len).unwrap_or_default();
601
602 skip_4_aligned(stream, data_len);
603
604 Ok(NodeProperty {
605 name: header.str_at_offset(prop.name_offset.get() as usize),
606 value: data,
607 })
608 }
609}
610
611#[derive(Debug)]
613#[repr(C)]
614pub struct MemoryReservation {
615 pub(crate) address: BigEndianU64,
616 pub(crate) size: BigEndianU64,
617}
618
619impl MemoryReservation {
620 pub fn address(&self) -> *const u8 {
622 self.address.get() as usize as *const u8
623 }
624
625 pub fn size(&self) -> usize {
627 self.size.get() as usize
628 }
629
630 pub(crate) fn from_bytes(bytes: &mut FdtData<'_>) -> Option<Self> {
631 let address = bytes.u64()?;
632 let size = bytes.u64()?;
633
634 Some(Self { address, size })
635 }
636}
637
638fn skip_4_aligned(stream: &mut FdtData<'_>, len: usize) {
639 stream.skip((len + 3) & !0x3);
640}