Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ pub enum FdtError {
/// The number of 4 byte cells expected in each element of the array.
chunk: usize,
},
/// Tried to convert part of a prop-encoded-array property to a type which
/// was too small.
#[error("prop-encoded-array field too big for chosen type ({cells} cells)")]
TooManyCells {
/// The number of (32-bit) cells in the field.
cells: usize,
},
}

/// An error that can occur when parsing a device tree.
Expand Down
36 changes: 18 additions & 18 deletions src/fdt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use zerocopy::byteorder::big_endian;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};

pub use self::node::FdtNode;
pub use self::property::FdtProperty;
pub use self::property::{Cells, FdtProperty};
use crate::error::{FdtErrorKind, FdtParseError};
use crate::memreserve::MemoryReservation;

Expand Down Expand Up @@ -240,7 +240,7 @@ impl<'a> Fdt<'a> {
Fdt::new(slice)
}

fn validate_header(&self) -> Result<(), FdtParseError> {
fn validate_header(self) -> Result<(), FdtParseError> {
let header = self.header();
let data = &self.data;

Expand Down Expand Up @@ -291,40 +291,40 @@ impl<'a> Fdt<'a> {
}

/// Returns the header of the device tree.
pub(crate) fn header(&self) -> &FdtHeader {
pub(crate) fn header(self) -> &'a FdtHeader {
let (header, _remaining_bytes) = FdtHeader::ref_from_prefix(self.data)
.expect("new() checks if the slice is at least as big as the header");
header
}

/// Returns the underlying data slice of the FDT.
#[must_use]
pub fn data(&self) -> &'a [u8] {
pub fn data(self) -> &'a [u8] {
self.data
}

/// Returns the version of the FDT.
#[must_use]
pub fn version(&self) -> u32 {
pub fn version(self) -> u32 {
self.header().version()
}

/// Returns the last compatible version of the FDT.
#[must_use]
pub fn last_comp_version(&self) -> u32 {
pub fn last_comp_version(self) -> u32 {
self.header().last_comp_version()
}

/// Returns the physical ID of the boot CPU.
#[must_use]
pub fn boot_cpuid_phys(&self) -> u32 {
pub fn boot_cpuid_phys(self) -> u32 {
self.header().boot_cpuid_phys()
}

/// Returns an iterator over the memory reservation block.
pub fn memory_reservations(
&self,
) -> impl Iterator<Item = Result<MemoryReservation, FdtParseError>> + '_ {
self,
) -> impl Iterator<Item = Result<MemoryReservation, FdtParseError>> + 'a {
let mut offset = self.header().off_mem_rsvmap() as usize;
core::iter::from_fn(move || {
if offset >= self.header().off_dt_struct() as usize {
Expand Down Expand Up @@ -366,7 +366,7 @@ impl<'a> Fdt<'a> {
/// let root = fdt.root().unwrap();
/// assert_eq!(root.name().unwrap(), "");
/// ```
pub fn root(&self) -> Result<FdtNode<'_>, FdtParseError> {
pub fn root(self) -> Result<FdtNode<'a>, FdtParseError> {
let offset = self.header().off_dt_struct() as usize;
let token = self.read_token(offset)?;
if token != FdtToken::BeginNode {
Expand All @@ -375,7 +375,7 @@ impl<'a> Fdt<'a> {
offset,
));
}
Ok(FdtNode { fdt: self, offset })
Ok(FdtNode::new(self, offset))
}

/// Finds a node by its path.
Expand Down Expand Up @@ -424,7 +424,7 @@ impl<'a> Fdt<'a> {
/// let node = fdt.find_node("/child2@42").unwrap().unwrap();
/// assert_eq!(node.name().unwrap(), "child2@42");
/// ```
pub fn find_node(&self, path: &str) -> Result<Option<FdtNode<'_>>, FdtParseError> {
pub fn find_node(self, path: &str) -> Result<Option<FdtNode<'a>>, FdtParseError> {
if !path.starts_with('/') {
return Ok(None);
}
Expand All @@ -441,15 +441,15 @@ impl<'a> Fdt<'a> {
Ok(Some(current_node))
}

pub(crate) fn read_token(&self, offset: usize) -> Result<FdtToken, FdtParseError> {
pub(crate) fn read_token(self, offset: usize) -> Result<FdtToken, FdtParseError> {
let val = big_endian::U32::ref_from_prefix(&self.data[offset..])
.map(|(val, _)| val.get())
.map_err(|_e| FdtParseError::new(FdtErrorKind::InvalidLength, offset))?;
FdtToken::try_from(val).map_err(|t| FdtParseError::new(FdtErrorKind::BadToken(t), offset))
}

/// Returns a string from the string block.
pub(crate) fn string(&self, string_block_offset: usize) -> Result<&'a str, FdtParseError> {
pub(crate) fn string(self, string_block_offset: usize) -> Result<&'a str, FdtParseError> {
let header = self.header();
let str_block_start = header.off_dt_strings() as usize;
let str_block_size = header.size_dt_strings() as usize;
Expand All @@ -465,7 +465,7 @@ impl<'a> Fdt<'a> {

/// Returns a NUL-terminated string from a given offset.
pub(crate) fn string_at_offset(
&self,
self,
offset: usize,
end: Option<usize>,
) -> Result<&'a str, FdtParseError> {
Expand All @@ -481,7 +481,7 @@ impl<'a> Fdt<'a> {
}
}

pub(crate) fn find_string_end(&self, start: usize) -> Result<usize, FdtParseError> {
pub(crate) fn find_string_end(self, start: usize) -> Result<usize, FdtParseError> {
let mut offset = start;
loop {
match self.data.get(offset) {
Expand All @@ -493,7 +493,7 @@ impl<'a> Fdt<'a> {
}
}

pub(crate) fn next_sibling_offset(&self, mut offset: usize) -> Result<usize, FdtParseError> {
pub(crate) fn next_sibling_offset(self, mut offset: usize) -> Result<usize, FdtParseError> {
offset += FDT_TAGSIZE; // Skip FDT_BEGIN_NODE

// Skip node name
Expand Down Expand Up @@ -532,7 +532,7 @@ impl<'a> Fdt<'a> {
Ok(offset)
}

pub(crate) fn next_property_offset(&self, mut offset: usize) -> Result<usize, FdtParseError> {
pub(crate) fn next_property_offset(self, mut offset: usize) -> Result<usize, FdtParseError> {
let len = big_endian::U32::ref_from_prefix(&self.data[offset..])
.map(|(val, _)| val.get())
.map_err(|_e| FdtParseError::new(FdtErrorKind::InvalidLength, offset))?
Expand Down
55 changes: 42 additions & 13 deletions src/fdt/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,27 @@ use core::fmt;
use super::{FDT_TAGSIZE, Fdt, FdtToken};
use crate::error::FdtParseError;
use crate::fdt::property::{FdtPropIter, FdtProperty};
use crate::standard::AddressSpaceProperties;

/// A node in a flattened device tree.
#[derive(Debug, Clone, Copy)]
pub struct FdtNode<'a> {
pub(crate) fdt: &'a Fdt<'a>,
pub(crate) fdt: Fdt<'a>,
pub(crate) offset: usize,
/// The `#address-cells` and `#size-cells` properties of this node's parent
/// node.
pub(crate) parent_address_space: AddressSpaceProperties,
}

impl<'a> FdtNode<'a> {
pub(crate) fn new(fdt: Fdt<'a>, offset: usize) -> Self {
Self {
fdt,
offset,
parent_address_space: AddressSpaceProperties::default(),
}
}

/// Returns the name of this node.
///
/// # Errors
Expand Down Expand Up @@ -196,10 +208,7 @@ impl<'a> FdtNode<'a> {
/// assert!(children.next().is_none());
/// ```
pub fn children(&self) -> impl Iterator<Item = Result<FdtNode<'a>, FdtParseError>> + use<'a> {
FdtChildIter::Start {
fdt: self.fdt,
offset: self.offset,
}
FdtChildIter::Start { node: *self }
}

pub(crate) fn fmt_recursive(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result {
Expand Down Expand Up @@ -242,8 +251,14 @@ impl<'a> FdtNode<'a> {

/// An iterator over the children of a device tree node.
enum FdtChildIter<'a> {
Start { fdt: &'a Fdt<'a>, offset: usize },
Running { fdt: &'a Fdt<'a>, offset: usize },
Start {
node: FdtNode<'a>,
},
Running {
fdt: Fdt<'a>,
offset: usize,
address_space: AddressSpaceProperties,
},
Error,
}

Expand All @@ -252,21 +267,33 @@ impl<'a> Iterator for FdtChildIter<'a> {

fn next(&mut self) -> Option<Self::Item> {
match self {
Self::Start { fdt, offset } => {
let mut offset = *offset;
Self::Start { node } => {
let address_space = match node.address_space() {
Ok(value) => value,
Err(e) => return Some(Err(e)),
};
let mut offset = node.offset;
offset += FDT_TAGSIZE; // Skip FDT_BEGIN_NODE
offset = match fdt.find_string_end(offset) {
offset = match node.fdt.find_string_end(offset) {
Ok(offset) => offset,
Err(e) => {
*self = Self::Error;
return Some(Err(e));
}
};
offset = Fdt::align_tag_offset(offset);
*self = Self::Running { fdt, offset };
*self = Self::Running {
fdt: node.fdt,
offset,
address_space,
};
self.next()
}
Self::Running { fdt, offset } => match Self::try_next(fdt, offset) {
Self::Running {
fdt,
offset,
address_space,
} => match Self::try_next(*fdt, offset, *address_space) {
Some(Ok(val)) => Some(Ok(val)),
Some(Err(e)) => {
*self = Self::Error;
Expand All @@ -281,8 +308,9 @@ impl<'a> Iterator for FdtChildIter<'a> {

impl<'a> FdtChildIter<'a> {
fn try_next(
fdt: &'a Fdt<'a>,
fdt: Fdt<'a>,
offset: &mut usize,
parent_address_space: AddressSpaceProperties,
) -> Option<Result<FdtNode<'a>, FdtParseError>> {
loop {
let token = match fdt.read_token(*offset) {
Expand All @@ -299,6 +327,7 @@ impl<'a> FdtChildIter<'a> {
return Some(Ok(FdtNode {
fdt,
offset: node_offset,
parent_address_space,
}));
}
FdtToken::Prop => {
Expand Down
Loading