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(&'a self) -> impl Iterator<Item = Node<'a>> + 'a {
73        self.find_nodes("/reserved-memory")
74    }
75
76    pub(crate) fn get_str(&'a 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(&'a self) -> impl Iterator<Item = Node<'a>> {
83        self.new_fdt_itr()
84    }
85
86    fn new_fdt_itr(&'a self) -> FdtIter<'a> {
87        let struct_bytes = &self.data[self.header.struct_range()];
88        let reader = FdtReader::new(struct_bytes);
89        FdtIter {
90            fdt: self,
91            current_level: 0,
92            reader,
93            stack: Default::default(),
94            node_reader: None,
95            node_name: "",
96        }
97    }
98
99    pub fn chosen(&'a self) -> Option<Chosen<'a>> {
100        self.find_nodes("/chosen").next().map(Chosen::new)
101    }
102
103    pub fn get_node_by_phandle(&'a self, phandle: Phandle) -> Option<Node<'a>> {
104        self.all_nodes()
105            .find(|x| match x.phandle() {
106                Some(p) => p.eq(&phandle),
107                None => false,
108            })
109            .clone()
110    }
111
112    pub fn get_node_by_name(&'a self, name: &str) -> Option<Node<'a>> {
113        self.all_nodes().find(|x| x.name().eq(name)).clone()
114    }
115
116    pub fn find_compatible(&'a self, with: &'a [&'a str]) -> impl Iterator<Item = Node<'a>> + 'a {
117        let mut all = self.all_nodes();
118
119        iter::from_fn(move || loop {
120            let node = all.next()?;
121            let caps = node.compatibles();
122            for cap in caps {
123                for want in with {
124                    if cap.eq(*want) {
125                        return Some(node);
126                    }
127                }
128            }
129        })
130    }
131
132    /// if path start with '/' then search by path, else search by aliases
133    pub fn find_nodes(&'a self, path: &'a str) -> impl Iterator<Item = Node<'a>> + 'a {
134        let path = if path.starts_with("/") {
135            path
136        } else {
137            self.find_aliase(path).expect("aliase not found")
138        };
139
140        IterFindNode::new(self.new_fdt_itr(), path)
141    }
142
143    pub fn find_aliase(&'a self, name: &str) -> Option<&'a str> {
144        let aliases = self.find_nodes("/aliases").next()?;
145        for prop in aliases.propertys() {
146            if prop.name.eq(name) {
147                return Some(prop.str());
148            }
149        }
150        None
151    }
152
153    pub fn memory(&'a self) -> impl Iterator<Item = Memory<'a>> + 'a {
154        self.find_nodes("/memory").map(Memory::new)
155    }
156}
157
158pub struct FdtIter<'a> {
159    fdt: &'a Fdt<'a>,
160    current_level: usize,
161    reader: FdtReader<'a>,
162    stack: [MetaData<'a>; 12],
163    node_reader: Option<FdtReader<'a>>,
164    node_name: &'a str,
165}
166
167impl<'a> FdtIter<'a> {
168    fn get_meta_parent(&self) -> MetaData<'a> {
169        let mut meta = MetaData::default();
170        let level = match self.level_parent_index() {
171            Some(l) => l,
172            None => return MetaData::default(),
173        } + 1;
174        macro_rules! get_field {
175            ($cell:ident) => {{
176                let mut size = None;
177                for i in (0..level).rev() {
178                    if let Some(cell_size) = &self.stack[i].$cell {
179                        size = Some(cell_size.clone());
180                        break;
181                    }
182                }
183                meta.$cell = size;
184            }};
185        }
186
187        get_field!(address_cells);
188        get_field!(size_cells);
189        get_field!(clock_cells);
190        get_field!(interrupt_cells);
191        get_field!(gpio_cells);
192        get_field!(dma_cells);
193        get_field!(cooling_cells);
194        get_field!(range);
195        get_field!(interrupt_parent);
196
197        meta
198    }
199    fn level_current_index(&self) -> usize {
200        self.current_level - 1
201    }
202    fn level_parent_index(&self) -> Option<usize> {
203        if self.level_current_index() > 0 {
204            Some(self.level_current_index() - 1)
205        } else {
206            None
207        }
208    }
209
210    fn handle_node_begin(&mut self) {
211        self.current_level += 1;
212        let i = self.level_current_index();
213        self.stack[i] = MetaData::default();
214        self.node_name = self.reader.take_unit_name().unwrap();
215        self.node_reader = Some(self.reader.clone());
216    }
217
218    fn finish_node(&mut self) -> Option<Node<'a>> {
219        let reader = self.node_reader.take()?;
220        let level = self.current_level;
221        let meta = self.stack[self.level_current_index()].clone();
222        let meta_parent = self.get_meta_parent();
223
224        let mut node = Node::new(self.fdt, level, self.node_name, reader, meta_parent, meta);
225        let ranges = node.node_ranges();
226        self.stack[self.level_current_index()].range = ranges.clone();
227        let ph = node.node_interrupt_parent();
228        self.stack[self.level_current_index()].interrupt_parent = ph;
229
230        node.meta = self.stack[self.level_current_index()].clone();
231
232        Some(node)
233    }
234}
235
236impl<'a> Iterator for FdtIter<'a> {
237    type Item = Node<'a>;
238
239    fn next(&mut self) -> Option<Self::Item> {
240        loop {
241            let token = self.reader.take_token()?;
242
243            match token {
244                Token::BeginNode => {
245                    let node = self.finish_node();
246                    self.handle_node_begin();
247                    if node.is_some() {
248                        return node;
249                    }
250                }
251                Token::EndNode => {
252                    let node = self.finish_node();
253                    self.current_level -= 1;
254                    if node.is_some() {
255                        return node;
256                    }
257                }
258                Token::Prop => {
259                    let prop = self.reader.take_prop(self.fdt)?;
260                    let index = self.level_current_index();
261                    macro_rules! update_cell {
262                        ($cell:ident) => {
263                            self.stack[index].$cell = Some(prop.u32() as _)
264                        };
265                    }
266                    match prop.name {
267                        "#address-cells" => update_cell!(address_cells),
268                        "#size-cells" => update_cell!(size_cells),
269                        "#clock-cells" => update_cell!(clock_cells),
270                        "#interrupt-cells" => update_cell!(interrupt_cells),
271                        "#gpio-cells" => update_cell!(gpio_cells),
272                        "#dma-cells" => update_cell!(dma_cells),
273                        "#cooling-cells" => update_cell!(cooling_cells),
274                        _ => {}
275                    }
276                }
277                Token::End => {
278                    return self.finish_node();
279                }
280                _ => {}
281            }
282        }
283    }
284}
285
286struct IterFindNode<'a> {
287    itr: FdtIter<'a>,
288    want: &'a str,
289    want_itr: usize,
290    is_path_last: bool,
291}
292
293impl<'a> IterFindNode<'a> {
294    fn new(itr: FdtIter<'a>, want: &'a str) -> Self {
295        IterFindNode {
296            itr,
297            want,
298            want_itr: 0,
299            is_path_last: false,
300        }
301    }
302}
303
304impl<'a> Iterator for IterFindNode<'a> {
305    type Item = Node<'a>;
306
307    fn next(&mut self) -> Option<Self::Item> {
308        let mut out = None;
309        loop {
310            let mut parts = self.want.split("/").filter(|o| !o.is_empty());
311            let mut want_part = "/";
312            for _ in 0..self.want_itr {
313                if let Some(part) = parts.next() {
314                    want_part = part;
315                } else {
316                    self.is_path_last = true;
317                    if let Some(out) = out {
318                        return Some(out);
319                    }
320                }
321            }
322            let node = self.itr.next()?;
323
324            let eq = if want_part.contains("@") {
325                node.name.eq(want_part)
326            } else {
327                let name = node.name.split("@").next().unwrap();
328                name.eq(want_part)
329            };
330            if eq {
331                self.want_itr += 1;
332                out = Some(node);
333            }
334        }
335    }
336}