Skip to content

Commit 1c721af

Browse files
committed
Add support for Memory Reservations in FDT
1 parent 204e7ab commit 1c721af

8 files changed

Lines changed: 148 additions & 1 deletion

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ alloc = []
1717
std = ["alloc"]
1818

1919
[dependencies]
20-
zerocopy = { version = "0.8", features = ["derive"] }
20+
zerocopy = { version = "0.8.28", features = ["derive"] }
2121

2222
[lints.rust]
2323
deprecated-safe = "warn"

src/error.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ pub enum FdtErrorKind {
4343
InvalidOffset,
4444
/// An invalid string was encountered.
4545
InvalidString,
46+
/// Memory reservation block has not been terminated with a null entry.
47+
MemReserveNotTerminated,
48+
/// Memory reservation block has an entry that is unaligned or has invalid
49+
/// size.
50+
MemReserveInvalid,
4651
}
4752

4853
impl fmt::Display for FdtError {
@@ -65,6 +70,14 @@ impl fmt::Display for FdtErrorKind {
6570
FdtErrorKind::BadToken(token) => write!(f, "bad FDT token: 0x{token:x}"),
6671
FdtErrorKind::InvalidOffset => write!(f, "invalid offset in FDT"),
6772
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+
),
6881
}
6982
}
7083
}

src/fdt/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
//! [Flattened Device Tree (FDT)]: https://devicetree-specification.readthedocs.io/en/latest/chapter5-flattened-format.html
1717
1818
use crate::error::{FdtError, FdtErrorKind};
19+
use crate::memreserve::MemoryReservation;
1920
mod node;
2021
mod property;
2122
use core::ffi::CStr;
@@ -312,6 +313,34 @@ impl<'a> Fdt<'a> {
312313
self.header().boot_cpuid_phys()
313314
}
314315

316+
/// Returns an iterator over the memory reservation block.
317+
pub fn memory_reservations(
318+
&self,
319+
) -> impl Iterator<Item = Result<MemoryReservation, FdtError>> + '_ {
320+
let mut offset = self.header().off_mem_rsvmap() as usize;
321+
core::iter::from_fn(move || {
322+
if offset >= self.header().off_dt_struct() as usize {
323+
return Some(Err(FdtError::new(
324+
FdtErrorKind::MemReserveNotTerminated,
325+
offset,
326+
)));
327+
}
328+
329+
let reservation = match MemoryReservation::ref_from_prefix(&self.data[offset..])
330+
.map_err(|_| FdtError::new(FdtErrorKind::MemReserveInvalid, offset))
331+
{
332+
Ok((reservation, _)) => *reservation,
333+
Err(e) => return Some(Err(e)),
334+
};
335+
offset += size_of::<MemoryReservation>();
336+
337+
if reservation == MemoryReservation::TERMINATOR {
338+
return None;
339+
}
340+
Some(Ok(reservation))
341+
})
342+
}
343+
315344
/// Returns the root node of the device tree.
316345
///
317346
/// # Errors
@@ -498,6 +527,15 @@ impl<'a> Fdt<'a> {
498527
impl fmt::Display for Fdt<'_> {
499528
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
500529
writeln!(f, "/dts-v1/;")?;
530+
for reservation in self.memory_reservations() {
531+
let reservation = reservation.map_err(|_| fmt::Error)?;
532+
writeln!(
533+
f,
534+
"/memreserve/ {:#x} {:#x};",
535+
reservation.address(),
536+
reservation.size()
537+
)?;
538+
}
501539
writeln!(f)?;
502540
let root = self.root().map_err(|_| fmt::Error)?;
503541
root.fmt_recursive(f, 0)

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,7 @@
2323
#![warn(missing_docs, rustdoc::missing_crate_level_docs)]
2424
#![cfg_attr(docsrs, feature(doc_cfg))]
2525

26+
pub mod memreserve;
27+
2628
pub mod error;
2729
pub mod fdt;

src/memreserve.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
//! Device tree memory reservations.
10+
11+
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, big_endian};
12+
13+
/// A 64-bit memory reservation.
14+
#[derive(
15+
Debug,
16+
Clone,
17+
Copy,
18+
PartialEq,
19+
Eq,
20+
PartialOrd,
21+
Ord,
22+
Hash,
23+
FromBytes,
24+
IntoBytes,
25+
Immutable,
26+
KnownLayout,
27+
)]
28+
#[repr(C)]
29+
pub struct MemoryReservation {
30+
address: big_endian::U64,
31+
size: big_endian::U64,
32+
}
33+
34+
impl MemoryReservation {
35+
pub(crate) const TERMINATOR: Self = Self::new(0, 0);
36+
37+
/// Creates a new [`MemoryReservation`].
38+
#[must_use]
39+
pub const fn new(address: u64, size: u64) -> Self {
40+
Self {
41+
address: big_endian::U64::new(address),
42+
size: big_endian::U64::new(size),
43+
}
44+
}
45+
46+
/// Returns the physical address of the reserved memory region.
47+
#[must_use]
48+
pub const fn address(&self) -> u64 {
49+
self.address.get()
50+
}
51+
52+
/// Returns the size of the reserved memory region.
53+
#[must_use]
54+
pub const fn size(&self) -> u64 {
55+
self.size.get()
56+
}
57+
}

tests/dtb/test_memreserve.dtb

104 Bytes
Binary file not shown.

tests/dts/test_memreserve.dts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/dts-v1/;
2+
3+
/memreserve/ 0x1000 0x100;
4+
/memreserve/ 0x2000 0x200;
5+
6+
/ {
7+
};

tests/memreserve.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2025 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5+
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6+
// option. This file may not be copied, modified, or distributed
7+
// except according to those terms.
8+
9+
use dtoolkit::fdt::Fdt;
10+
use dtoolkit::memreserve::MemoryReservation;
11+
12+
#[test]
13+
fn memreserve() {
14+
let dtb = include_bytes!("dtb/test_memreserve.dtb");
15+
let fdt = Fdt::new(dtb).unwrap();
16+
17+
let reservations: Result<Vec<_>, _> = fdt.memory_reservations().collect();
18+
let reservations = reservations.unwrap();
19+
assert_eq!(
20+
reservations,
21+
&[
22+
MemoryReservation::new(0x1000, 0x100),
23+
MemoryReservation::new(0x2000, 0x200)
24+
]
25+
);
26+
27+
let dts = fdt.to_string();
28+
assert!(dts.contains("/memreserve/ 0x1000 0x100;"));
29+
assert!(dts.contains("/memreserve/ 0x2000 0x200;"));
30+
}

0 commit comments

Comments
 (0)