fdt_parser/
fdt.rs

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/// The reference to the FDT raw data.
9#[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    /// Get the raw data as a byte slice.
18    pub fn as_slice(&self) -> &'a [u8] {
19        self.data
20    }
21
22    /// Create a new FDT from raw data.
23    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    /// Create a new FDT from a pointer.
32    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    /// This field shall contain the physical ID of the system’s boot CPU. It shall be identical to the physical ID given in the
53    /// reg property of that CPU node within the devicetree.
54    pub fn boot_cpuid_phys(&self) -> u32 {
55        self.header.boot_cpuid_phys.get()
56    }
57
58    /// The memory reservation block provides the client program with a list of areas in physical memory which are reserved; that
59    /// is, which shall not be used for general memory allocations. It is used to protect vital data structures from being overwritten
60    /// by the client program.
61    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    /// Reserved memory is specified as a node under the `/reserved-memory` node. The operating system shall exclude reserved
76    /// memory from normal usage. One can create child nodes describing particular reserved (excluded from normal use) memory
77    /// regions. Such memory regions are usually designed for the special usage by various device drivers.
78    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    /// if path start with '/' then search by path, else search by aliases
140    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}