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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ alloc = []
std = ["alloc"]

[dependencies]
zerocopy = { version = "0.8", features = ["derive"] }
zerocopy = { version = "0.8.28", features = ["derive"] }

[lints.rust]
deprecated-safe = "warn"
Expand Down
13 changes: 13 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ pub enum FdtErrorKind {
InvalidOffset,
/// An invalid string was encountered.
InvalidString,
/// Memory reservation block has not been terminated with a null entry.
MemReserveNotTerminated,
/// Memory reservation block has an entry that is unaligned or has invalid
/// size.
MemReserveInvalid,
}

impl fmt::Display for FdtError {
Expand All @@ -65,6 +70,14 @@ impl fmt::Display for FdtErrorKind {
FdtErrorKind::BadToken(token) => write!(f, "bad FDT token: 0x{token:x}"),
FdtErrorKind::InvalidOffset => write!(f, "invalid offset in FDT"),
FdtErrorKind::InvalidString => write!(f, "invalid string in FDT"),
FdtErrorKind::MemReserveNotTerminated => write!(
f,
"memory reservation block not terminated with a null entry"
),
FdtErrorKind::MemReserveInvalid => write!(
f,
"memory reservation block has an entry that is unaligned or has invalid size"
),
}
}
}
Expand Down
38 changes: 38 additions & 0 deletions src/fdt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//! [Flattened Device Tree (FDT)]: https://devicetree-specification.readthedocs.io/en/latest/chapter5-flattened-format.html

use crate::error::{FdtError, FdtErrorKind};
use crate::memreserve::MemoryReservation;
mod node;
mod property;
use core::ffi::CStr;
Expand Down Expand Up @@ -312,6 +313,34 @@ impl<'a> Fdt<'a> {
self.header().boot_cpuid_phys()
}

/// Returns an iterator over the memory reservation block.
pub fn memory_reservations(
&self,
) -> impl Iterator<Item = Result<MemoryReservation, FdtError>> + '_ {
let mut offset = self.header().off_mem_rsvmap() as usize;
core::iter::from_fn(move || {
if offset >= self.header().off_dt_struct() as usize {
return Some(Err(FdtError::new(
FdtErrorKind::MemReserveNotTerminated,
offset,
)));
}

let reservation = match MemoryReservation::ref_from_prefix(&self.data[offset..])
.map_err(|_| FdtError::new(FdtErrorKind::MemReserveInvalid, offset))
{
Ok((reservation, _)) => *reservation,
Err(e) => return Some(Err(e)),
};
offset += size_of::<MemoryReservation>();

if reservation == MemoryReservation::TERMINATOR {
return None;
}
Some(Ok(reservation))
})
}

/// Returns the root node of the device tree.
///
/// # Errors
Expand Down Expand Up @@ -494,6 +523,15 @@ impl<'a> Fdt<'a> {
impl fmt::Display for Fdt<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "/dts-v1/;")?;
for reservation in self.memory_reservations() {
let reservation = reservation.map_err(|_| fmt::Error)?;
writeln!(
f,
"/memreserve/ {:#x} {:#x};",
reservation.address(),
reservation.size()
)?;
}
writeln!(f)?;
let root = self.root().map_err(|_| fmt::Error)?;
root.fmt_recursive(f, 0)
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@

pub mod error;
pub mod fdt;
pub mod memreserve;
57 changes: 57 additions & 0 deletions src/memreserve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Device tree memory reservations.

use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, big_endian};

/// A 64-bit memory reservation.
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
FromBytes,
IntoBytes,
Immutable,
KnownLayout,
)]
#[repr(C)]
pub struct MemoryReservation {
address: big_endian::U64,
size: big_endian::U64,
}

impl MemoryReservation {
pub(crate) const TERMINATOR: Self = Self::new(0, 0);

/// Creates a new [`MemoryReservation`].
#[must_use]
pub const fn new(address: u64, size: u64) -> Self {
Self {
address: big_endian::U64::new(address),
size: big_endian::U64::new(size),
}
}

/// Returns the physical address of the reserved memory region.
#[must_use]
pub const fn address(&self) -> u64 {
self.address.get()
}

/// Returns the size of the reserved memory region.
#[must_use]
pub const fn size(&self) -> u64 {
self.size.get()
}
}
Binary file added tests/dtb/test_memreserve.dtb
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/dts/test_memreserve.dts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/dts-v1/;
/memreserve/ 0x1000 0x100;
/memreserve/ 0x2000 0x200;

/ {
};
1 change: 1 addition & 0 deletions tests/fdt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ macro_rules! load_dtb_dts_pair {
const ALL_DT_FILES: &[(&[u8], &str, &str)] = &[
load_dtb_dts_pair!("test_children_nested"),
load_dtb_dts_pair!("test_children"),
load_dtb_dts_pair!("test_memreserve"),
load_dtb_dts_pair!("test_pretty_print"),
load_dtb_dts_pair!("test_props"),
load_dtb_dts_pair!("test_traversal"),
Expand Down
30 changes: 30 additions & 0 deletions tests/memreserve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use dtoolkit::fdt::Fdt;
use dtoolkit::memreserve::MemoryReservation;

#[test]
fn memreserve() {
let dtb = include_bytes!("dtb/test_memreserve.dtb");
let fdt = Fdt::new(dtb).unwrap();

let reservations: Result<Vec<_>, _> = fdt.memory_reservations().collect();
let reservations = reservations.unwrap();
assert_eq!(
reservations,
&[
MemoryReservation::new(0x1000, 0x100),
MemoryReservation::new(0x2000, 0x200)
]
);

let dts = fdt.to_string();
assert!(dts.contains("/memreserve/ 0x1000 0x100;"));
assert!(dts.contains("/memreserve/ 0x2000 0x200;"));
}