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}