Skip to main content

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