1use zerocopy::{BigEndian, FromBytes, Immutable, KnownLayout, U32, U64};
6
7#[derive(FromBytes, Debug, KnownLayout, Immutable)]
11#[repr(C)]
12pub struct Header {
13 pub magic: U32<BigEndian>,
15
16 pub totalsize: U32<BigEndian>,
21
22 pub off_dt_struct: U32<BigEndian>,
24
25 pub off_dt_strings: U32<BigEndian>,
27
28 pub off_mem_rsvmap: U32<BigEndian>,
30
31 pub version: U32<BigEndian>,
33
34 pub last_comp_version: U32<BigEndian>,
37
38 pub boot_cpuid_phys: U32<BigEndian>,
40
41 pub size_dt_strings: U32<BigEndian>,
43
44 pub size_dt_struct: U32<BigEndian>,
46}
47
48#[derive(FromBytes, Debug, KnownLayout, Immutable)]
49#[repr(C)]
50pub struct ReserveEntry {
51 pub address: U64<BigEndian>,
53
54 pub size: U64<BigEndian>,
56}
57
58#[derive(Debug)]
59pub struct Property<'a> {
60 pub name: &'a str,
63
64 pub value: &'a [u8],
66}
67
68#[derive(Debug)]
69pub struct Node<'a> {
70 pub name: &'a str,
71 pub properties: Vec<Property<'a>>,
72 pub children: Vec<Node<'a>>,
73}
74
75impl<'a> Node<'a> {
76 pub(crate) fn new(name: &'a str) -> Self {
77 Node { name, properties: vec![], children: vec![] }
78 }
79
80 pub fn find(&self, prefix: &str) -> Option<&Node<'a>> {
82 if self.name.starts_with(prefix) {
83 return Some(self);
84 }
85
86 for child in &self.children {
87 let found_child = child.find(prefix);
88 if found_child.is_some() {
89 return found_child;
90 }
91 }
92
93 return None;
94 }
95
96 pub fn get_property(&self, name: &str) -> Option<&Property<'a>> {
97 self.properties.iter().find(|p| p.name == name)
98 }
99}
100
101#[derive(Debug)]
102pub struct Devicetree<'a> {
103 pub header: &'a Header,
104 pub reserve_entries: &'a [ReserveEntry],
105 pub root_node: Node<'a>,
106}
107
108#[cfg(test)]
109mod test {
110 use super::*;
111
112 #[test]
113 fn test_node_find() {
114 let child1 = Node { name: "child1", properties: vec![], children: vec![] };
115 let child2 = Node { name: "child2", properties: vec![], children: vec![] };
116 let root = Node { name: "root", properties: vec![], children: vec![child1, child2] };
117
118 assert_eq!(root.find("root").unwrap().name, "root");
119 assert_eq!(root.find("child1").unwrap().name, "child1");
120 assert_eq!(root.find("child2").unwrap().name, "child2");
121 assert!(root.find("nonexistent").is_none());
122 }
123
124 #[test]
125 fn test_node_find_nested() {
126 let grandchild = Node { name: "grandchild", properties: vec![], children: vec![] };
127 let child = Node { name: "child", properties: vec![], children: vec![grandchild] };
128 let root = Node { name: "root", properties: vec![], children: vec![child] };
129
130 assert_eq!(root.find("root").unwrap().name, "root");
131 assert_eq!(root.find("child").unwrap().name, "child");
132 assert_eq!(root.find("grandchild").unwrap().name, "grandchild");
133 assert!(root.find("nonexistent").is_none());
134 }
135
136 #[test]
137 fn test_node_find_duplicate() {
138 let property_value = vec![];
139 let property = Property { name: "p1", value: &property_value };
140 let child1 = Node { name: "child", properties: vec![property], children: vec![] };
141 let child2 = Node { name: "child", properties: vec![], children: vec![] };
142 let root = Node { name: "root", properties: vec![], children: vec![child1, child2] };
143
144 assert_eq!(root.find("child").unwrap().name, "child");
145 assert!(root.find("child").unwrap().get_property("p1").is_some());
146 }
147}