Skip to content

Commit 18576e3

Browse files
committed
WIP: Add getter for standard reg property.
1 parent fa206de commit 18576e3

9 files changed

Lines changed: 156 additions & 3 deletions

File tree

src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ pub enum FdtError {
2121
"prop-encoded-array property was {size} bytes, but should have been a multiple of {chunk} cells"
2222
)]
2323
PropEncodedArraySizeMismatch { size: usize, chunk: usize },
24+
#[error("Reg address too big for chosen type ({cells} cells)")]
25+
AddressTooBig { cells: usize },
26+
#[error("Reg size too big for chosen type ({cells} cells)")]
27+
SizeTooBig { cells: usize },
2428
}
2529

2630
/// An error that can occur when parsing a device tree.

src/fdt/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
2828

2929
pub use self::node::FdtNode;
3030
pub use self::property::FdtProperty;
31+
pub use self::property::reg::Reg;
3132
pub use self::property::status::Status;
3233
use crate::error::{FdtError, FdtErrorKind, FdtParseError};
3334
use crate::memreserve::MemoryReservation;

src/fdt/node.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use core::fmt;
1313
use super::{FDT_TAGSIZE, Fdt, FdtToken};
1414
use crate::error::{FdtError, FdtParseError};
1515
use crate::fdt::Status;
16+
use crate::fdt::property::reg::Reg;
1617
use crate::fdt::property::{FdtPropIter, FdtProperty};
1718

1819
const DEFAULT_ADDRESS_CELLS: u32 = 2;
@@ -289,6 +290,25 @@ impl<'a> FdtNode<'a> {
289290
})
290291
}
291292

293+
/// Returns the value of the standard `reg` property.
294+
pub fn reg(&self) -> Result<Option<impl Iterator<Item = Reg<'a>> + use<'a>>, FdtError> {
295+
let parent = self.parent();
296+
let address_cells = parent.address_cells()?;
297+
let size_cells = parent.size_cells()?;
298+
Ok(if let Some(property) = self.property("reg")? {
299+
Some(
300+
property
301+
.as_prop_encoded_array((address_cells + size_cells) as usize)?
302+
.map(move |element| {
303+
let (address, size) = element.split_at(address_cells as usize);
304+
Reg { address, size }
305+
}),
306+
)
307+
} else {
308+
None
309+
})
310+
}
311+
292312
/// Returns the value of the standard `virtual-reg` property.
293313
pub fn virtual_reg(&self) -> Result<Option<u32>, FdtError> {
294314
Ok(if let Some(property) = self.property("virtual-reg")? {

src/fdt/property.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
//! A read-only API for inspecting a device tree property.
1010
11+
pub mod reg;
1112
pub mod status;
1213

1314
use core::ffi::CStr;

src/fdt/property/reg.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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 core::fmt::{self, Display, Formatter};
10+
use core::ops::{BitOr, Shl};
11+
12+
use zerocopy::big_endian;
13+
14+
use crate::error::FdtError;
15+
16+
/// The value of a `reg` property.
17+
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
18+
pub struct Reg<'a> {
19+
/// The address of the device within the address space of the parent bus.
20+
pub address: &'a [big_endian::U32],
21+
/// The size of the device within the address space of the parent bus.
22+
pub size: &'a [big_endian::U32],
23+
}
24+
25+
impl Reg<'_> {
26+
/// Attempts to return the address as the given type, if it will fit.
27+
pub fn address<T: Default + From<u32> + Shl<usize, Output = T> + BitOr<Output = T>>(
28+
self,
29+
) -> Result<T, FdtError> {
30+
if size_of::<T>() < self.address.len() * size_of::<u32>() {
31+
Err(FdtError::AddressTooBig {
32+
cells: self.address.len(),
33+
})
34+
} else {
35+
let mut value = Default::default();
36+
for cell in self.address {
37+
value = (value << 32) | cell.get().into();
38+
}
39+
Ok(value)
40+
}
41+
}
42+
43+
/// Attempts to return the size as the given type, if it will fit.
44+
pub fn size<T: Default + From<u32> + Shl<usize, Output = T> + BitOr<Output = T>>(
45+
self,
46+
) -> Result<T, FdtError> {
47+
if size_of::<T>() < self.size.len() * size_of::<u32>() {
48+
Err(FdtError::SizeTooBig {
49+
cells: self.size.len(),
50+
})
51+
} else {
52+
let mut value = Default::default();
53+
for cell in self.size {
54+
value = value << size_of::<u32>() | cell.get().into();
55+
}
56+
Ok(value)
57+
}
58+
}
59+
}
60+
61+
impl Display for Reg<'_> {
62+
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
63+
f.write_str("0x")?;
64+
for part in self.address {
65+
write!(f, "{part:08x}")?;
66+
}
67+
f.write_str(" 0x")?;
68+
for part in self.size {
69+
write!(f, "{part:08x}")?;
70+
}
71+
Ok(())
72+
}
73+
}
74+
75+
#[cfg(test)]
76+
mod tests {
77+
use super::*;
78+
79+
#[test]
80+
fn format_reg() {
81+
let reg = Reg {
82+
address: &[0x12345678.into(), 0xabcd0000.into()],
83+
size: &[0x11223344.into()],
84+
};
85+
assert_eq!(format!("{}", reg), "0x12345678abcd0000 0x11223344");
86+
}
87+
88+
#[test]
89+
fn address_size() {
90+
let reg = Reg {
91+
address: &[0x12345678.into(), 0xabcd0000.into()],
92+
size: &[0x11223344.into()],
93+
};
94+
assert_eq!(
95+
reg.address::<u32>(),
96+
Err(FdtError::AddressTooBig { cells: 2 })
97+
);
98+
assert_eq!(reg.address::<u64>(), Ok(0x12345678_abcd0000));
99+
assert_eq!(reg.size::<u32>(), Ok(0x11223344));
100+
assert_eq!(reg.size::<u64>(), Ok(0x11223344));
101+
}
102+
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
//! you don't need the Device Tree manipulation functionality, the library is
2020
//! also no-`alloc`-compatible.
2121
22-
#![no_std]
22+
#![cfg_attr(not(test), no_std)]
2323
#![warn(missing_docs, rustdoc::missing_crate_level_docs)]
2424
#![cfg_attr(docsrs, feature(doc_cfg))]
2525

tests/dtb/test_props.dtb

36 Bytes
Binary file not shown.

tests/dts/test_props.dts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
str-list-prop = "first", "second", "third";
1212
};
1313

