1use core::ops::Deref;
2
3use super::Fdt;
4use crate::{
5 base::NodeIter,
6 data::{Buffer, Raw, U32Iter2D},
7 property::PropIter,
8 FdtError, FdtRangeSilce, FdtReg, Phandle, Property, Status,
9};
10
11mod chosen;
12mod interrupt_controller;
13mod memory;
14
15pub use chosen::*;
16pub use interrupt_controller::*;
17pub use memory::*;
18
19#[derive(Clone)]
20pub struct NodeBase<'a> {
21 name: &'a str,
22 pub(crate) fdt: Fdt<'a>,
23 pub level: usize,
24 pub(crate) raw: Raw<'a>,
25 pub(crate) parent: Option<ParentInfo<'a>>,
26 interrupt_parent: Option<Phandle>,
27}
28
29#[derive(Clone)]
30pub(crate) struct ParentInfo<'a> {
31 pub name: &'a str,
32 pub level: usize,
33 pub raw: Raw<'a>,
34 pub address_cells: Option<u8>,
36 pub size_cells: Option<u8>,
37 pub ranges: Option<FdtRangeSilce<'a>>,
39}
40
41impl<'a> NodeBase<'a> {
42 pub(crate) fn new_with_parent_info(
44 name: &'a str,
45 fdt: Fdt<'a>,
46 raw: Raw<'a>,
47 level: usize,
48 parent: Option<&NodeBase<'a>>,
49 parent_address_cells: Option<u8>,
50 parent_size_cells: Option<u8>,
51 parent_ranges: Option<FdtRangeSilce<'a>>,
52 interrupt_parent: Option<Phandle>,
53 ) -> Self {
54 let name = if name.is_empty() { "/" } else { name };
55 NodeBase {
56 name,
57 fdt,
58 level,
59 parent: parent.map(|p| ParentInfo {
60 name: p.name(),
61 level: p.level(),
62 raw: p.raw(),
63 address_cells: parent_address_cells,
64 size_cells: parent_size_cells,
65 ranges: parent_ranges,
66 }),
67 interrupt_parent,
68 raw,
69 }
70 }
71
72 pub fn parent_name(&self) -> Option<&'a str> {
73 self.parent_fast().map(|p| p.name())
74 }
75
76 pub fn parent(&self) -> Option<Node<'a>> {
77 let parent_info = self.parent.as_ref()?;
78 self.fdt
79 .all_nodes()
80 .flatten()
81 .find(|node| node.name() == parent_info.name && node.level() == parent_info.level)
82 }
83
84 pub(crate) fn parent_fast(&self) -> Option<NodeBase<'a>> {
85 self.parent.as_ref().map(|p| NodeBase {
86 name: p.name,
87 fdt: self.fdt.clone(),
88 level: p.level,
89 raw: p.raw,
90 parent: None,
91 interrupt_parent: None,
92 })
93 }
94
95 pub fn raw(&self) -> Raw<'a> {
96 self.raw
97 }
98
99 pub fn name(&self) -> &'a str {
101 self.name
102 }
103
104 pub fn level(&self) -> usize {
106 self.level
107 }
108
109 pub fn compatibles(&self) -> Result<impl Iterator<Item = &'a str> + 'a, FdtError> {
111 let prop = self.find_property("compatible")?;
112 Ok(prop.str_list())
113 }
114
115 pub fn compatibles_flatten(&self) -> Result<impl Iterator<Item = &'a str> + 'a, FdtError> {
116 self.compatibles()
117 }
118
119 pub fn reg(&self) -> Result<RegIter<'a>, FdtError> {
120 let prop = self.find_property("reg")?;
121
122 let parent_info = self
124 .parent
125 .as_ref()
126 .ok_or(FdtError::NodeNotFound("parent"))?;
127
128 let address_cell = parent_info.address_cells.unwrap_or(2);
130 let size_cell = parent_info.size_cells.unwrap_or(1);
131
132 let ranges = parent_info.ranges.clone();
134
135 Ok(RegIter {
136 size_cell,
137 address_cell,
138 buff: prop.data.buffer(),
139 ranges,
140 })
141 }
142
143 fn is_interrupt_controller(&self) -> bool {
144 self.find_property("#interrupt-controller").is_ok()
145 }
146
147 pub fn is_root(&self) -> bool {
149 self.level == 0
150 }
151
152 pub fn debug_info(&self) -> NodeDebugInfo<'a> {
154 NodeDebugInfo {
155 name: self.name(),
156 level: self.level,
157 pos: self.raw.pos(),
158 }
159 }
160
161 pub fn properties(&self) -> impl Iterator<Item = Result<Property<'a>, FdtError>> + '_ {
162 let reader = self.raw.buffer();
163 PropIter::new(self.fdt.clone(), reader)
164 }
165
166 pub fn find_property(&self, name: &str) -> Result<Property<'a>, FdtError> {
167 for prop in self.properties() {
168 let prop = prop?;
169 if prop.name.eq(name) {
170 return Ok(prop);
171 }
172 }
173 Err(FdtError::NotFound)
174 }
175
176 pub fn phandle(&self) -> Result<Phandle, FdtError> {
177 let prop = self.find_property("phandle")?;
178 Ok(prop.u32()?.into())
179 }
180
181 pub fn interrupt_parent(&self) -> Result<InterruptController<'a>, FdtError> {
183 let phandle = self.interrupt_parent.ok_or(FdtError::NotFound)?;
185
186 let node = self.fdt.get_node_by_phandle(phandle)?;
188 match node {
189 Node::InterruptController(ic) => Ok(ic),
190 _ => Err(FdtError::NodeNotFound("interrupt-parent")),
191 }
192 }
193
194 pub fn get_interrupt_parent_phandle(&self) -> Option<Phandle> {
196 self.interrupt_parent
197 }
198
199 pub fn interrupts(
200 &self,
201 ) -> Result<impl Iterator<Item = impl Iterator<Item = u32> + 'a> + 'a, FdtError> {
202 let prop = self.find_property("interrupts")?;
203 let irq_parent = self.interrupt_parent()?;
204 let cell_size = irq_parent.interrupt_cells()?;
205 let iter = U32Iter2D::new(&prop.data, cell_size);
206
207 Ok(iter)
208 }
209
210 pub fn clock_frequency(&self) -> Result<u32, FdtError> {
211 let prop = self.find_property("clock-frequency")?;
212 Ok(prop.u32()?)
213 }
214
215 pub fn children(&self) -> NodeChildIter<'a> {
216 NodeChildIter {
217 fdt: self.fdt.clone(),
218 parent: self.clone(),
219 all_nodes: None,
220 target_level: 0,
221 found_parent: false,
222 }
223 }
224
225 pub fn status(&self) -> Result<Status, FdtError> {
226 let prop = self.find_property("status")?;
227 let s = prop.str()?;
228
229 if s.contains("disabled") {
230 return Ok(Status::Disabled);
231 }
232
233 if s.contains("okay") {
234 return Ok(Status::Okay);
235 }
236
237 Err(FdtError::NotFound)
238 }
239}
240
241#[derive(Debug)]
243pub struct NodeDebugInfo<'a> {
244 pub name: &'a str,
245 pub level: usize,
246 pub pos: usize,
247}
248
249impl core::fmt::Debug for NodeBase<'_> {
250 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
251 f.debug_struct("Node").field("name", &self.name()).finish()
252 }
253}
254
255pub struct RegIter<'a> {
256 pub(crate) size_cell: u8,
257 pub(crate) address_cell: u8,
258 pub(crate) buff: Buffer<'a>,
259 pub(crate) ranges: Option<FdtRangeSilce<'a>>,
260}
261impl Iterator for RegIter<'_> {
262 type Item = FdtReg;
263
264 fn next(&mut self) -> Option<Self::Item> {
265 let child_bus_address = self.buff.take_by_cell_size(self.address_cell)?;
266
267 let mut address = child_bus_address;
268
269 if let Some(ranges) = &self.ranges {
270 for one in ranges.iter() {
271 let range_child_bus_address = one.child_bus_address().as_u64();
272 let range_parent_bus_address = one.parent_bus_address().as_u64();
273
274 if child_bus_address >= range_child_bus_address
275 && child_bus_address < range_child_bus_address + one.size
276 {
277 address =
278 child_bus_address - range_child_bus_address + range_parent_bus_address;
279 break;
280 }
281 }
282 }
283
284 let size = if self.size_cell > 0 {
285 Some(self.buff.take_by_cell_size(self.size_cell)? as usize)
286 } else {
287 None
288 };
289 Some(FdtReg {
290 address,
291 child_bus_address,
292 size,
293 })
294 }
295}
296
297#[derive(Debug, Clone)]
298pub enum Node<'a> {
299 General(NodeBase<'a>),
300 Chosen(Chosen<'a>),
301 Memory(Memory<'a>),
302 InterruptController(InterruptController<'a>),
303}
304
305impl<'a> Node<'a> {
306 pub fn node(&self) -> &NodeBase<'a> {
307 self.deref()
308 }
309}
310
311impl<'a> From<NodeBase<'a>> for Node<'a> {
312 fn from(node: NodeBase<'a>) -> Self {
313 if node.name() == "chosen" {
314 Node::Chosen(Chosen::new(node))
315 } else if node.name().starts_with("memory@") {
316 Node::Memory(Memory::new(node))
317 } else if node.is_interrupt_controller() {
318 Node::InterruptController(InterruptController::new(node))
319 } else {
320 Node::General(node)
321 }
322 }
323}
324
325impl<'a> Deref for Node<'a> {
326 type Target = NodeBase<'a>;
327
328 fn deref(&self) -> &Self::Target {
329 match self {
330 Node::General(n) => n,
331 Node::Chosen(n) => n,
332 Node::Memory(n) => n,
333 Node::InterruptController(n) => n,
334 }
335 }
336}
337
338pub struct NodeChildIter<'a> {
339 fdt: Fdt<'a>,
340 parent: NodeBase<'a>,
341 all_nodes: Option<NodeIter<'a, 16>>,
342 target_level: usize,
343 found_parent: bool,
344}
345
346impl<'a> Iterator for NodeChildIter<'a> {
347 type Item = Result<Node<'a>, FdtError>;
348
349 fn next(&mut self) -> Option<Self::Item> {
350 if self.all_nodes.is_none() {
352 self.all_nodes = Some(self.fdt.all_nodes());
353 }
354
355 let all_nodes = self.all_nodes.as_mut()?;
356
357 loop {
359 let node = match all_nodes.next()? {
360 Ok(node) => node,
361 Err(e) => return Some(Err(e)),
362 };
363
364 if !self.found_parent {
366 if node.name() == self.parent.name() && node.level() == self.parent.level() {
367 self.found_parent = true;
368 self.target_level = node.level() + 1;
369 }
370 continue;
371 }
372
373 let current_level = node.level();
375
376 if current_level == self.target_level {
379 return Some(Ok(node));
380 }
381
382 if current_level <= self.parent.level() {
384 break;
385 }
386 }
387
388 None
389 }
390}
391
392impl<'a> NodeChildIter<'a> {
393 pub fn new(fdt: Fdt<'a>, parent: NodeBase<'a>) -> Self {
395 NodeChildIter {
396 fdt,
397 parent,
398 all_nodes: None,
399 target_level: 0,
400 found_parent: false,
401 }
402 }
403
404 pub fn parent(&self) -> &NodeBase<'a> {
406 &self.parent
407 }
408
409 pub fn collect_children(self) -> Result<alloc::vec::Vec<Node<'a>>, FdtError> {
411 self.collect()
412 }
413
414 pub fn find_child_by_name(self, name: &str) -> Result<Node<'a>, FdtError> {
416 for child_result in self {
417 let child = child_result?;
418 if child.name() == name {
419 return Ok(child);
420 }
421 }
422 Err(FdtError::NotFound)
423 }
424
425 pub fn find_child_by_compatible(self, compatible: &str) -> Result<Node<'a>, FdtError> {
427 for child_result in self {
428 let child = child_result?;
429 match child.compatibles() {
430 Ok(mut compatibles) => {
431 if compatibles.any(|comp| comp == compatible) {
432 return Ok(child);
433 }
434 }
435 Err(FdtError::NotFound) => {}
436 Err(e) => return Err(e),
437 }
438 }
439 Err(FdtError::NotFound)
440 }
441}
442
443#[cfg(test)]
444mod tests {
445 use super::{Fdt, FdtError};
446
447 #[test]
448 fn test_node_child_iter_basic() {
449 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/bcm2711-rpi-4-b.dtb");
450 let fdt = Fdt::from_bytes(dtb_data).unwrap();
451
452 let root_node = fdt.find_nodes("/").next().unwrap().unwrap();
454
455 let children: Result<alloc::vec::Vec<_>, _> = root_node.children().collect();
457 let children = children.unwrap();
458
459 assert!(!children.is_empty(), "根节点应该有子节点");
461
462 for child in &children {
464 assert_eq!(child.level(), 1, "根节点的直接子节点应该在 level 1");
465 }
466
467 let child_names: alloc::vec::Vec<_> = children.iter().map(|c| c.name()).collect();
469 assert!(child_names.contains(&"chosen"), "应该包含 chosen 节点");
470 assert!(child_names.contains(&"memory@0"), "应该包含 memory@0 节点");
471 }
472
473 #[test]
474 fn test_find_child_by_name() {
475 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/bcm2711-rpi-4-b.dtb");
476 let fdt = Fdt::from_bytes(dtb_data).unwrap();
477
478 let root_node = fdt.find_nodes("/").next().unwrap().unwrap();
480
481 let memory_node = root_node.children().find_child_by_name("memory@0").unwrap();
483
484 assert_eq!(memory_node.name(), "memory@0");
485
486 let nonexistent_err = root_node
488 .children()
489 .find_child_by_name("nonexistent")
490 .unwrap_err();
491 assert!(matches!(nonexistent_err, FdtError::NotFound));
492 }
493
494 #[test]
495 fn test_child_iter_empty() {
496 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/bcm2711-rpi-4-b.dtb");
497 let fdt = Fdt::from_bytes(dtb_data).unwrap();
498
499 let leaf_node = fdt.find_nodes("/chosen").next().unwrap().unwrap();
501
502 let children: Result<alloc::vec::Vec<_>, _> = leaf_node.children().collect();
504 let children = children.unwrap();
505
506 assert!(children.is_empty(), "叶子节点不应该有子节点");
507 }
508
509 #[test]
510 fn test_child_iter_multiple_levels() {
511 let dtb_data = include_bytes!("../../../../dtb-file/src/dtb/bcm2711-rpi-4-b.dtb");
512 let fdt = Fdt::from_bytes(dtb_data).unwrap();
513
514 let reserved_memory = fdt
516 .all_nodes()
517 .find(|node| node.as_ref().is_ok_and(|n| n.name() == "reserved-memory"))
518 .unwrap()
519 .unwrap();
520
521 let children: Result<alloc::vec::Vec<_>, _> = reserved_memory.children().collect();
523 let children = children.unwrap();
524
525 for child in &children {
527 assert_eq!(
528 child.level(),
529 reserved_memory.level() + 1,
530 "子节点的 level 应该比父节点高 1"
531 );
532 }
533 }
534}