microsoft/openvmm

Public

mirrored fromhttps://github.com/microsoft/openvmmAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
e6c778cbebacf3a70be1d39295b4f090134c4091

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

support/fdt/src/parser.rs

967lines · modecode

1// Copyright (C) Microsoft Corporation. All rights reserved.
2
3//! Code to parse a Flattened DeviceTree binary blob.
4
5use super::spec;
6use super::spec::U32b;
7use super::spec::U64b;
8use core::fmt::Display;
9use core::mem::size_of;
10use zerocopy::FromBytes;
11use zerocopy::Ref;
12use zerocopy_helpers::FromBytesExt;
13
14/// Errors returned when parsing a FDT.
15#[derive(Debug)]
16pub struct Error<'a>(ErrorKind<'a>);
17
18impl<'a> Display for Error<'a> {
19 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
20 f.write_fmt(format_args!("{}", self.0))
21 }
22}
23
24// TODO: Once core::error::Error is stablized, we can remove this feature gate.
25#[cfg(feature = "std")]
26impl<'a> std::error::Error for Error<'a> {}
27
28/// Types of errors when parsing a FDT.
29#[derive(Debug)]
30enum ErrorKind<'a> {
31 /// Buffer is not aligned to u32
32 BufferAlignment,
33 /// Buffer too small for fixed header
34 NoHeader,
35 /// Fixed header magic invalid
36 HeaderMagic,
37 /// Total size described in the fixed header is greater than buffer provided
38 HeaderTotalSize,
39 /// Header version is invalid
40 HeaderVersion,
41 /// Structure block not contained within buffer
42 StructureBlock,
43 /// Structure block not aligned to u32
44 StructureBlockAlignment,
45 /// Memory reservation block not contained within buffer
46 MemoryReservationBlock,
47 /// Memory reservation block did not end with an empty entry
48 MemoryReservationBlockEnd,
49 /// Strings block not contained within buffer
50 StringsBlock,
51 /// No root node present
52 RootNode,
53 /// More than one node at the root
54 MultipleRootNodes,
55 /// Unable to parse FDT token when parsing nodes
56 NodeToken(ParseTokenError),
57 /// Unexpected token when parsing begin node
58 NodeBegin(u32),
59 /// Unexpected token when parsing node properties
60 NodeProp(u32),
61 /// Unexpected token when parsing children nodes
62 NodeChildren(u32),
63 /// Property data buffer len is not a multiple of requested type size
64 PropertyDataTypeBuffer {
65 node_name: &'a str,
66 prop_name: &'a str,
67 },
68 /// Property requested at offset is larger than data buffer
69 PropertyOffset {
70 node_name: &'a str,
71 prop_name: &'a str,
72 },
73 /// Property data is not a a valid string
74 PropertyStr {
75 node_name: &'a str,
76 error: StringError,
77 },
78 /// Unable to parse FDT token when parsing properties
79 PropertyTokenParse {
80 node_name: &'a str,
81 error: ParseTokenError,
82 },
83 /// Unexpected FDT token when parsing properties
84 PropertyToken { node_name: &'a str, token: u32 },
85 /// Property name string is not a valid string
86 PropertyNameStr {
87 node_name: &'a str,
88 error: StringError,
89 },
90 /// FDT end token not present at end of structure block
91 FdtEnd,
92}
93
94impl<'a> Display for ErrorKind<'a> {
95 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
96 match self {
97 ErrorKind::BufferAlignment => f.write_str("Buffer is not aligned to u32"),
98 ErrorKind::NoHeader => f.write_str("Buffer too small for fixed FDT header"),
99 ErrorKind::HeaderMagic => f.write_str("FDT header magic field invalid"),
100 ErrorKind::HeaderTotalSize => {
101 f.write_str("FDT header total size greater than provided buffer")
102 }
103 ErrorKind::HeaderVersion => f.write_str("FDT header version invalid"),
104 ErrorKind::StructureBlock => f.write_str("Structure block not contained within buffer"),
105 ErrorKind::StructureBlockAlignment => {
106 f.write_str("Structure block offset is not aligned to u32")
107 }
108 ErrorKind::MemoryReservationBlock => {
109 f.write_str("Memory reservation block not contained within buffer")
110 }
111 ErrorKind::MemoryReservationBlockEnd => {
112 f.write_str("Memory reservation block did not end with an empty entry")
113 }
114 ErrorKind::StringsBlock => f.write_str("Strings block not contained within buffer"),
115 ErrorKind::RootNode => f.write_str("No root node present"),
116 ErrorKind::MultipleRootNodes => f.write_str("More than one node at the root"),
117 ErrorKind::NodeToken(e) => f.write_fmt(format_args!(
118 "Unable to parse FDT token when parsing nodes {}",
119 e
120 )),
121 ErrorKind::NodeBegin(token) => f.write_fmt(format_args!(
122 "Unexpected token when parsing begin node {}",
123 token
124 )),
125 ErrorKind::NodeProp(token) => f.write_fmt(format_args!(
126 "Unexpected token when parsing node properties {}",
127 token
128 )),
129 ErrorKind::NodeChildren(token) => f.write_fmt(format_args!(
130 "Unexpected token when parsing children nodes {}",
131 token
132 )),
133 ErrorKind::PropertyDataTypeBuffer { node_name, prop_name } => f.write_fmt(format_args!(
134 "Property {prop_name} data buffer len is not multiple of type size for node {node_name}"
135 )),
136 ErrorKind::PropertyOffset { node_name, prop_name } => f.write_fmt(format_args!(
137 "Property {prop_name} requested at offset is larger than data buffer for node {node_name}"
138 )),
139 ErrorKind::PropertyStr { node_name, error } => f.write_fmt(format_args!(
140 "Property data is not a a valid string for node {node_name}: {error}"
141 )),
142 ErrorKind::PropertyTokenParse { node_name, error } => f.write_fmt(format_args!(
143 "Unable to parse FDT token when parsing properties for node {node_name}: {error}",
144 )),
145 ErrorKind::PropertyToken { node_name, token } => f.write_fmt(format_args!(
146 "Unexpected FDT token when parsing properties for node {node_name}: {}",
147 token
148 )),
149 ErrorKind::PropertyNameStr { node_name, error } => f.write_fmt(format_args!(
150 "Property name string is not a valid string for node {node_name}: {error}",
151 )),
152 ErrorKind::FdtEnd => f.write_str("FDT end token not present at end of structure block"),
153 }
154 }
155}
156
157/// A parser used to parse a FDT.
158pub struct Parser<'a> {
159 /// The total size used by the dt.
160 pub total_size: usize,
161 /// The strings block.
162 strings_block: &'a [u8],
163 /// The structure block.
164 structure_block: &'a [u8],
165 /// The bsp reg field
166 pub boot_cpuid_phys: u32,
167 /// The memory reservations blocks without the final empty entry.
168 memory_reservations: &'a [u8],
169}
170
171impl<'a> Parser<'a> {
172 /// Read just the `totalsize` field of a FDT header. This is useful when
173 /// attempting to determine the overall size of a device tree.
174 pub fn read_total_size(buf: &[u8]) -> Result<usize, Error<'a>> {
175 let header = spec::Header::read_from_prefix(buf).ok_or(Error(ErrorKind::NoHeader))?;
176
177 if u32::from(header.magic) != spec::MAGIC {
178 Err(Error(ErrorKind::HeaderMagic))
179 } else {
180 Ok(u32::from(header.totalsize) as usize)
181 }
182 }
183
184 /// Create a new instance of a FDT parser.
185 pub fn new(buf: &'a [u8]) -> Result<Self, Error<'a>> {
186 if buf.as_ptr() as usize % size_of::<u32>() != 0 {
187 return Err(Error(ErrorKind::BufferAlignment));
188 }
189
190 let header = spec::Header::read_from_prefix(buf).ok_or(Error(ErrorKind::NoHeader))?;
191
192 if u32::from(header.magic) != spec::MAGIC {
193 return Err(Error(ErrorKind::HeaderMagic));
194 }
195
196 // Validate total size within buf.
197 let total_size = u32::from(header.totalsize) as usize;
198 if total_size > buf.len() {
199 return Err(Error(ErrorKind::HeaderTotalSize));
200 }
201
202 if u32::from(header.version) < spec::CURRENT_VERSION
203 || u32::from(header.last_comp_version) > spec::COMPAT_VERSION
204 {
205 return Err(Error(ErrorKind::HeaderVersion));
206 }
207
208 // Validate the mem_rsvmap region ends with an empty entry. Currently
209 // the parser does not make these values accessible.
210 let mem_rsvmap_offset = u32::from(header.off_mem_rsvmap) as usize;
211 let mut memory_reservations_len = 0;
212 let mut mem_rsvmap = buf
213 .get(mem_rsvmap_offset..)
214 .ok_or(Error(ErrorKind::MemoryReservationBlock))?;
215 loop {
216 let (entry, rest) = spec::ReserveEntry::read_from_prefix_split(mem_rsvmap)
217 .ok_or(Error(ErrorKind::MemoryReservationBlockEnd))?;
218
219 if u64::from(entry.address) == 0 && u64::from(entry.size) == 0 {
220 break;
221 }
222
223 mem_rsvmap = rest;
224 memory_reservations_len += size_of::<spec::ReserveEntry>();
225 }
226
227 let memory_reservations = buf
228 .get(mem_rsvmap_offset..(mem_rsvmap_offset + memory_reservations_len))
229 .ok_or(Error(ErrorKind::MemoryReservationBlock))?;
230
231 let struct_offset = u32::from(header.off_dt_struct) as usize;
232 let struct_len = u32::from(header.size_dt_struct) as usize;
233
234 if struct_offset % size_of::<u32>() != 0 {
235 return Err(Error(ErrorKind::StructureBlockAlignment));
236 }
237
238 let structure_block = buf
239 .get(struct_offset..(struct_offset + struct_len))
240 .ok_or(Error(ErrorKind::StructureBlock))?;
241
242 // FDT_END must be the last token in the structure block. Ignore it once
243 // checked.
244 let structure_block = structure_block
245 .strip_suffix(&spec::END.to_be_bytes())
246 .ok_or(Error(ErrorKind::FdtEnd))?;
247
248 let strings_offset = u32::from(header.off_dt_strings) as usize;
249 let strings_len = u32::from(header.size_dt_strings) as usize;
250 let strings_block = buf
251 .get(strings_offset..(strings_offset + strings_len))
252 .ok_or(Error(ErrorKind::StringsBlock))?;
253
254 Ok(Self {
255 total_size,
256 strings_block,
257 structure_block,
258 memory_reservations,
259 boot_cpuid_phys: header.boot_cpuid_phys.into(),
260 })
261 }
262
263 /// Returns the root node of this FDT.
264 pub fn root<'b>(&'b self) -> Result<Node<'a>, Error<'a>> {
265 let mut iter = NodeIter {
266 strings_block: self.strings_block,
267 nodes: self.structure_block,
268 };
269
270 let root = iter.next().ok_or(Error(ErrorKind::RootNode))??;
271
272 if iter.next().is_some() {
273 Err(Error(ErrorKind::MultipleRootNodes))
274 } else {
275 Ok(root)
276 }
277 }
278
279 /// Returns an iterator to parse through memory reservations.
280 pub fn memory_reservations(&self) -> MemoryReserveIter<'a> {
281 MemoryReserveIter {
282 memory_reservations: self.memory_reservations,
283 }
284 }
285}
286
287/// Get a string from the strings block at the given offset.
288fn string_from_offset(strings_block: &[u8], offset: U32b) -> Result<&str, StringError> {
289 let offset = u32::from(offset) as usize;
290
291 extract_str_from_bytes(strings_block.get(offset..).ok_or(StringError::Offset)?)
292}
293
294/// An iterator to parse through FDT nodes.
295pub struct NodeIter<'a> {
296 strings_block: &'a [u8],
297 nodes: &'a [u8],
298}
299
300enum ParsedToken<'a> {
301 BeginNode { name: &'a str },
302 Property { name_offset: U32b, data: &'a [u8] },
303 EndNode,
304 Nop,
305 End,
306}
307
308impl ParsedToken<'_> {
309 fn raw(&self) -> u32 {
310 match self {
311 ParsedToken::BeginNode { .. } => spec::BEGIN_NODE,
312 ParsedToken::Property { .. } => spec::PROP,
313 ParsedToken::EndNode => spec::END_NODE,
314 ParsedToken::Nop => spec::NOP,
315 ParsedToken::End => spec::END,
316 }
317 }
318}
319
320/// Errors returned when parsing FDT tokens.
321#[derive(Debug)]
322enum ParseTokenError {
323 /// Unknown token
324 Unknown(u32),
325 /// Buf too small
326 BufLen,
327 /// Buf too small for prop header
328 PropHeader,
329 /// Buf too small for prop data described in prop header
330 PropData,
331 /// Begin node name is not valid
332 BeginName(StringError),
333 /// Buf too small for begin node name alignment
334 BeginNameAlignment,
335}
336
337impl Display for ParseTokenError {
338 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
339 match self {
340 ParseTokenError::Unknown(token) => {
341 f.write_fmt(format_args!("Unknown FDT token {}", token))
342 }
343 ParseTokenError::BufLen => f.write_str("Buffer too small to read token"),
344 ParseTokenError::PropHeader => f.write_str("Buffer too small to read property header"),
345 ParseTokenError::PropData => {
346 f.write_str("Buffer too small to read property data encoded in property header")
347 }
348 ParseTokenError::BeginName(e) => {
349 f.write_fmt(format_args!("Node name is not valid {}", e))
350 }
351 ParseTokenError::BeginNameAlignment => {
352 f.write_str("Buffer is too small for begin node name alignment")
353 }
354 }
355 }
356}
357
358/// Read to the next token from `buf`, returning `(token, remaining_buffer)`.
359fn read_token(buf: &[u8]) -> Result<(ParsedToken<'_>, &[u8]), ParseTokenError> {
360 let (token, rest) = U32b::read_from_prefix_split(buf).ok_or(ParseTokenError::BufLen)?;
361 let token = u32::from(token);
362 match token {
363 spec::BEGIN_NODE => {
364 // Extract the node's name.
365 let name = extract_str_from_bytes(rest).map_err(ParseTokenError::BeginName)?;
366
367 // The string extracted does not contain the null terminator. Add
368 // the length and align up the total size.
369 let aligned_str_len = ((name.len() + 1) + 4 - 1) & !(4 - 1);
370
371 // Attempt to extract the remainder of the slice, not including the
372 // aligned padding bytes.
373 let rest = rest
374 .get(aligned_str_len..)
375 .ok_or(ParseTokenError::BeginNameAlignment)?;
376
377 Ok((ParsedToken::BeginNode { name }, rest))
378 }
379 spec::PROP => {
380 // Read the property header
381 let (header, rest) = spec::PropHeader::read_from_prefix_split(rest)
382 .ok_or(ParseTokenError::PropHeader)?;
383 let len = u32::from(header.len) as usize;
384 let align_up_len = (len + 4 - 1) & !(4 - 1);
385
386 if align_up_len > rest.len() {
387 return Err(ParseTokenError::PropData);
388 }
389
390 // Only return the non-aligned data buf
391 let data = &rest[..len];
392 let (_, rest) = rest.split_at(align_up_len);
393
394 Ok((
395 ParsedToken::Property {
396 name_offset: header.nameoff,
397 data,
398 },
399 rest,
400 ))
401 }
402 spec::END_NODE => Ok((ParsedToken::EndNode, rest)),
403 spec::NOP => Ok((ParsedToken::Nop, rest)),
404 spec::END => Ok((ParsedToken::End, rest)),
405 _ => Err(ParseTokenError::Unknown(token)),
406 }
407}
408
409impl<'a> NodeIter<'a> {
410 fn parse(&mut self) -> Result<Option<Node<'a>>, ErrorKind<'a>> {
411 while !self.nodes.is_empty() {
412 // Parse the next token.
413 let (token, rest) = read_token(self.nodes).map_err(ErrorKind::NodeToken)?;
414 debug_assert!(rest.len() % size_of::<U32b>() == 0);
415
416 let name = match token {
417 ParsedToken::Nop => {
418 self.nodes = rest;
419 continue;
420 }
421 ParsedToken::BeginNode { name } => name,
422 _ => return Err(ErrorKind::NodeBegin(token.raw())),
423 };
424
425 self.nodes = rest;
426
427 // Find if there is a properties section, which comes before children.
428 let mut prop = self.nodes;
429 'prop: loop {
430 let (token, rest) = read_token(prop).map_err(ErrorKind::NodeToken)?;
431 match token {
432 ParsedToken::BeginNode { .. } => {
433 // Begin node means move to parsing children nodes.
434 break 'prop;
435 }
436 ParsedToken::EndNode => {
437 // End node means this node had no properties.
438 break 'prop;
439 }
440 ParsedToken::Property { .. } | ParsedToken::Nop => {}
441 token => return Err(ErrorKind::NodeProp(token.raw())),
442 };
443
444 prop = rest;
445 }
446
447 let (prop, rest) = self.nodes.split_at(self.nodes.len() - prop.len());
448 self.nodes = rest;
449
450 // Discover if there are any children, which are signified
451 // by other BEGIN_NODE tokens.
452 let mut children = self.nodes;
453 let mut begin_node_count = 0;
454 'children: loop {
455 let (token, rest) = read_token(children).map_err(ErrorKind::NodeToken)?;
456 match token {
457 ParsedToken::EndNode => {
458 if begin_node_count == 0 {
459 // End of current node
460 break 'children;
461 } else {
462 // Parsing child node, pop node count
463 begin_node_count -= 1;
464 }
465 }
466 ParsedToken::BeginNode { .. } => {
467 begin_node_count += 1;
468 }
469 ParsedToken::Property { .. } | ParsedToken::Nop => {}
470 token => return Err(ErrorKind::NodeChildren(token.raw())),
471 };
472
473 children = rest;
474 }
475
476 let (children, rest) = self.nodes.split_at(self.nodes.len() - children.len());
477 self.nodes = rest;
478
479 // Consume END_NODE and return the parsed node
480 let (end_node, rest) = read_token(self.nodes).expect("should be end node");
481 assert!(matches!(end_node, ParsedToken::EndNode));
482 self.nodes = rest;
483
484 return Ok(Some(Node {
485 name,
486 strings_block: self.strings_block,
487 properties: prop,
488 children,
489 }));
490 }
491
492 Ok(None)
493 }
494}
495
496impl<'a> Iterator for NodeIter<'a> {
497 type Item = Result<Node<'a>, Error<'a>>;
498
499 fn next(&mut self) -> Option<Self::Item> {
500 self.parse().map_err(Error).transpose()
501 }
502}
503
504/// A parsed FDT node.
505pub struct Node<'a> {
506 /// The name for this node.
507 pub name: &'a str,
508 strings_block: &'a [u8],
509 properties: &'a [u8],
510 children: &'a [u8],
511}
512
513impl<'a> Node<'a> {
514 /// Returns an iterator to parse through children of this node.
515 pub fn children(&self) -> NodeIter<'a> {
516 NodeIter {
517 strings_block: self.strings_block,
518 nodes: self.children,
519 }
520 }
521
522 /// Returns an iterator to parse through properties of this node.
523 pub fn properties(&self) -> PropertyIter<'a> {
524 PropertyIter {
525 node_name: self.name,
526 strings_block: self.strings_block,
527 properties: self.properties,
528 }
529 }
530
531 /// Find a property with a given name.
532 ///
533 /// Returns `Ok(None)` if the property does not exist.
534 ///
535 /// Returns an error if this node's properties are unable to be parsed.
536 ///
537 /// This method is O(n) for the number of properties on this node, as the
538 /// [`Self::properties`] is used to perform a linear search.
539 pub fn find_property(&self, name: &str) -> Result<Option<Property<'a>>, Error<'a>> {
540 for prop in self.properties() {
541 let prop = prop?;
542
543 if name == prop.name {
544 return Ok(Some(prop));
545 }
546 }
547
548 Ok(None)
549 }
550}
551
552/// An iterator for FDT node properties.
553pub struct PropertyIter<'a> {
554 node_name: &'a str,
555 strings_block: &'a [u8],
556 properties: &'a [u8],
557}
558
559impl<'a> PropertyIter<'a> {
560 fn parse(&mut self) -> Result<Option<Property<'a>>, ErrorKind<'a>> {
561 while !self.properties.is_empty() {
562 // Parse the next token.
563 let (token, rest) =
564 read_token(self.properties).map_err(|error| ErrorKind::PropertyTokenParse {
565 node_name: self.node_name,
566 error,
567 })?;
568
569 let (name_off, data, rest) = match token {
570 ParsedToken::Nop => {
571 self.properties = rest;
572 continue;
573 }
574 ParsedToken::Property { name_offset, data } => (name_offset, data, rest),
575 _ => {
576 return Err(ErrorKind::PropertyToken {
577 node_name: self.node_name,
578 token: token.raw(),
579 })
580 }
581 };
582
583 // Read the property name
584 let name = string_from_offset(self.strings_block, name_off).map_err(|error| {
585 ErrorKind::PropertyNameStr {
586 node_name: self.node_name,
587 error,
588 }
589 })?;
590
591 self.properties = rest;
592 return Ok(Some(Property {
593 node_name: self.node_name,
594 name,
595 data,
596 }));
597 }
598
599 Ok(None)
600 }
601}
602
603impl<'a> Iterator for PropertyIter<'a> {
604 type Item = Result<Property<'a>, Error<'a>>;
605
606 fn next(&mut self) -> Option<Self::Item> {
607 self.parse().map_err(Error).transpose()
608 }
609}
610
611/// A parsed FDT node property.
612pub struct Property<'a> {
613 node_name: &'a str,
614 /// The name for this property.
615 pub name: &'a str,
616 /// Raw data for this property.
617 pub data: &'a [u8],
618}
619
620impl<'a> Property<'a> {
621 /// Read a value at a given offset, indexed by `size_of::<T>() * index`.
622 /// T must be BigEndian.
623 fn read_val<T: FromBytes + Copy + zerocopy::Unaligned>(
624 &self,
625 index: usize,
626 ) -> Result<T, Error<'a>> {
627 // self.data must be:
628 // - len must be multiple of size_of(T)
629 // - index must be within the constructed slice of T
630 //
631 // NOTE: The unaligned bound on T is due to the fact that FDT properties
632 // are only guaranteed to sit on a 4 byte alignment boundary. Thus, to
633 // read types that are greater than 4 bytes, we must bound T to accept
634 // unaligned types so LayoutVerified does not apply alignment and read
635 // incorrect values.
636 Ok(*Ref::new_slice_unaligned(self.data)
637 .ok_or(Error(ErrorKind::PropertyDataTypeBuffer {
638 node_name: self.node_name,
639 prop_name: self.name,
640 }))?
641 .into_slice()
642 .get(index)
643 .ok_or(Error(ErrorKind::PropertyOffset {
644 node_name: self.node_name,
645 prop_name: self.name,
646 }))?)
647 }
648
649 /// Read a u32 from this property, at a given u32 index.
650 pub fn read_u32(&self, index: usize) -> Result<u32, Error<'a>> {
651 let val: u32 = self.read_val::<U32b>(index)?.into();
652
653 Ok(val)
654 }
655
656 /// Read a u64 from this property, at a given u64 index.
657 pub fn read_u64(&self, index: usize) -> Result<u64, Error<'a>> {
658 let val: u64 = self.read_val::<U64b>(index)?.into();
659
660 Ok(val)
661 }
662
663 /// Read the data as a `&str`.
664 pub fn read_str(&self) -> Result<&'a str, Error<'a>> {
665 extract_str_from_bytes(self.data).map_err(|error| {
666 Error(ErrorKind::PropertyStr {
667 node_name: self.node_name,
668 error,
669 })
670 })
671 }
672
673 /// Read data as an iterator of u64 values.
674 pub fn as_64_list(&self) -> Result<impl Iterator<Item = u64> + 'a, Error<'a>> {
675 Ok(U64b::slice_from(self.data)
676 .ok_or(Error(ErrorKind::PropertyDataTypeBuffer {
677 node_name: self.node_name,
678 prop_name: self.name,
679 }))?
680 .iter()
681 .map(|v| v.get()))
682 }
683}
684
685/// Errors when reading a string from the FDT.
686#[derive(Debug)]
687enum StringError {
688 /// Invalid string block offset
689 Offset,
690 /// No null terminator found
691 Null,
692 /// String is not utf8
693 Utf8(core::str::Utf8Error),
694}
695
696impl Display for StringError {
697 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
698 match self {
699 StringError::Offset => f.write_str("Invalid string block offset"),
700 StringError::Null => f.write_str("No null terminator found"),
701 StringError::Utf8(e) => f.write_fmt(format_args!("String is not utf8 {}", e)),
702 }
703 }
704}
705
706/// An iterator to parse through memory reservations.
707pub struct MemoryReserveIter<'a> {
708 memory_reservations: &'a [u8],
709}
710
711impl<'a> MemoryReserveIter<'a> {
712 fn parse(&mut self) -> Result<Option<spec::ReserveEntry>, ErrorKind<'a>> {
713 if self.memory_reservations.is_empty() {
714 return Ok(None);
715 }
716
717 let (entry, rest) = spec::ReserveEntry::read_from_prefix_split(self.memory_reservations)
718 .ok_or(ErrorKind::MemoryReservationBlock)?;
719
720 if u64::from(entry.address) == 0 && u64::from(entry.size) == 0 {
721 return Ok(None);
722 }
723
724 self.memory_reservations = rest;
725
726 Ok(Some(entry))
727 }
728}
729
730impl<'a> Iterator for MemoryReserveIter<'a> {
731 type Item = Result<spec::ReserveEntry, Error<'a>>;
732
733 fn next(&mut self) -> Option<Self::Item> {
734 self.parse().map_err(Error).transpose()
735 }
736}
737
738#[cfg(feature = "std")]
739// TODO: Once core::error::Error is stablized, we can remove this feature gate.
740impl std::error::Error for StringError {}
741
742/// Extract a string from bytes treated as a C String, stopping at the first null terminator.
743fn extract_str_from_bytes(bytes: &[u8]) -> Result<&str, StringError> {
744 // Find the null terminator.
745 // TODO: unstable CStr::from_bytes_until_nul would be nice here.
746 let null_index = bytes
747 .iter()
748 .position(|char| *char == 0)
749 .ok_or(StringError::Null)?;
750
751 core::str::from_utf8(&bytes[..null_index]).map_err(StringError::Utf8)
752}
753
754#[cfg(test)]
755mod test {
756 use super::*;
757 use crate::builder::Builder;
758 use crate::builder::BuilderConfig;
759 use crate::builder::StringId;
760 use crate::spec::ReserveEntry;
761 use std::vec;
762
763 #[derive(Debug, Clone, PartialEq, Eq)]
764 enum DtProp {
765 PropA(u64),
766 PropB(Vec<u8>),
767 Reg(u32),
768 SuperAwesomeProp(String),
769 }
770
771 #[derive(Debug, PartialEq, Eq)]
772 struct DtNode {
773 name: String,
774 children: Vec<DtNode>,
775 properties: Vec<DtProp>,
776 }
777
778 #[derive(Debug, PartialEq, Eq)]
779 struct Dt {
780 boot_cpuid_phys: u32,
781 root: DtNode,
782 memory_reservations: Vec<ReserveEntry>,
783 }
784
785 struct PropIds {
786 propa: StringId,
787 propb: StringId,
788 reg: StringId,
789 saprop: StringId,
790 }
791
792 macro_rules! build_fdt_props {
793 ($ids:expr, $node:expr, $builder:expr) => {{
794 let mut new_builder = $builder.start_node(&$node.name).unwrap();
795
796 for prop in &$node.properties {
797 new_builder = match &prop {
798 DtProp::PropA(val) => new_builder.add_u64($ids.propa, *val).unwrap(),
799 DtProp::PropB(val) => new_builder.add_prop_array($ids.propb, &[&val]).unwrap(),
800 DtProp::Reg(val) => new_builder.add_u32($ids.reg, *val).unwrap(),
801 DtProp::SuperAwesomeProp(val) => new_builder.add_str($ids.saprop, val).unwrap(),
802 };
803 }
804
805 new_builder
806 }};
807 }
808
809 impl Dt {
810 fn build_fdt(&self) -> Vec<u8> {
811 let mut buf = vec![0; 4096 * 256];
812 let memory_reservations = vec![ReserveEntry {
813 address: 1024.into(),
814 size: 2048.into(),
815 }];
816 let mut builder = Builder::new(BuilderConfig {
817 blob_buffer: buf.as_mut_slice(),
818 string_table_cap: 1024,
819 memory_reservations: &memory_reservations,
820 })
821 .unwrap();
822
823 let ids = PropIds {
824 propa: builder.add_string("prop-a").unwrap(),
825 propb: builder.add_string("test,prop-b").unwrap(),
826 reg: builder.add_string("reg").unwrap(),
827 saprop: builder.add_string("Awesome,super-prop").unwrap(),
828 };
829
830 // build root
831 let root = &self.root;
832 let mut root_builder = build_fdt_props!(&ids, root, builder);
833
834 // build L1 nodes
835 for child in &root.children {
836 let mut child_builder = build_fdt_props!(&ids, child, root_builder);
837
838 // Build L2 nodes
839 for child_l2 in &child.children {
840 child_builder = build_fdt_props!(&ids, child_l2, child_builder)
841 .end_node()
842 .unwrap();
843
844 assert!(child_l2.children.is_empty());
845 }
846
847 root_builder = child_builder.end_node().unwrap();
848 }
849
850 let builder = root_builder.end_node().unwrap();
851
852 let len = builder.build(self.boot_cpuid_phys).unwrap();
853 buf.truncate(len);
854 buf
855 }
856
857 fn from_fdt(buf: &[u8]) -> Self {
858 let parser = Parser::new(buf).unwrap();
859
860 let parse_props = |parser: &Node<'_>, node: &mut DtNode| {
861 for prop in parser.properties() {
862 let prop = prop.unwrap();
863 let name = prop.name;
864
865 let dt_prop = match name {
866 "prop-a" => DtProp::PropA(prop.read_u64(0).unwrap()),
867 "test,prop-b" => DtProp::PropB(prop.data.into()),
868 "reg" => DtProp::Reg(prop.read_u32(0).unwrap()),
869 "Awesome,super-prop" => {
870 DtProp::SuperAwesomeProp(prop.read_str().unwrap().into())
871 }
872 _ => panic!("unexpected name {}", name),
873 };
874
875 node.properties.push(dt_prop);
876 }
877 };
878
879 let root = parser.root().unwrap();
880 let mut p_root = DtNode {
881 name: root.name.into(),
882 children: vec![],
883 properties: vec![],
884 };
885
886 parse_props(&root, &mut p_root);
887
888 for child in root.children() {
889 let child = child.unwrap();
890
891 let mut p_child = DtNode {
892 name: child.name.into(),
893 children: vec![],
894 properties: vec![],
895 };
896
897 parse_props(&child, &mut p_child);
898
899 for child_l2 in child.children() {
900 let child_l2 = child_l2.unwrap();
901
902 let mut p_child_l2 = DtNode {
903 name: child_l2.name.into(),
904 children: vec![],
905 properties: vec![],
906 };
907
908 parse_props(&child_l2, &mut p_child_l2);
909
910 assert!(child_l2.children().next().is_none());
911
912 p_child.children.push(p_child_l2);
913 }
914
915 p_root.children.push(p_child);
916 }
917
918 let mut memory_reservations = vec![];
919 parser.memory_reservations().for_each(|entry| {
920 memory_reservations.push(entry.unwrap());
921 });
922
923 Dt {
924 boot_cpuid_phys: parser.boot_cpuid_phys,
925 root: p_root,
926 memory_reservations,
927 }
928 }
929 }
930
931 fn cpu_node(num: usize, apic_id: u32) -> DtNode {
932 DtNode {
933 name: format!("cpu@{}", num),
934 properties: vec![DtProp::Reg(apic_id)],
935 children: vec![],
936 }
937 }
938
939 #[test]
940 fn test_simple_dt() {
941 let dt = Dt {
942 boot_cpuid_phys: 0,
943 root: DtNode {
944 name: "".into(),
945 children: vec![DtNode {
946 name: "cpus".into(),
947 children: (0..10).map(|i| cpu_node(i, (i + 10) as u32)).collect(),
948 properties: vec![DtProp::SuperAwesomeProp("super".into())],
949 }],
950 properties: vec![
951 DtProp::PropA(0x123456789abcdef),
952 DtProp::PropB(vec![]),
953 DtProp::Reg(0xabcdef),
954 DtProp::SuperAwesomeProp("this is a string!".into()),
955 ],
956 },
957 memory_reservations: vec![ReserveEntry {
958 address: 1024.into(),
959 size: 2048.into(),
960 }],
961 };
962
963 let fdt = dt.build_fdt();
964 let parsed_dt = Dt::from_fdt(&fdt);
965 assert_eq!(dt, parsed_dt);
966 }
967}
968