14-
standard-props {
14+
standard-props@1 {
1515
#address-cells = <0x08>;
1616
#size-cells = <0x04>;
17+
reg = <0x3000 0x20 0xfe00 0x100>;
1718
compatible = "abc,def", "some,other";
1819
status = "fail";
1920
model = "Some Model";

tests/fdt.rs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
use dtoolkit::fdt::{Fdt, InitialMappedArea, Status};
9+
use dtoolkit::fdt::{Fdt, InitialMappedArea, Reg, Status};
1010

1111
#[test]
1212
fn read_child_nodes() {
@@ -112,6 +112,23 @@ fn standard_properties() {
112112
.collect::<Vec<_>>(),
113113
vec!["abc,def", "some,other"]
114114
);
115+
assert_eq!(
116+
standard_props_node
117+
.reg()
118+
.unwrap()
119+
.unwrap()
120+
.collect::<Vec<_>>(),
121+
vec![
122+
Reg {
123+
address: &[0x3000.into()],
124+
size: &[32.into()],
125+
},
126+
Reg {
127+
address: &[0xfe00.into()],
128+
size: &[256.into()],
129+
},
130+
]
131+
);
115132
}
116133

117134
#[test]
@@ -188,6 +205,13 @@ fn memory() {
188205
let fdt = Fdt::new(dtb).unwrap();
189206

190207
let memory = fdt.memory().unwrap();
208+
assert_eq!(
209+
memory.reg().unwrap().unwrap().collect::<Vec<_>>(),
210+
vec![Reg {
211+
address: &[0.into(), 0x80000000.into()],
212+
size: &[0x20000000.into()]
213+
}]
214+
);
191215
assert!(memory.hotpluggable().unwrap());
192216
assert_eq!(
193217
memory

0 commit comments

Comments
 (0)