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#[derive(Clone)]
10pub struct Fdt<'a> {
11 pub(crate) header: FdtHeader,
12 pub(crate) data: &'a [u8],
13}
14
15impl<'a> Fdt<'a> {
16 pub fn as_slice(&self) -> &'a [u8] {
18 self.data
19 }
20
21 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 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 pub fn boot_cpuid_phys(&self) -> u32 {
54 self.header.boot_cpuid_phys.get()
55 }
56
57 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 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 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}