1use crate::{
6 node::{CellSizes, FdtNode, NodeProperty},
7 parsing::{BigEndianU32, BigEndianU64, CStr, FdtData},
8 Fdt,
9};
10
11#[derive(Debug, Clone, Copy)]
13pub struct Chosen<'b, 'a: 'b> {
14 pub(crate) node: FdtNode<'b, 'a>,
15}
16
17impl<'b, 'a: 'b> Chosen<'b, 'a> {
18 pub fn bootargs(self) -> Option<&'a str> {
20 self.node
21 .properties()
22 .find(|n| n.name == "bootargs")
23 .and_then(|n| core::str::from_utf8(&n.value[..n.value.len() - 1]).ok())
24 }
25
26 pub fn stdout(self) -> Option<FdtNode<'b, 'a>> {
29 self.node
30 .properties()
31 .find(|n| n.name == "stdout-path")
32 .and_then(|n| core::str::from_utf8(&n.value[..n.value.len() - 1]).ok())
33 .and_then(|name| self.node.header.find_node(name))
34 }
35
36 pub fn stdin(self) -> Option<FdtNode<'b, 'a>> {
41 self.node
42 .properties()
43 .find(|n| n.name == "stdin-path")
44 .and_then(|n| core::str::from_utf8(&n.value[..n.value.len() - 1]).ok())
45 .and_then(|name| self.node.header.find_node(name))
46 .or_else(|| self.stdout())
47 }
48}
49
50#[derive(Debug, Clone, Copy)]
52pub struct Root<'b, 'a: 'b> {
53 pub(crate) node: FdtNode<'b, 'a>,
54}
55
56impl<'b, 'a: 'b> Root<'b, 'a> {
57 pub fn cell_sizes(self) -> CellSizes {
59 self.node.cell_sizes()
60 }
61
62 pub fn model(self) -> &'a str {
64 self.node
65 .properties()
66 .find(|p| p.name == "model")
67 .and_then(|p| core::str::from_utf8(p.value).map(|s| s.trim_end_matches('\0')).ok())
68 .unwrap()
69 }
70
71 pub fn compatible(self) -> Compatible<'a> {
73 self.node.compatible().unwrap()
74 }
75
76 pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> + 'b {
78 self.node.properties()
79 }
80
81 pub fn property(self, name: &str) -> Option<NodeProperty<'a>> {
83 self.node.properties().find(|p| p.name == name)
84 }
85}
86
87#[derive(Debug, Clone, Copy)]
89pub struct Aliases<'b, 'a: 'b> {
90 pub(crate) header: &'b Fdt<'a>,
91 pub(crate) node: FdtNode<'b, 'a>,
92}
93
94impl<'b, 'a: 'b> Aliases<'b, 'a> {
95 pub fn resolve(self, alias: &str) -> Option<&'a str> {
97 self.node
98 .properties()
99 .find(|p| p.name == alias)
100 .and_then(|p| core::str::from_utf8(p.value).map(|s| s.trim_end_matches('\0')).ok())
101 }
102
103 pub fn resolve_node(self, alias: &str) -> Option<FdtNode<'b, 'a>> {
105 self.resolve(alias).and_then(|name| self.header.find_node(name))
106 }
107
108 pub fn all(self) -> impl Iterator<Item = (&'a str, &'a str)> + 'b {
110 self.node.properties().filter_map(|p| {
111 Some((p.name, core::str::from_utf8(p.value).map(|s| s.trim_end_matches('\0')).ok()?))
112 })
113 }
114}
115
116#[derive(Debug, Clone, Copy)]
118pub struct Cpu<'b, 'a: 'b> {
119 pub(crate) parent: FdtNode<'b, 'a>,
120 pub(crate) node: FdtNode<'b, 'a>,
121}
122
123impl<'b, 'a: 'b> Cpu<'b, 'a> {
124 pub fn ids(self) -> CpuIds<'a> {
126 let address_cells = self.node.parent_cell_sizes().address_cells;
127
128 CpuIds {
129 reg: self
130 .node
131 .properties()
132 .find(|p| p.name == "reg")
133 .expect("reg is a required property of cpu nodes"),
134 address_cells,
135 }
136 }
137
138 pub fn clock_frequency(self) -> usize {
140 self.node
141 .properties()
142 .find(|p| p.name == "clock-frequency")
143 .or_else(|| self.parent.property("clock-frequency"))
144 .map(|p| match p.value.len() {
145 4 => BigEndianU32::from_bytes(p.value).unwrap().get() as usize,
146 8 => BigEndianU64::from_bytes(p.value).unwrap().get() as usize,
147 _ => unreachable!(),
148 })
149 .expect("clock-frequency is a required property of cpu nodes")
150 }
151
152 pub fn timebase_frequency(self) -> usize {
154 self.node
155 .properties()
156 .find(|p| p.name == "timebase-frequency")
157 .or_else(|| self.parent.property("timebase-frequency"))
158 .map(|p| match p.value.len() {
159 4 => BigEndianU32::from_bytes(p.value).unwrap().get() as usize,
160 8 => BigEndianU64::from_bytes(p.value).unwrap().get() as usize,
161 _ => unreachable!(),
162 })
163 .expect("timebase-frequency is a required property of cpu nodes")
164 }
165
166 pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> + 'b {
168 self.node.properties()
169 }
170
171 pub fn property(self, name: &str) -> Option<NodeProperty<'a>> {
173 self.node.properties().find(|p| p.name == name)
174 }
175}
176
177#[derive(Debug, Clone, Copy)]
180pub struct CpuIds<'a> {
181 pub(crate) reg: NodeProperty<'a>,
182 pub(crate) address_cells: usize,
183}
184
185impl<'a> CpuIds<'a> {
186 pub fn first(self) -> usize {
188 match self.address_cells {
189 1 => BigEndianU32::from_bytes(self.reg.value).unwrap().get() as usize,
190 2 => BigEndianU64::from_bytes(self.reg.value).unwrap().get() as usize,
191 n => panic!("address-cells of size {} is currently not supported", n),
192 }
193 }
194
195 pub fn all(self) -> impl Iterator<Item = usize> + 'a {
197 let mut vals = FdtData::new(self.reg.value);
198 core::iter::from_fn(move || match vals.remaining() {
199 [] => None,
200 _ => Some(match self.address_cells {
201 1 => vals.u32()?.get() as usize,
202 2 => vals.u64()?.get() as usize,
203 n => panic!("address-cells of size {} is currently not supported", n),
204 }),
205 })
206 }
207}
208
209#[derive(Clone, Copy)]
211pub struct Compatible<'a> {
212 pub(crate) data: &'a [u8],
213}
214
215impl<'a> Compatible<'a> {
216 pub fn first(self) -> &'a str {
218 CStr::new(self.data).expect("expected C str").as_str().unwrap()
219 }
220
221 pub fn all(self) -> impl Iterator<Item = &'a str> {
223 let mut data = self.data;
224 core::iter::from_fn(move || {
225 if data.is_empty() {
226 return None;
227 }
228
229 match data.iter().position(|b| *b == b'\0') {
230 Some(idx) => {
231 let ret = Some(core::str::from_utf8(&data[..idx]).ok()?);
232 data = &data[idx + 1..];
233
234 ret
235 }
236 None => {
237 let ret = Some(core::str::from_utf8(data).ok()?);
238 data = &[];
239
240 ret
241 }
242 }
243 })
244 }
245}
246
247#[derive(Debug, Clone, Copy)]
249pub struct Memory<'b, 'a: 'b> {
250 pub(crate) node: FdtNode<'b, 'a>,
251}
252
253impl Memory<'_, '_> {
254 pub fn regions(&self) -> impl Iterator<Item = MemoryRegion> + '_ {
256 self.node.reg().unwrap()
257 }
258
259 pub fn initial_mapped_area(&self) -> Option<MappedArea> {
261 let mut mapped_area = None;
262
263 if let Some(init_mapped_area) = self.node.property("initial_mapped_area") {
264 let mut stream = FdtData::new(init_mapped_area.value);
265 let effective_address = stream.u64().expect("effective address");
266 let physical_address = stream.u64().expect("physical address");
267 let size = stream.u32().expect("size");
268
269 mapped_area = Some(MappedArea {
270 effective_address: effective_address.get() as usize,
271 physical_address: physical_address.get() as usize,
272 size: size.get() as usize,
273 });
274 }
275
276 mapped_area
277 }
278}
279
280#[derive(Debug, Clone, Copy, PartialEq)]
283#[repr(C)]
284pub struct MappedArea {
285 pub effective_address: usize,
287 pub physical_address: usize,
289 pub size: usize,
291}
292
293#[derive(Debug, Clone, Copy, PartialEq)]
295pub struct MemoryRegion {
296 pub starting_address: *const u8,
298 pub size: Option<usize>,
300}