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