Skip to content

Commit cc093d9

Browse files
authored
feat: Add getters for some standard properties (#16)
1 parent 6d2fd59 commit cc093d9

File tree

14 files changed

+353
-103
lines changed

14 files changed

+353
-103
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ write = ["dep:indexmap", "dep:twox-hash"]
1818

1919
[dependencies]
2020
indexmap = { version = "2", optional = true, default-features = false }
21+
thiserror = { version = "2", default-features = false }
2122
twox-hash = { version = "2", optional = true, features = ["xxhash64"], default-features = false }
2223
zerocopy = { version = "0.8.28", features = ["derive"] }
2324

src/error.rs

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,78 +8,71 @@
88

99
//! Error types for the `dtoolkit` crate.
1010
11-
use core::fmt;
11+
use core::fmt::{self, Display, Formatter};
12+
13+
use thiserror::Error;
14+
15+
/// An error that can occur when parsing or accessing a device tree.
16+
#[derive(Clone, Debug, Eq, Error, PartialEq)]
17+
pub enum FdtError {
18+
/// There was an error parsing the device tree.
19+
#[error("{0}")]
20+
Parse(#[from] FdtParseError),
21+
/// The `status` property of a node had an invalid value.
22+
#[error("Invalid status value")]
23+
InvalidStatus,
24+
}
1225

1326
/// An error that can occur when parsing a device tree.
14-
#[derive(Debug)]
27+
#[derive(Clone, Debug, Eq, Error, PartialEq)]
1528
#[non_exhaustive]
16-
pub struct FdtError {
29+
pub struct FdtParseError {
1730
offset: usize,
1831
/// The type of the error that has occurred.
1932
pub kind: FdtErrorKind,
2033
}
2134

22-
impl FdtError {
35+
impl FdtParseError {
2336
pub(crate) fn new(kind: FdtErrorKind, offset: usize) -> Self {
2437
Self { offset, kind }
2538
}
2639
}
2740

41+
impl Display for FdtParseError {
42+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
43+
write!(f, "{} at offset {}", self.kind, self.offset)
44+
}
45+
}
2846
/// The kind of an error that can occur when parsing a device tree.
29-
#[derive(Debug)]
47+
#[derive(Clone, Debug, Eq, Error, PartialEq)]
3048
#[non_exhaustive]
3149
pub enum FdtErrorKind {
3250
/// The magic number of the device tree is invalid.
51+
#[error("Invalid FDT magic number")]
3352
InvalidMagic,
3453
/// The Device Tree version is not supported by this library.
54+
#[error("FDT version {0} is not supported")]
3555
UnsupportedVersion(u32),
3656
/// The length of the device tree is invalid.
57+
#[error("Invalid FDT length")]
3758
InvalidLength,
3859
/// The header failed validation.
60+
#[error("FDT header has failed validation: {0}")]
3961
InvalidHeader(&'static str),
4062
/// An invalid token was encountered.
63+
#[error("Bad FDT token: {0:#x}")]
4164
BadToken(u32),
4265
/// A read from data at invalid offset was attempted.
66+
#[error("Invalid offset in FDT")]
4367
InvalidOffset,
4468
/// An invalid string was encountered.
69+
#[error("Invalid string in FDT")]
4570
InvalidString,
4671
/// Memory reservation block has not been terminated with a null entry.
72+
#[error("Memory reservation block was not terminated with a null entry")]
4773
MemReserveNotTerminated,
4874
/// Memory reservation block has an entry that is unaligned or has invalid
4975
/// size.
76+
#[error("Memory reservation block has an entry that is unaligned or has invalid size")]
5077
MemReserveInvalid,
5178
}
52-
53-
impl fmt::Display for FdtError {
54-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55-
write!(f, "{} at offset {}", self.kind, self.offset)
56-
}
57-
}
58-
59-
impl fmt::Display for FdtErrorKind {
60-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61-
match self {
62-
FdtErrorKind::InvalidMagic => write!(f, "invalid FDT magic number"),
63-
FdtErrorKind::UnsupportedVersion(version) => {
64-
write!(f, "the FDT version {version} is not supported")
65-
}
66-
FdtErrorKind::InvalidLength => write!(f, "invalid FDT length"),
67-
FdtErrorKind::InvalidHeader(msg) => {
68-
write!(f, "FDT header has failed validation: {msg}")
69-
}
70-
FdtErrorKind::BadToken(token) => write!(f, "bad FDT token: 0x{token:x}"),
71-
FdtErrorKind::InvalidOffset => write!(f, "invalid offset in FDT"),
72-
FdtErrorKind::InvalidString => write!(f, "invalid string in FDT"),
73-
FdtErrorKind::MemReserveNotTerminated => write!(
74-
f,
75-
"memory reservation block not terminated with a null entry"
76-
),
77-
FdtErrorKind::MemReserveInvalid => write!(
78-
f,
79-
"memory reservation block has an entry that is unaligned or has invalid size"
80-
),
81-
}
82-
}
83-
}
84-
85-
impl core::error::Error for FdtError {}

src/fdt/mod.rs

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,21 @@
1515
//!
1616
//! [Flattened Device Tree (FDT)]: https://devicetree-specification.readthedocs.io/en/latest/chapter5-flattened-format.html
1717
18-
use crate::error::{FdtError, FdtErrorKind};
19-
use crate::memreserve::MemoryReservation;
2018
mod node;
2119
mod property;
20+
2221
use core::ffi::CStr;
2322
use core::mem::offset_of;
2423
use core::{fmt, ptr};
2524

26-
pub use node::FdtNode;
27-
pub use property::FdtProperty;
2825
use zerocopy::byteorder::big_endian;
2926
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
3027

28+
pub use self::node::FdtNode;
29+
pub use self::property::FdtProperty;
30+
use crate::error::{FdtErrorKind, FdtParseError};
31+
use crate::memreserve::MemoryReservation;
32+
3133
/// Version of the FDT specification supported by this library.
3234
const FDT_VERSION: u32 = 17;
3335
pub(crate) const FDT_TAGSIZE: usize = size_of::<u32>();
@@ -161,29 +163,29 @@ impl<'a> Fdt<'a> {
161163
/// # let dtb = include_bytes!("../../tests/dtb/test.dtb");
162164
/// let fdt = Fdt::new(dtb).unwrap();
163165
/// ```
164-
pub fn new(data: &'a [u8]) -> Result<Self, FdtError> {
166+
pub fn new(data: &'a [u8]) -> Result<Self, FdtParseError> {
165167
if data.len() < size_of::<FdtHeader>() {
166-
return Err(FdtError::new(FdtErrorKind::InvalidLength, 0));
168+
return Err(FdtParseError::new(FdtErrorKind::InvalidLength, 0));
167169
}
168170

169171
let fdt = Fdt { data };
170172
let header = fdt.header();
171173

172174
if header.magic() != FDT_MAGIC {
173-
return Err(FdtError::new(
175+
return Err(FdtParseError::new(
174176
FdtErrorKind::InvalidMagic,
175177
offset_of!(FdtHeader, magic),
176178
));
177179
}
178180
if !(header.last_comp_version()..=header.version()).contains(&FDT_VERSION) {
179-
return Err(FdtError::new(
181+
return Err(FdtParseError::new(
180182
FdtErrorKind::UnsupportedVersion(header.version()),
181183
offset_of!(FdtHeader, version),
182184
));
183185
}
184186

185187
if header.totalsize() as usize != data.len() {
186-
return Err(FdtError::new(
188+
return Err(FdtParseError::new(
187189
FdtErrorKind::InvalidLength,
188190
offset_of!(FdtHeader, totalsize),
189191
));
@@ -222,7 +224,7 @@ impl<'a> Fdt<'a> {
222224
embedded applications, where the binary only gets a pointer to DT from the firmware or \
223225
a bootloader. The user must ensure it trusts the data."
224226
)]
225-
pub unsafe fn from_raw(data: *const u8) -> Result<Self, FdtError> {
227+
pub unsafe fn from_raw(data: *const u8) -> Result<Self, FdtParseError> {
226228
// SAFETY: The caller guarantees that `data` is a valid pointer to a Flattened
227229
// Device Tree (FDT) blob. We are reading an `FdtHeader` from this
228230
// pointer, which is a `#[repr(C, packed)]` struct. The `totalsize`
@@ -238,27 +240,27 @@ impl<'a> Fdt<'a> {
238240
Fdt::new(slice)
239241
}
240242

241-
fn validate_header(&self) -> Result<(), FdtError> {
243+
fn validate_header(&self) -> Result<(), FdtParseError> {
242244
let header = self.header();
243245
let data = &self.data;
244246

245247
let off_mem_rsvmap = header.off_mem_rsvmap() as usize;
246248
let off_dt_struct = header.off_dt_struct() as usize;
247249
let off_dt_strings = header.off_dt_strings() as usize;
248250
if off_mem_rsvmap > off_dt_struct {
249-
return Err(FdtError::new(
251+
return Err(FdtParseError::new(
250252
FdtErrorKind::InvalidHeader("dt_struct not after memrsvmap"),
251253
offset_of!(FdtHeader, off_mem_rsvmap),
252254
));
253255
}
254256
if off_dt_struct > data.len() {
255-
return Err(FdtError::new(
257+
return Err(FdtParseError::new(
256258
FdtErrorKind::InvalidHeader("struct offset out of bounds"),
257259
offset_of!(FdtHeader, off_dt_struct),
258260
));
259261
}
260262
if off_dt_strings > data.len() {
261-
return Err(FdtError::new(
263+
return Err(FdtParseError::new(
262264
FdtErrorKind::InvalidHeader("strings offset out of bounds"),
263265
offset_of!(FdtHeader, off_dt_strings),
264266
));
@@ -267,19 +269,19 @@ impl<'a> Fdt<'a> {
267269
let size_dt_struct = header.size_dt_struct() as usize;
268270
let size_dt_strings = header.size_dt_strings() as usize;
269271
if off_dt_struct.saturating_add(size_dt_struct) > data.len() {
270-
return Err(FdtError::new(
272+
return Err(FdtParseError::new(
271273
FdtErrorKind::InvalidHeader("struct block overflows"),
272274
offset_of!(FdtHeader, size_dt_struct),
273275
));
274276
}
275277
if off_dt_strings.saturating_add(size_dt_strings) > data.len() {
276-
return Err(FdtError::new(
278+
return Err(FdtParseError::new(
277279
FdtErrorKind::InvalidHeader("strings block overflows"),
278280
offset_of!(FdtHeader, size_dt_strings),
279281
));
280282
}
281283
if off_dt_struct.saturating_add(size_dt_struct) > off_dt_strings {
282-
return Err(FdtError::new(
284+
return Err(FdtParseError::new(
283285
FdtErrorKind::InvalidHeader("strings block not after struct block"),
284286
offset_of!(FdtHeader, off_dt_strings),
285287
));
@@ -322,18 +324,18 @@ impl<'a> Fdt<'a> {
322324
/// Returns an iterator over the memory reservation block.
323325
pub fn memory_reservations(
324326
&self,
325-
) -> impl Iterator<Item = Result<MemoryReservation, FdtError>> + '_ {
327+
) -> impl Iterator<Item = Result<MemoryReservation, FdtParseError>> + '_ {
326328
let mut offset = self.header().off_mem_rsvmap() as usize;
327329
core::iter::from_fn(move || {
328330
if offset >= self.header().off_dt_struct() as usize {
329-
return Some(Err(FdtError::new(
331+
return Some(Err(FdtParseError::new(
330332
FdtErrorKind::MemReserveNotTerminated,
331333
offset,
332334
)));
333335
}
334336

335337
let reservation = match MemoryReservation::ref_from_prefix(&self.data[offset..])
336-
.map_err(|_| FdtError::new(FdtErrorKind::MemReserveInvalid, offset))
338+
.map_err(|_| FdtParseError::new(FdtErrorKind::MemReserveInvalid, offset))
337339
{
338340
Ok((reservation, _)) => *reservation,
339341
Err(e) => return Some(Err(e)),
@@ -364,11 +366,11 @@ impl<'a> Fdt<'a> {
364366
/// let root = fdt.root().unwrap();
365367
/// assert_eq!(root.name().unwrap(), "");
366368
/// ```
367-
pub fn root(&self) -> Result<FdtNode<'_>, FdtError> {
369+
pub fn root(&self) -> Result<FdtNode<'_>, FdtParseError> {
368370
let offset = self.header().off_dt_struct() as usize;
369371
let token = self.read_token(offset)?;
370372
if token != FdtToken::BeginNode {
371-
return Err(FdtError::new(
373+
return Err(FdtParseError::new(
372374
FdtErrorKind::BadToken(FDT_BEGIN_NODE),
373375
offset,
374376
));
@@ -422,7 +424,7 @@ impl<'a> Fdt<'a> {
422424
/// let node = fdt.find_node("/child2@42").unwrap().unwrap();
423425
/// assert_eq!(node.name().unwrap(), "child2@42");
424426
/// ```
425-
pub fn find_node(&self, path: &str) -> Result<Option<FdtNode<'_>>, FdtError> {
427+
pub fn find_node(&self, path: &str) -> Result<Option<FdtNode<'_>>, FdtParseError> {
426428
if !path.starts_with('/') {
427429
return Ok(None);
428430
}
@@ -439,23 +441,23 @@ impl<'a> Fdt<'a> {
439441
Ok(Some(current_node))
440442
}
441443

442-
pub(crate) fn read_token(&self, offset: usize) -> Result<FdtToken, FdtError> {
444+
pub(crate) fn read_token(&self, offset: usize) -> Result<FdtToken, FdtParseError> {
443445
let val = big_endian::U32::ref_from_prefix(&self.data[offset..])
444446
.map(|(val, _)| val.get())
445-
.map_err(|_e| FdtError::new(FdtErrorKind::InvalidLength, offset))?;
446-
FdtToken::try_from(val).map_err(|t| FdtError::new(FdtErrorKind::BadToken(t), offset))
447+
.map_err(|_e| FdtParseError::new(FdtErrorKind::InvalidLength, offset))?;
448+
FdtToken::try_from(val).map_err(|t| FdtParseError::new(FdtErrorKind::BadToken(t), offset))
447449
}
448450

449451
/// Returns a string from the string block.
450-
pub(crate) fn string(&self, string_block_offset: usize) -> Result<&'a str, FdtError> {
452+
pub(crate) fn string(&self, string_block_offset: usize) -> Result<&'a str, FdtParseError> {
451453
let header = self.header();
452454
let str_block_start = header.off_dt_strings() as usize;
453455
let str_block_size = header.size_dt_strings() as usize;
454456
let str_block_end = str_block_start + str_block_size;
455457
let str_start = str_block_start + string_block_offset;
456458

457459
if str_start >= str_block_end {
458-
return Err(FdtError::new(FdtErrorKind::InvalidLength, str_start));
460+
return Err(FdtParseError::new(FdtErrorKind::InvalidLength, str_start));
459461
}
460462

461463
self.string_at_offset(str_start, Some(str_block_end))
@@ -466,32 +468,32 @@ impl<'a> Fdt<'a> {
466468
&self,
467469
offset: usize,
468470
end: Option<usize>,
469-
) -> Result<&'a str, FdtError> {
471+
) -> Result<&'a str, FdtParseError> {
470472
let slice = match end {
471473
Some(end) => self.data.get(offset..end),
472474
None => self.data.get(offset..),
473475
};
474-
let slice = slice.ok_or(FdtError::new(FdtErrorKind::InvalidOffset, offset))?;
476+
let slice = slice.ok_or(FdtParseError::new(FdtErrorKind::InvalidOffset, offset))?;
475477

476478
match CStr::from_bytes_until_nul(slice).map(|val| val.to_str()) {
477479
Ok(Ok(val)) => Ok(val),
478-
_ => Err(FdtError::new(FdtErrorKind::InvalidString, offset)),
480+
_ => Err(FdtParseError::new(FdtErrorKind::InvalidString, offset)),
479481
}
480482
}
481483

482-
pub(crate) fn find_string_end(&self, start: usize) -> Result<usize, FdtError> {
484+
pub(crate) fn find_string_end(&self, start: usize) -> Result<usize, FdtParseError> {
483485
let mut offset = start;
484486
loop {
485487
match self.data.get(offset) {
486488
Some(0) => return Ok(offset + 1),
487489
Some(_) => {}
488-
None => return Err(FdtError::new(FdtErrorKind::InvalidString, start)),
490+
None => return Err(FdtParseError::new(FdtErrorKind::InvalidString, start)),
489491
}
490492
offset += 1;
491493
}
492494
}
493495

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

497499
// Skip node name
@@ -530,10 +532,10 @@ impl<'a> Fdt<'a> {
530532
Ok(offset)
531533
}
532534

533-
pub(crate) fn next_property_offset(&self, mut offset: usize) -> Result<usize, FdtError> {
535+
pub(crate) fn next_property_offset(&self, mut offset: usize) -> Result<usize, FdtParseError> {
534536
let len = big_endian::U32::ref_from_prefix(&self.data[offset..])
535537
.map(|(val, _)| val.get())
536-
.map_err(|_e| FdtError::new(FdtErrorKind::InvalidLength, offset))?
538+
.map_err(|_e| FdtParseError::new(FdtErrorKind::InvalidLength, offset))?
537539
as usize;
538540
offset += FDT_TAGSIZE; // skip value length
539541
offset += FDT_TAGSIZE; // skip name offset

0 commit comments

Comments
 (0)