fdt_parser/base/
fdt.rs

1use core::iter;
2
3use super::node::*;
4use crate::{
5    data::{Buffer, Raw},
6    FdtError, FdtRangeSilce, Header, MemoryRegion, Phandle, Property, Token,
7};
8
9#[derive(Clone)]
10pub struct Fdt<'a> {
11    header: Header,
12    pub(crate) raw: Raw<'a>,
13}
14
15impl<'a> Fdt<'a> {
16    /// Create a new `Fdt` from byte slice.
17    pub fn from_bytes(data: &'a [u8]) -> Result<Fdt<'a>, FdtError> {
18        let header = Header::from_bytes(data)?;
19        if data.len() < header.totalsize as usize {
20            return Err(FdtError::BufferTooSmall {
21                pos: header.totalsize as usize,
22            });
23        }
24        let buffer = Raw::new(data);
25        Ok(Fdt {
26            header,
27            raw: buffer,
28        })
29    }
30
31    /// Create a new `Fdt` from a raw pointer and size in bytes.
32    ///
33    /// # Safety
34    ///
35    /// The caller must ensure that the pointer is valid and points to a
36    /// memory region of at least `size` bytes that contains a valid device tree
37    /// blob.
38    pub unsafe fn from_ptr(ptr: *mut u8) -> Result<Fdt<'a>, FdtError> {
39        let header = unsafe { Header::from_ptr(ptr)? };
40
41        let raw = Raw::new(core::slice::from_raw_parts(ptr, header.totalsize as _));
42
43        Ok(Fdt { header, raw })
44    }
45
46    pub fn as_slice(&self) -> &'a [u8] {
47        self.raw.value()
48    }
49
50    /// Get a reference to the FDT header.
51    pub fn header(&self) -> &Header {
52        &self.header
53    }
54
55    pub fn total_size(&self) -> usize {
56        self.header.totalsize as usize
57    }
58
59    /// This field shall contain the physical ID of the system's boot CPU. It shall be identical to the physical ID given in the
60    /// reg property of that CPU node within the devicetree.
61    pub fn boot_cpuid_phys(&self) -> u32 {
62        self.header.boot_cpuid_phys
63    }
64
65    /// Get a reference to the underlying buffer.
66    pub fn raw(&self) -> &'a [u8] {
67        self.raw.value()
68    }
69
70    /// Get the FDT version
71    pub fn version(&self) -> u32 {
72        self.header.version
73    }
74
75    pub fn memory_reservation_blocks(&self) -> impl Iterator<Item = MemoryRegion> + 'a {
76        let mut buffer = self
77            .raw
78            .begin_at(self.header.off_mem_rsvmap as usize)
79            .buffer();
80
81        core::iter::from_fn(move || {
82            let address = buffer.take_u64().ok()?;
83            let size = buffer.take_u64().ok()?;
84
85            if address == 0 && size == 0 {
86                return None;
87            }
88
89            Some(MemoryRegion {
90                address: address as usize as _,
91                size: size as _,
92            })
93        })
94    }
95
96    pub(crate) fn get_str(&self, offset: usize) -> Result<&'a str, FdtError> {
97        let start = self.header.off_dt_strings as usize + offset;
98        let mut buffer = self.raw.begin_at(start).buffer();
99        buffer.take_str()
100    }
101
102    pub fn all_nodes(&self) -> NodeIter<'a, 16> {
103        NodeIter::new(self.clone())
104    }
105
106    /// if path start with '/' then search by path, else search by aliases
107    pub fn find_nodes(
108        &self,
109        path: &'a str,
110    ) -> impl Iterator<Item = Result<Node<'a>, FdtError>> + 'a {
111        let path = if path.starts_with("/") {
112            path
113        } else {
114            self.find_aliase(path).unwrap()
115        };
116
117        IterFindNode::new(self.all_nodes(), path)
118    }
119
120    pub fn find_aliase(&self, name: &str) -> Result<&'a str, FdtError> {
121        let aliases = self
122            .find_nodes("/aliases")
123            .next()
124            .ok_or(FdtError::NoAlias)??;
125        for prop in aliases.properties() {
126            let prop = prop?;
127            if prop.name.eq(name) {
128                return prop.str();
129            }
130        }
131        Err(FdtError::NoAlias)
132    }
133
134    pub fn find_compatible<'b, 'c: 'b>(
135        &'b self,
136        with: &'c [&'c str],
137    ) -> impl Iterator<Item = Result<Node<'a>, FdtError>> + 'b {
138        let mut iter = self.all_nodes();
139        let mut has_err = false;
140        iter::from_fn(move || loop {
141            if has_err {
142                return None;
143            }
144            let node = iter.next()?;
145            let node = match node {
146                Ok(n) => n,
147                Err(e) => {
148                    return {
149                        has_err = true;
150                        Some(Err(e))
151                    }
152                }
153            };
154            match node.compatibles() {
155                Ok(mut comp) => {
156                    if comp.any(|c| with.iter().any(|w| w.eq(&c))) {
157                        return Some(Ok(node));
158                    }
159                }
160                Err(FdtError::NotFound) => {}
161                Err(e) => {
162                    return {
163                        has_err = true;
164                        Some(Err(e))
165                    }
166                }
167            }
168        })
169    }
170
171    pub fn chosen(&self) -> Result<Chosen<'a>, FdtError> {
172        let node = self
173            .find_nodes("/chosen")
174            .next()
175            .ok_or(FdtError::NotFound)??;
176        let node = match node {
177            Node::Chosen(c) => c,
178            _ => return Err(FdtError::NodeNotFound("chosen")),
179        };
180        Ok(node)
181    }
182
183    pub fn get_node_by_phandle(&self, phandle: Phandle) -> Result<Node<'a>, FdtError> {
184        for node in self.all_nodes() {
185            let node = node?;
186            match node.phandle() {
187                Ok(p) if p == phandle => return Ok(node),
188                Ok(_) => {}
189                Err(FdtError::NotFound) => {}
190                Err(e) => return Err(e),
191            }
192        }
193        Err(FdtError::NotFound)
194    }
195
196    pub fn get_node_by_name(&'a self, name: &str) -> Result<Node<'a>, FdtError> {
197        for node in self.all_nodes() {
198            let node = node?;
199            if node.name() == name {
200                return Ok(node);
201            }
202        }
203        Err(FdtError::NotFound)
204    }
205
206    pub fn memory(&'a self) -> impl Iterator<Item = Result<Memory<'a>, FdtError>> + 'a {
207        self.find_nodes("/memory@").map(|o| {
208            o.map(|o| match o {
209                Node::Memory(m) => m,
210                _ => unreachable!(),
211            })
212        })
213    }
214
215    /// Get the reserved-memory node
216    fn reserved_memory_node(&self) -> Result<Node<'a>, FdtError> {
217        let node = self
218            .find_nodes("/reserved-memory")
219            .next()
220            .ok_or(FdtError::NotFound)?;
221        node
222    }
223
224    /// Get all reserved-memory child nodes (memory regions)
225    pub fn reserved_memory_regions(&self) -> Result<ReservedMemoryRegionsIter<'a>, FdtError> {
226        match self.reserved_memory_node() {
227            Ok(reserved_memory_node) => Ok(ReservedMemoryRegionsIter::new(reserved_memory_node)),
228            Err(FdtError::NotFound) => Ok(ReservedMemoryRegionsIter::empty()),
229            Err(e) => Err(e),
230        }
231    }
232}
233
234/// Iterator for reserved memory regions (child nodes of reserved-memory)
235pub struct ReservedMemoryRegionsIter<'a> {
236    child_iter: Option<NodeChildIter<'a>>,
237}
238
239impl<'a> ReservedMemoryRegionsIter<'a> {
240    /// Create a new iterator for reserved memory regions
241    fn new(reserved_memory_node: Node<'a>) -> Self {
242        ReservedMemoryRegionsIter {
243            child_iter: Some(reserved_memory_node.children()),
244        }
245    }
246
247    /// Create an empty iterator
248    fn empty() -> Self {
249        ReservedMemoryRegionsIter { child_iter: None }
250    }
251
252    /// Find a reserved memory region by name
253    pub fn find_by_name(self, name: &str) -> Result<Node<'a>, FdtError> {
254        for region_result in self {
255            let region = region_result?;
256            if region.name() == name {
257                return Ok(region);
258            }
259        }
260        Err(FdtError::NotFound)
261    }
262
263    /// Find reserved memory regions by compatible string
264    pub fn find_by_compatible(
265        self,
266        compatible: &str,
267    ) -> Result<alloc::vec::Vec<Node<'a>>, FdtError> {
268        let mut matching_regions = alloc::vec::Vec::new();
269
270        for region_result in self {
271            let region = region_result?;
272            match region.compatibles() {
273                Ok(mut compatibles) => {
274                    if compatibles.any(|comp| comp == compatible) {
275                        matching_regions.push(region);
276                    }
277                }
278                Err(FdtError::NotFound) => {}
279                Err(e) => return Err(e),
280            }
281        }
282
283        Ok(matching_regions)
284    }
285}
286
287impl<'a> Iterator for ReservedMemoryRegionsIter<'a> {
288    type Item = Result<Node<'a>, FdtError>;
289
290    fn next(&mut self) -> Option<Self::Item> {
291        match &mut self.child_iter {
292            Some(iter) => iter.next(),
293            None => None,
294        }
295    }
296}
297
298/// Stack frame for tracking node context during iteration
299#[derive(Clone)]
300struct NodeStackFrame<'a> {
301    level: usize,
302    node: NodeBase<'a>,
303    address_cells: u8,
304    size_cells: u8,
305    ranges: Option<FdtRangeSilce<'a>>,
306    interrupt_parent: Option<Phandle>,
307}
308
309pub struct NodeIter<'a, const MAX_DEPTH: usize = 16> {
310    buffer: Buffer<'a>,
311    fdt: Fdt<'a>,
312    level: isize,
313    has_err: bool,
314    // Stack to store complete node hierarchy
315    node_stack: heapless::Vec<NodeStackFrame<'a>, MAX_DEPTH>,
316}
317
318impl<'a, const MAX_DEPTH: usize> NodeIter<'a, MAX_DEPTH> {
319    /// Create a new NodeIter with the given FDT
320    pub fn new(fdt: Fdt<'a>) -> Self {
321        NodeIter {
322            buffer: fdt.raw.begin_at(fdt.header.off_dt_struct as usize).buffer(),
323            fdt,
324            level: -1,
325            has_err: false,
326            node_stack: heapless::Vec::new(),
327        }
328    }
329
330    /// Get the current node from stack (parent of the node being created)
331    fn current_parent(&self) -> Option<&NodeBase<'a>> {
332        self.node_stack.last().map(|frame| &frame.node)
333    }
334
335    /// Get the current effective interrupt parent phandle from the stack
336    fn current_interrupt_parent(&self) -> Option<Phandle> {
337        // Search from the top of the stack downward for the first interrupt parent
338        for frame in self.node_stack.iter().rev() {
339            if let Some(phandle) = frame.interrupt_parent {
340                return Some(phandle);
341            }
342        }
343        None
344    }
345
346    /// Get address_cells and size_cells from parent frame
347    fn current_cells(&self) -> (u8, u8) {
348        self.node_stack
349            .last()
350            .map(|frame| (frame.address_cells, frame.size_cells))
351            .unwrap_or((2, 1))
352    }
353
354    /// Push a new node onto the stack
355    fn push_node(&mut self, frame: NodeStackFrame<'a>) -> Result<(), FdtError> {
356        self.node_stack
357            .push(frame)
358            .map_err(|_| FdtError::BufferTooSmall {
359                pos: self.node_stack.len(),
360            })
361    }
362
363    /// Pop nodes from stack when exiting to a certain level
364    fn pop_to_level(&mut self, target_level: isize) {
365        while let Some(frame) = self.node_stack.last() {
366            if frame.level as isize > target_level {
367                self.node_stack.pop();
368            } else {
369                break;
370            }
371        }
372    }
373
374    /// Scan ahead to find node properties (#address-cells, #size-cells, interrupt-parent, ranges)
375    fn scan_node_properties(
376        &self,
377    ) -> Result<
378        (
379            Option<u8>,
380            Option<u8>,
381            Option<Phandle>,
382            Option<Property<'a>>,
383        ),
384        FdtError,
385    > {
386        let mut address_cells = None;
387        let mut size_cells = None;
388        let mut interrupt_parent = self.current_interrupt_parent();
389        let mut ranges = None;
390        let mut temp_buffer = self.buffer.clone();
391
392        // Look for properties in this node
393        loop {
394            match temp_buffer.take_token() {
395                Ok(Token::Prop) => {
396                    let prop = temp_buffer.take_prop(&self.fdt)?;
397                    match prop.name {
398                        "#address-cells" => {
399                            if let Ok(value) = prop.u32() {
400                                address_cells = Some(value as u8);
401                            }
402                        }
403                        "#size-cells" => {
404                            if let Ok(value) = prop.u32() {
405                                size_cells = Some(value as u8);
406                            }
407                        }
408                        "interrupt-parent" => {
409                            if let Ok(phandle_value) = prop.u32() {
410                                interrupt_parent = Some(Phandle::from(phandle_value));
411                            }
412                        }
413                        "ranges" => {
414                            ranges = Some(prop);
415                        }
416                        _ => {}
417                    }
418                }
419                Ok(Token::BeginNode) | Ok(Token::EndNode) | Ok(Token::End) => {
420                    break;
421                }
422                _ => {
423                    continue;
424                }
425            }
426        }
427
428        Ok((address_cells, size_cells, interrupt_parent, ranges))
429    }
430
431    /// Handle BeginNode token and create a new node
432    fn handle_begin_node(&mut self) -> Result<Option<NodeBase<'a>>, FdtError> {
433        self.level += 1;
434
435        let name = self.buffer.take_str()?;
436        self.buffer.take_to_aligned();
437
438        // Scan node properties including ranges
439        let (address_cells, size_cells, interrupt_parent, ranges_prop) =
440            self.scan_node_properties()?;
441
442        // Use defaults from parent if not specified
443        let (default_addr, default_size) = self.current_cells();
444        let address_cells = address_cells.unwrap_or(default_addr);
445        let size_cells = size_cells.unwrap_or(default_size);
446        let interrupt_parent = interrupt_parent.or_else(|| self.current_interrupt_parent());
447
448        // Get parent node and its info from stack
449        let parent = self.current_parent();
450        let (parent_address_cells, parent_size_cells, parent_ranges) = self
451            .node_stack
452            .last()
453            .map(|frame| {
454                (
455                    Some(frame.address_cells),
456                    Some(frame.size_cells),
457                    frame.ranges.clone(),
458                )
459            })
460            .unwrap_or((None, None, None));
461
462        // Calculate ranges for this node if ranges property exists
463        // The ranges will be used by this node's children for address translation
464        let ranges = if let Some(ranges_prop) = ranges_prop {
465            // Get parent's address cells for the ranges property
466            let parent_addr_cells = parent_address_cells.unwrap_or(2);
467
468            Some(FdtRangeSilce::new(
469                address_cells,
470                parent_addr_cells,
471                size_cells,
472                &ranges_prop.data,
473            ))
474        } else {
475            None
476        };
477
478        // Create the new node with parent info from stack
479        let node = NodeBase::new_with_parent_info(
480            name,
481            self.fdt.clone(),
482            self.buffer.remain(),
483            self.level as _,
484            parent,
485            parent_address_cells,
486            parent_size_cells,
487            parent_ranges,
488            interrupt_parent,
489        );
490        // Push this node onto the stack for its children
491        let frame = NodeStackFrame {
492            level: self.level as usize,
493            node: node.clone(),
494            address_cells,
495            size_cells,
496            ranges,
497            interrupt_parent,
498        };
499        self.push_node(frame)?;
500
501        // Return the node immediately
502        Ok(Some(node))
503    }
504
505    /// Handle EndNode token - just pop from stack
506    fn handle_end_node(&mut self) -> Option<NodeBase<'a>> {
507        self.level -= 1;
508
509        // Pop the current level from stack
510        self.pop_to_level(self.level);
511
512        // Don't return anything - nodes are returned on BeginNode
513        None
514    }
515
516    /// Handle Prop token
517    fn handle_prop(&mut self) -> Result<(), FdtError> {
518        let _prop = self.buffer.take_prop(&self.fdt)?;
519        // Property handling is now done in BeginNode scanning
520        Ok(())
521    }
522
523    fn try_next(&mut self) -> Result<Option<NodeBase<'a>>, FdtError> {
524        loop {
525            let token = self.buffer.take_token()?;
526            match token {
527                Token::BeginNode => {
528                    if let Some(finished_node) = self.handle_begin_node()? {
529                        return Ok(Some(finished_node));
530                    }
531                }
532                Token::EndNode => {
533                    if let Some(node) = self.handle_end_node() {
534                        return Ok(Some(node));
535                    }
536                }
537                Token::Prop => {
538                    self.handle_prop()?;
539                }
540                Token::End => {
541                    return Ok(None);
542                }
543                _ => continue,
544            }
545        }
546    }
547}
548
549impl<'a, const MAX_DEPTH: usize> Iterator for NodeIter<'a, MAX_DEPTH> {
550    type Item = Result<Node<'a>, FdtError>;
551
552    fn next(&mut self) -> Option<Self::Item> {
553        if self.has_err {
554            return None;
555        }
556        match self.try_next() {
557            Ok(Some(node)) => Some(Ok(node.into())),
558            Ok(None) => None,
559            Err(e) => {
560                self.has_err = true;
561                Some(Err(e))
562            }
563        }
564    }
565}
566
567struct IterFindNode<'a, const MAX_DEPTH: usize = 16> {
568    itr: NodeIter<'a, MAX_DEPTH>,
569    want: &'a str,
570    want_itr: usize,
571    is_path_last: bool,
572    has_err: bool,
573}
574
575impl<'a, const MAX_DEPTH: usize> IterFindNode<'a, MAX_DEPTH> {
576    fn new(itr: NodeIter<'a, MAX_DEPTH>, want: &'a str) -> Self {
577        IterFindNode {
578            itr,
579            want,
580            want_itr: 0,
581            is_path_last: false,
582            has_err: false,
583        }
584    }
585}
586
587impl<'a, const MAX_DEPTH: usize> Iterator for IterFindNode<'a, MAX_DEPTH> {
588    type Item = Result<Node<'a>, FdtError>;
589
590    fn next(&mut self) -> Option<Self::Item> {
591        let mut out = None;
592        loop {
593            let mut parts = self.want.split("/").filter(|o| !o.is_empty());
594            let mut want_part = "/";
595            for _ in 0..self.want_itr {
596                if let Some(part) = parts.next() {
597                    want_part = part;
598                } else {
599                    self.is_path_last = true;
600                    if let Some(out) = out {
601                        return Some(out);
602                    }
603                }
604            }
605            let node = match self.itr.next()? {
606                Ok(v) => v,
607                Err(e) => {
608                    self.has_err = true;
609                    return Some(Err(e));
610                }
611            };
612
613            let eq = if want_part.contains("@") {
614                node.name().eq(want_part)
615            } else {
616                let name = node.name().split("@").next().unwrap();
617                name.eq(want_part)
618            };
619            if eq {
620                self.want_itr += 1;
621                out = Some(Ok(node));
622            }
623        }
624    }
625}