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