microsoft/openvmm
Publicmirrored fromhttps://github.com/microsoft/openvmmAvailable
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 | |
| 5 | use super::spec; |
| 6 | use super::spec::U32b; |
| 7 | use super::spec::U64b; |
| 8 | use core::fmt::Display; |
| 9 | use core::mem::size_of; |
| 10 | use zerocopy::FromBytes; |
| 11 | use zerocopy::Ref; |
| 12 | use zerocopy_helpers::FromBytesExt; |
| 13 | |
| 14 | /// Errors returned when parsing a FDT. |
| 15 | #[derive(Debug)] |
| 16 | pub struct Error<'a>(ErrorKind<'a>); |
| 17 | |
| 18 | impl<'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")] |
| 26 | impl<'a> std::error::Error for Error<'a> {} |
| 27 | |
| 28 | /// Types of errors when parsing a FDT. |
| 29 | #[derive(Debug)] |
| 30 | enum 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 | |
| 94 | impl<'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. |
| 158 | pub 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 | |
| 171 | impl<'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. |
| 288 | fn 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. |
| 295 | pub struct NodeIter<'a> { |
| 296 | strings_block: &'a [u8], |
| 297 | nodes: &'a [u8], |
| 298 | } |
| 299 | |
| 300 | enum ParsedToken<'a> { |
| 301 | BeginNode { name: &'a str }, |
| 302 | Property { name_offset: U32b, data: &'a [u8] }, |
| 303 | EndNode, |
| 304 | Nop, |
| 305 | End, |
| 306 | } |
| 307 | |
| 308 | impl 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)] |
| 322 | enum 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 | |
| 337 | impl 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)`. |
| 359 | fn 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 | |
| 409 | impl<'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 | |
| 496 | impl<'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. |
| 505 | pub 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 | |
| 513 | impl<'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. |
| 553 | pub struct PropertyIter<'a> { |
| 554 | node_name: &'a str, |
| 555 | strings_block: &'a [u8], |
| 556 | properties: &'a [u8], |
| 557 | } |
| 558 | |
| 559 | impl<'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 | |
| 603 | impl<'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. |
| 612 | pub 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 | |
| 620 | impl<'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)] |
| 687 | enum 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 | |
| 696 | impl 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. |
| 707 | pub struct MemoryReserveIter<'a> { |
| 708 | memory_reservations: &'a [u8], |
| 709 | } |
| 710 | |
| 711 | impl<'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 | |
| 730 | impl<'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. |
| 740 | impl std::error::Error for StringError {} |
| 741 | |
| 742 | /// Extract a string from bytes treated as a C String, stopping at the first null terminator. |
| 743 | fn 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)] |
| 755 | mod 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 | |