1mod ranges;
8mod reg;
9
10use core::ffi::CStr;
11use core::fmt;
12
13use log::error;
14
15pub use ranges::*;
16pub use reg::{RegInfo, RegIter};
17
18use crate::{
19 FdtError, Phandle, Status, Token,
20 data::{Bytes, Reader, StrIter, U32_SIZE, U32Iter},
21};
22
23#[derive(Clone)]
29pub struct Property<'a> {
30 name: &'a str,
31 data: Bytes<'a>,
32}
33
34impl<'a> Property<'a> {
35 pub fn new(name: &'a str, data: Bytes<'a>) -> Self {
37 Self { name, data }
38 }
39
40 pub fn name(&self) -> &'a str {
42 self.name
43 }
44
45 pub fn data(&self) -> Bytes<'a> {
47 self.data.clone()
48 }
49
50 pub fn is_empty(&self) -> bool {
52 self.data.is_empty()
53 }
54
55 pub fn len(&self) -> usize {
57 self.data.len()
58 }
59
60 pub fn as_u32_iter(&self) -> U32Iter<'a> {
62 self.data.as_u32_iter()
63 }
64
65 pub fn as_str_iter(&self) -> StrIter<'a> {
69 self.data.as_str_iter()
70 }
71
72 pub fn as_slice(&self) -> &[u8] {
74 self.data.as_slice()
75 }
76
77 pub fn as_u64(&self) -> Option<u64> {
81 let mut iter = self.as_u32_iter();
82 let high = iter.next()? as u64;
83 let low = iter.next()? as u64;
84 if iter.next().is_some() {
85 return None;
86 }
87 Some((high << 32) | low)
88 }
89
90 pub fn as_u32(&self) -> Option<u32> {
94 let mut iter = self.as_u32_iter();
95 let value = iter.next()?;
96 if iter.next().is_some() {
97 return None;
98 }
99 Some(value)
100 }
101
102 pub fn as_str(&self) -> Option<&'a str> {
104 let bytes = self.data.as_slice();
105 let cstr = CStr::from_bytes_until_nul(bytes).ok()?;
106 cstr.to_str().ok()
107 }
108
109 pub fn as_address_cells(&self) -> Option<u8> {
113 if self.name == "#address-cells" {
114 self.as_u32().map(|v| v as u8)
115 } else {
116 None
117 }
118 }
119
120 pub fn as_size_cells(&self) -> Option<u8> {
124 if self.name == "#size-cells" {
125 self.as_u32().map(|v| v as u8)
126 } else {
127 None
128 }
129 }
130
131 pub fn as_interrupt_cells(&self) -> Option<u8> {
135 if self.name == "#interrupt-cells" {
136 self.as_u32().map(|v| v as u8)
137 } else {
138 None
139 }
140 }
141
142 pub fn as_status(&self) -> Option<Status> {
146 let v = self.as_str()?;
147 if self.name == "status" {
148 match v {
149 "okay" | "ok" => Some(Status::Okay),
150 "disabled" => Some(Status::Disabled),
151 _ => None,
152 }
153 } else {
154 None
155 }
156 }
157
158 pub fn as_phandle(&self) -> Option<Phandle> {
162 if self.name == "phandle" {
163 self.as_u32().map(Phandle::from)
164 } else {
165 None
166 }
167 }
168
169 pub fn as_device_type(&self) -> Option<&'a str> {
173 if self.name == "device_type" {
174 self.as_str()
175 } else {
176 None
177 }
178 }
179
180 pub fn as_interrupt_parent(&self) -> Option<Phandle> {
184 if self.name == "interrupt-parent" {
185 self.as_u32().map(Phandle::from)
186 } else {
187 None
188 }
189 }
190
191 pub fn as_clock_names(&self) -> Option<StrIter<'a>> {
195 if self.name == "clock-names" {
196 Some(self.as_str_iter())
197 } else {
198 None
199 }
200 }
201
202 pub fn as_compatible(&self) -> Option<StrIter<'a>> {
206 if self.name == "compatible" {
207 Some(self.as_str_iter())
208 } else {
209 None
210 }
211 }
212
213 pub fn is_dma_coherent(&self) -> bool {
217 self.name == "dma-coherent" && self.data.is_empty()
218 }
219}
220
221impl fmt::Display for Property<'_> {
222 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223 if self.is_empty() {
224 return write!(f, "{}", self.name());
225 }
226
227 if let Some(result) = self.try_format_typed(f) {
229 return result;
230 }
231
232 match self.name() {
234 "reg" => {
235 write!(f, "reg = ")?;
236 format_bytes(f, &self.data())
237 }
238 _ => self.format_generic(f),
239 }
240 }
241}
242
243impl Property<'_> {
244 fn try_format_typed(&self, f: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
247 if let Some(v) = self.as_address_cells() {
248 return Some(write!(f, "#address-cells = <{:#x}>", v));
249 }
250 if let Some(v) = self.as_size_cells() {
251 return Some(write!(f, "#size-cells = <{:#x}>", v));
252 }
253 if let Some(v) = self.as_interrupt_cells() {
254 return Some(write!(f, "#interrupt-cells = <{:#x}>", v));
255 }
256 if let Some(s) = self.as_status() {
257 return Some(write!(f, "status = \"{:?}\"", s));
258 }
259 if let Some(p) = self.as_phandle() {
260 return Some(write!(f, "phandle = {}", p));
261 }
262 if let Some(p) = self.as_interrupt_parent() {
263 return Some(write!(f, "interrupt-parent = {}", p));
264 }
265 if let Some(s) = self.as_device_type() {
266 return Some(write!(f, "device_type = \"{}\"", s));
267 }
268 if let Some(iter) = self.as_compatible() {
269 return Some(format_string_list(f, "compatible", iter));
270 }
271 if let Some(iter) = self.as_clock_names() {
272 return Some(format_string_list(f, "clock-names", iter));
273 }
274 if self.is_dma_coherent() {
275 return Some(write!(f, "dma-coherent"));
276 }
277 None
278 }
279
280 fn format_generic(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282 if self.has_multiple_strings() {
284 return format_string_list(f, self.name(), self.as_str_iter());
285 }
286
287 if let Some(s) = self.as_str() {
289 return write!(f, "{} = \"{}\"", self.name(), s);
290 }
291
292 if self.len() == 4 {
294 let v = u32::from_be_bytes(self.data().as_slice().try_into().unwrap());
295 return write!(f, "{} = <{:#x}>", self.name(), v);
296 }
297
298 write!(f, "{} = ", self.name())?;
300 format_bytes(f, &self.data())
301 }
302
303 fn has_multiple_strings(&self) -> bool {
305 self.data().iter().filter(|&&b| b == 0).count() > 1
306 }
307}
308
309fn format_string_list<'a>(
311 f: &mut fmt::Formatter<'_>,
312 name: &str,
313 iter: impl Iterator<Item = &'a str>,
314) -> fmt::Result {
315 write!(f, "{} = ", name)?;
316 let mut first = true;
317 for s in iter {
318 if !first {
319 write!(f, ", ")?;
320 }
321 write!(f, "\"{}\"", s)?;
322 first = false;
323 }
324 Ok(())
325}
326
327fn format_bytes(f: &mut fmt::Formatter<'_>, data: &[u8]) -> fmt::Result {
329 if data.len().is_multiple_of(4) {
330 write!(f, "<")?;
332 let mut first = true;
333 for chunk in data.chunks(4) {
334 if !first {
335 write!(f, " ")?;
336 }
337 let v = u32::from_be_bytes(chunk.try_into().unwrap());
338 write!(f, "{:#x}", v)?;
339 first = false;
340 }
341 write!(f, ">")
342 } else {
343 write!(f, "[")?;
345 for (i, b) in data.iter().enumerate() {
346 if i > 0 {
347 write!(f, " ")?;
348 }
349 write!(f, "{:02x}", b)?;
350 }
351 write!(f, "]")
352 }
353}
354
355pub struct PropIter<'a> {
369 reader: Reader<'a>,
371 strings: Bytes<'a>,
373 finished: bool,
375}
376
377impl<'a> PropIter<'a> {
378 pub(crate) fn new(reader: Reader<'a>, strings: Bytes<'a>) -> Self {
380 Self {
381 reader,
382 strings,
383
384 finished: false,
385 }
386 }
387
388 fn handle_error(&mut self, err: FdtError) {
390 error!("Property parse error: {}", err);
391 self.finished = true;
392 }
393
394 fn read_prop_name(&self, nameoff: u32) -> Result<&'a str, FdtError> {
396 if nameoff as usize >= self.strings.len() {
397 return Err(FdtError::BufferTooSmall {
398 pos: nameoff as usize,
399 });
400 }
401 let bytes = self.strings.slice(nameoff as usize..self.strings.len());
402 let cstr = CStr::from_bytes_until_nul(bytes.as_slice())?;
403 Ok(cstr.to_str()?)
404 }
405
406 fn align4(&mut self) {
408 let pos = self.reader.position();
409 let aligned = (pos + U32_SIZE - 1) & !(U32_SIZE - 1);
410 let skip = aligned - pos;
411 if skip > 0 {
412 let _ = self.reader.read_bytes(skip);
413 }
414 }
415}
416
417impl<'a> Iterator for PropIter<'a> {
418 type Item = Property<'a>;
419
420 fn next(&mut self) -> Option<Self::Item> {
421 if self.finished {
422 return None;
423 }
424
425 loop {
426 let token = match self.reader.read_token() {
427 Ok(t) => t,
428 Err(e) => {
429 self.handle_error(e);
430 return None;
431 }
432 };
433
434 match token {
435 Token::Prop => {
436 let len = match self.reader.read_u32() {
438 Some(b) => b,
439 None => {
440 self.handle_error(FdtError::BufferTooSmall {
441 pos: self.reader.position(),
442 });
443 return None;
444 }
445 };
446
447 let nameoff = match self.reader.read_u32() {
449 Some(b) => b,
450 None => {
451 self.handle_error(FdtError::BufferTooSmall {
452 pos: self.reader.position(),
453 });
454 return None;
455 }
456 };
457
458 let prop_data = if len > 0 {
460 match self.reader.read_bytes(len as _) {
461 Some(b) => b,
462 None => {
463 self.handle_error(FdtError::BufferTooSmall {
464 pos: self.reader.position(),
465 });
466 return None;
467 }
468 }
469 } else {
470 Bytes::new(&[])
471 };
472
473 let name = match self.read_prop_name(nameoff) {
475 Ok(n) => n,
476 Err(e) => {
477 self.handle_error(e);
478 return None;
479 }
480 };
481
482 self.align4();
484
485 return Some(Property::new(name, prop_data));
486 }
487 Token::BeginNode | Token::EndNode | Token::End => {
488 self.reader.backtrack(U32_SIZE);
490 self.finished = true;
491 return None;
492 }
493 Token::Nop => {
494 continue;
496 }
497 Token::Data(_) => {
498 self.handle_error(FdtError::BufferTooSmall {
500 pos: self.reader.position(),
501 });
502 return None;
503 }
504 }
505 }
506 }
507}