1mod ranges;
4mod reg;
5
6use core::ffi::CStr;
7use core::fmt;
8
9use log::error;
10
11pub use ranges::*;
12pub use reg::{RegInfo, RegIter};
13
14use crate::{
15 FdtError, Phandle, Status, Token,
16 data::{Bytes, Reader, StrIter, U32Iter},
17};
18
19#[derive(Clone)]
21pub struct Property<'a> {
22 name: &'a str,
23 data: Bytes<'a>,
24}
25
26impl<'a> Property<'a> {
27 pub fn new(name: &'a str, data: Bytes<'a>) -> Self {
28 Self { name, data }
29 }
30
31 pub fn name(&self) -> &'a str {
32 self.name
33 }
34
35 pub fn data(&self) -> Bytes<'a> {
36 self.data.clone()
37 }
38
39 pub fn is_empty(&self) -> bool {
40 self.data.is_empty()
41 }
42
43 pub fn len(&self) -> usize {
44 self.data.len()
45 }
46
47 pub fn as_u32_iter(&self) -> U32Iter<'a> {
49 self.data.as_u32_iter()
50 }
51
52 pub fn as_str_iter(&self) -> StrIter<'a> {
54 self.data.as_str_iter()
55 }
56
57 pub fn as_slice(&self) -> &[u8] {
59 self.data.as_slice()
60 }
61
62 pub fn as_u64(&self) -> Option<u64> {
64 let mut iter = self.as_u32_iter();
65 let high = iter.next()? as u64;
66 let low = iter.next()? as u64;
67 if iter.next().is_some() {
68 return None;
69 }
70 Some((high << 32) | low)
71 }
72
73 pub fn as_u32(&self) -> Option<u32> {
75 let mut iter = self.as_u32_iter();
76 let value = iter.next()?;
77 if iter.next().is_some() {
78 return None;
79 }
80 Some(value)
81 }
82
83 pub fn as_str(&self) -> Option<&'a str> {
85 let bytes = self.data.as_slice();
86 let cstr = CStr::from_bytes_until_nul(bytes).ok()?;
87 cstr.to_str().ok()
88 }
89
90 pub fn as_address_cells(&self) -> Option<u8> {
92 if self.name == "#address-cells" {
93 self.as_u32().map(|v| v as u8)
94 } else {
95 None
96 }
97 }
98
99 pub fn as_size_cells(&self) -> Option<u8> {
101 if self.name == "#size-cells" {
102 self.as_u32().map(|v| v as u8)
103 } else {
104 None
105 }
106 }
107
108 pub fn as_interrupt_cells(&self) -> Option<u8> {
110 if self.name == "#interrupt-cells" {
111 self.as_u32().map(|v| v as u8)
112 } else {
113 None
114 }
115 }
116
117 pub fn as_status(&self) -> Option<Status> {
119 let v = self.as_str()?;
120 if self.name == "status" {
121 match v {
122 "okay" | "ok" => Some(Status::Okay),
123 "disabled" => Some(Status::Disabled),
124 _ => None,
125 }
126 } else {
127 None
128 }
129 }
130
131 pub fn as_phandle(&self) -> Option<Phandle> {
133 if self.name == "phandle" {
134 self.as_u32().map(Phandle::from)
135 } else {
136 None
137 }
138 }
139
140 pub fn as_device_type(&self) -> Option<&'a str> {
142 if self.name == "device_type" {
143 self.as_str()
144 } else {
145 None
146 }
147 }
148
149 pub fn as_interrupt_parent(&self) -> Option<Phandle> {
151 if self.name == "interrupt-parent" {
152 self.as_u32().map(Phandle::from)
153 } else {
154 None
155 }
156 }
157
158 pub fn as_clock_names(&self) -> Option<StrIter<'a>> {
160 if self.name == "clock-names" {
161 Some(self.as_str_iter())
162 } else {
163 None
164 }
165 }
166
167 pub fn as_compatible(&self) -> Option<StrIter<'a>> {
169 if self.name == "compatible" {
170 Some(self.as_str_iter())
171 } else {
172 None
173 }
174 }
175
176 pub fn is_dma_coherent(&self) -> bool {
178 self.name == "dma-coherent" && self.data.is_empty()
179 }
180}
181
182impl fmt::Display for Property<'_> {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 if self.is_empty() {
185 write!(f, "{}", self.name())
186 } else if let Some(v) = self.as_address_cells() {
187 write!(f, "#address-cells = <{:#x}>", v)
188 } else if let Some(v) = self.as_size_cells() {
189 write!(f, "#size-cells = <{:#x}>", v)
190 } else if let Some(v) = self.as_interrupt_cells() {
191 write!(f, "#interrupt-cells = <{:#x}>", v)
192 } else if self.name() == "reg" {
193 write!(f, "reg = ")?;
196 format_bytes(f, &self.data())
197 } else if let Some(s) = self.as_status() {
198 write!(f, "status = \"{:?}\"", s)
199 } else if let Some(p) = self.as_phandle() {
200 write!(f, "phandle = {}", p)
201 } else if let Some(p) = self.as_interrupt_parent() {
202 write!(f, "interrupt-parent = {}", p)
203 } else if let Some(s) = self.as_device_type() {
204 write!(f, "device_type = \"{}\"", s)
205 } else if let Some(iter) = self.as_compatible() {
206 write!(f, "compatible = ")?;
207 let mut first = true;
208 for s in iter.clone() {
209 if !first {
210 write!(f, ", ")?;
211 }
212 write!(f, "\"{}\"", s)?;
213 first = false;
214 }
215 Ok(())
216 } else if let Some(iter) = self.as_clock_names() {
217 write!(f, "clock-names = ")?;
218 let mut first = true;
219 for s in iter.clone() {
220 if !first {
221 write!(f, ", ")?;
222 }
223 write!(f, "\"{}\"", s)?;
224 first = false;
225 }
226 Ok(())
227 } else if self.is_dma_coherent() {
228 write!(f, "dma-coherent")
229 } else if let Some(s) = self.as_str() {
230 if self.data().iter().filter(|&&b| b == 0).count() > 1 {
232 write!(f, "{} = ", self.name())?;
233 let mut first = true;
234 for s in self.as_str_iter() {
235 if !first {
236 write!(f, ", ")?;
237 }
238 write!(f, "\"{}\"", s)?;
239 first = false;
240 }
241 Ok(())
242 } else {
243 write!(f, "{} = \"{}\"", self.name(), s)
244 }
245 } else if self.len() == 4 {
246 let v = u32::from_be_bytes(self.data().as_slice().try_into().unwrap());
248 write!(f, "{} = <{:#x}>", self.name(), v)
249 } else {
250 write!(f, "{} = ", self.name())?;
252 format_bytes(f, &self.data())
253 }
254 }
255}
256
257fn format_bytes(f: &mut fmt::Formatter<'_>, data: &[u8]) -> fmt::Result {
259 if data.len().is_multiple_of(4) {
260 write!(f, "<")?;
262 let mut first = true;
263 for chunk in data.chunks(4) {
264 if !first {
265 write!(f, " ")?;
266 }
267 let v = u32::from_be_bytes(chunk.try_into().unwrap());
268 write!(f, "{:#x}", v)?;
269 first = false;
270 }
271 write!(f, ">")
272 } else {
273 write!(f, "[")?;
275 for (i, b) in data.iter().enumerate() {
276 if i > 0 {
277 write!(f, " ")?;
278 }
279 write!(f, "{:02x}", b)?;
280 }
281 write!(f, "]")
282 }
283}
284
285pub struct PropIter<'a> {
287 reader: Reader<'a>,
288 strings: Bytes<'a>,
289 finished: bool,
290}
291
292impl<'a> PropIter<'a> {
293 pub(crate) fn new(reader: Reader<'a>, strings: Bytes<'a>) -> Self {
294 Self {
295 reader,
296 strings,
297
298 finished: false,
299 }
300 }
301
302 fn handle_error(&mut self, err: FdtError) {
304 error!("Property parse error: {}", err);
305 self.finished = true;
306 }
307
308 fn read_prop_name(&self, nameoff: u32) -> Result<&'a str, FdtError> {
310 if nameoff as usize >= self.strings.len() {
311 return Err(FdtError::BufferTooSmall {
312 pos: nameoff as usize,
313 });
314 }
315 let bytes = self.strings.slice(nameoff as usize..self.strings.len());
316 let cstr = CStr::from_bytes_until_nul(bytes.as_slice())?;
317 Ok(cstr.to_str()?)
318 }
319
320 fn align4(&mut self) {
321 let pos = self.reader.position();
322 let aligned = (pos + 3) & !3;
323 let skip = aligned - pos;
324 if skip > 0 {
325 let _ = self.reader.read_bytes(skip);
326 }
327 }
328}
329
330impl<'a> Iterator for PropIter<'a> {
331 type Item = Property<'a>;
332
333 fn next(&mut self) -> Option<Self::Item> {
334 if self.finished {
335 return None;
336 }
337
338 loop {
339 let token = match self.reader.read_token() {
340 Ok(t) => t,
341 Err(e) => {
342 self.handle_error(e);
343 return None;
344 }
345 };
346
347 match token {
348 Token::Prop => {
349 let len = match self.reader.read_u32() {
351 Some(b) => b,
352 None => {
353 self.handle_error(FdtError::BufferTooSmall {
354 pos: self.reader.position(),
355 });
356 return None;
357 }
358 };
359
360 let nameoff = match self.reader.read_u32() {
362 Some(b) => b,
363 None => {
364 self.handle_error(FdtError::BufferTooSmall {
365 pos: self.reader.position(),
366 });
367 return None;
368 }
369 };
370
371 let prop_data = if len > 0 {
373 match self.reader.read_bytes(len as _) {
374 Some(b) => b,
375 None => {
376 self.handle_error(FdtError::BufferTooSmall {
377 pos: self.reader.position(),
378 });
379 return None;
380 }
381 }
382 } else {
383 Bytes::new(&[])
384 };
385
386 let name = match self.read_prop_name(nameoff) {
388 Ok(n) => n,
389 Err(e) => {
390 self.handle_error(e);
391 return None;
392 }
393 };
394
395 self.align4();
397
398 return Some(Property::new(name, prop_data));
399 }
400 Token::BeginNode | Token::EndNode | Token::End => {
401 self.reader.backtrack(4);
403 self.finished = true;
404 return None;
405 }
406 Token::Nop => {
407 continue;
409 }
410 Token::Data(_) => {
411 self.handle_error(FdtError::BufferTooSmall {
413 pos: self.reader.position(),
414 });
415 return None;
416 }
417 }
418 }
419 }
420}