Skip to content

Commit

Permalink
fix Ranges
Browse files Browse the repository at this point in the history
I misread the spec
  • Loading branch information
kadiwa4 committed Sep 28, 2023
1 parent 7e04606 commit c4de8bf
Show file tree
Hide file tree
Showing 3 changed files with 127 additions and 34 deletions.
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ impl<'dtb> DeserializeProperty<'dtb> for &'dtb [u8] {
}

impl<'dtb> DeserializeProperty<'dtb> for &'dtb [u32] {
/// Gives a devicetree property value as a big-endian u32 slice.
fn deserialize(blob_prop: Property<'dtb>, _cx: NodeContext<'_>) -> Result<Self> {
match Ref::new_slice(blob_prop.value()) {
Some(val) => Ok(val.into_slice()),
Expand All @@ -275,6 +276,7 @@ impl<'dtb> DeserializeProperty<'dtb> for &'dtb [u32] {
}

impl<'dtb> DeserializeProperty<'dtb> for u32 {
/// Gives a devicetree property value as a native-endian u32.
fn deserialize(blob_prop: Property<'dtb>, _cx: NodeContext<'_>) -> Result<Self> {
match blob_prop.value().try_into() {
Ok(arr) => Ok(Self::from_be_bytes(arr)),
Expand All @@ -284,6 +286,7 @@ impl<'dtb> DeserializeProperty<'dtb> for u32 {
}

impl<'dtb> DeserializeProperty<'dtb> for u64 {
/// Gives a devicetree property value as a native-endian u64.
fn deserialize(blob_prop: Property<'dtb>, _cx: NodeContext<'_>) -> Result<Self> {
match blob_prop.value().try_into() {
Ok(arr) => Ok(Self::from_be_bytes(arr)),
Expand Down
138 changes: 104 additions & 34 deletions src/prop_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl Default for Strings<'static> {
}

/// Iterator over the _(address, length)_ pairs of `reg`'s value.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub struct Reg<'dtb> {
value: &'dtb [u32],
address_cells: Cells,
Expand Down Expand Up @@ -180,12 +180,12 @@ impl DoubleEndedIterator for Reg<'_> {
impl ExactSizeIterator for Reg<'_> {}
impl FusedIterator for Reg<'_> {}

/// _(address, length)_ pair contained in [`Reg`].
/// _(address, length)_ pair contained in [`reg`](Reg).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RegBlock(pub u128, pub u128);

impl RegBlock {
/// Parses an element of a `reg` property.
/// Parses an element of a [`reg`](Reg) property.
///
/// Returns something only if the length of the value is a multiple of 4 and
/// none of the cell counts are bigger than 16 bytes each. The 16-byte limit
Expand All @@ -198,76 +198,141 @@ impl RegBlock {
}
}

/// Iterator over the _(child-bus-address, parent-bus-address, length)_ triplets of `ranges`' value.
#[derive(Clone, Debug, Default)]
/// Value of `ranges`.
#[derive(Clone, Copy, Debug, Default)]
pub struct Ranges<'dtb> {
value: &'dtb [u32],
address_cells: Cells,
size_cells: Cells,
}

impl<'dtb> Ranges<'dtb> {
/// Creates a new iterator over the _(address, length)_ pairs of the value.
pub fn new(value: &'dtb [u32], address_cells: Cells, size_cells: Cells) -> Result<Self> {
if address_cells > 4 || size_cells > 4 {
/// Creates a new iterator over the _(child-bus-address, parent-bus-address,
/// length)_ triplets of the value.
pub fn iter(
self,
child_address_cells: Cells,
child_size_cells: Cells,
) -> Result<RangesIter<'dtb>> {
RangesIter::new(
self.value,
child_address_cells,
self.address_cells,
child_size_cells,
)
}
}

impl<'dtb> DeserializeProperty<'dtb> for Ranges<'dtb> {
fn deserialize(blob_prop: Property<'dtb>, cx: NodeContext<'_>) -> Result<Self> {
if cx.address_cells > 4 {
return Err(Error::TooManyCells);
}
if value.len() % (address_cells * 2 + size_cells) as usize != 0 {
Ok(Self {
value: <&[u32]>::deserialize(blob_prop, cx)?,
address_cells: cx.address_cells,
})
}
}

/// Iterator over the _(child-bus-address, parent-bus-address, length)_ triplets
/// of [`ranges`](Ranges)' value.
///
/// # Examples
/// ```
/// # use devicetree::prop_value::{RangesBlock, RangesIter};
///
/// let data = [
/// 0x0200_0000, 0x0000_0000, 0x4000_0000,
/// 0x0000_0000, 0x4000_0000,
/// 0x0000_0000, 0x4000_0000,
/// ]
/// .map(u32::to_be);
/// let iter = RangesIter::new(&data, 3, 2, 2).unwrap();
/// let expected = RangesBlock(
/// 0x0200_0000_0000_0000_4000_0000,
/// 0x4000_0000,
/// 0x4000_0000,
/// );
/// assert_eq!(iter.collect::<Vec<_>>(), [expected]);
/// ```
#[derive(Clone, Debug)]
pub struct RangesIter<'dtb> {
value: &'dtb [u32],
child_address_cells: Cells,
address_cells: Cells,
child_size_cells: Cells,
}

impl<'dtb> RangesIter<'dtb> {
/// Creates a new iterator over the _(child-bus-address, parent-bus-address,
/// length)_ triplets of a [`ranges`](Ranges) value.
pub fn new(
value: &'dtb [u32],
child_address_cells: Cells,
address_cells: Cells,
child_size_cells: Cells,
) -> Result<Self> {
if child_address_cells > 4 || address_cells > 4 || child_size_cells > 4 {
return Err(Error::TooManyCells);
}
if value.len() as u32 % (child_address_cells + address_cells + child_size_cells) as u32 != 0
{
return Err(Error::UnsuitableProperty);
}

Ok(Self {
value,
child_address_cells,
address_cells,
size_cells,
child_size_cells,
})
}
}

impl<'dtb> DeserializeProperty<'dtb> for Ranges<'dtb> {
fn deserialize(blob_prop: Property<'dtb>, cx: NodeContext<'_>) -> Result<Self> {
if cx.address_cells > 4 || cx.size_cells > 4 {
return Err(Error::TooManyCells);
}
let value = <&[u32]>::deserialize(blob_prop, cx)?;
Self::new(value, cx.address_cells, cx.size_cells)
fn ranges_block_cells(&self) -> Cells {
self.child_address_cells + self.address_cells + self.child_size_cells
}
}

impl Iterator for Ranges<'_> {
impl Iterator for RangesIter<'_> {
type Item = RangesBlock;

fn next(&mut self) -> Option<Self::Item> {
RangesBlock::parse(&mut self.value, self.address_cells, self.size_cells)
RangesBlock::parse(
&mut self.value,
self.child_address_cells,
self.address_cells,
self.child_size_cells,
)
}

fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.value.len() / (self.address_cells * 2 + self.size_cells) as usize;
(len, Some(len))
let len = self.value.len() as u32 / self.ranges_block_cells() as u32;
(len as usize, Some(len as usize))
}

fn nth(&mut self, n: usize) -> Option<RangesBlock> {
let idx = usize::checked_mul(n, (self.address_cells * 2 + self.size_cells) as usize)?;
self.value = self.value.get(idx..)?;
let idx = u32::checked_mul(n as u32, self.ranges_block_cells() as u32)?;
self.value = self.value.get(idx as usize..)?;
self.next()
}
}

impl DoubleEndedIterator for Ranges<'_> {
impl DoubleEndedIterator for RangesIter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
let length = util::parse_cells_back(&mut self.value, self.size_cells)?;
let length = util::parse_cells_back(&mut self.value, self.child_size_cells)?;
let parent_bus_address =
util::parse_cells_back(&mut self.value, self.address_cells).unwrap();
let child_bus_address =
util::parse_cells_back(&mut self.value, self.address_cells).unwrap();
util::parse_cells_back(&mut self.value, self.child_address_cells).unwrap();
Some(RangesBlock(child_bus_address, parent_bus_address, length))
}
}

impl ExactSizeIterator for Ranges<'_> {}
impl FusedIterator for Ranges<'_> {}
impl ExactSizeIterator for RangesIter<'_> {}
impl FusedIterator for RangesIter<'_> {}

/// _(child-bus-address, parent-bus-address, length)_ triplets in [`Ranges`].
/// _(child-bus-address, parent-bus-address, length)_ triplets in
/// [`ranges`](Ranges). Obtained from [`RangesIter`].
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RangesBlock(pub u128, pub u128, pub u128);

Expand All @@ -278,10 +343,15 @@ impl RangesBlock {
/// none of the cell counts are bigger than 16 bytes each. The 16-byte limit
/// is not part of the spec. The fields each default to 0 if zero cells are
/// to be parsed.
pub fn parse(bytes: &mut &[u32], address_cells: Cells, size_cells: Cells) -> Option<Self> {
let child_bus_address = util::parse_cells(bytes, address_cells)?;
pub fn parse(
bytes: &mut &[u32],
child_address_cells: Cells,
address_cells: Cells,
child_size_cells: Cells,
) -> Option<Self> {
let child_bus_address = util::parse_cells(bytes, child_address_cells)?;
let parent_bus_address = util::parse_cells(bytes, address_cells)?;
let length = util::parse_cells(bytes, size_cells)?;
let length = util::parse_cells(bytes, child_size_cells)?;
Some(Self(child_bus_address, parent_bus_address, length))
}
}
Expand Down
20 changes: 20 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,23 @@ fn from_ptr() {
.unwrap();
assert_eq!(original.blob().len(), from_ptr.blob().len());
}

#[test]
fn reg_value() {
#[derive(Default, DeserializeNode)]
struct SocNode<'dtb> {
#[dt_child]
spi: SpiNode<'dtb>,
}

#[derive(Default, DeserializeNode)]
struct SpiNode<'dtb> {
reg: prop_value::Reg<'dtb>,
}

let soc_node = dt().get_node_strict(&["soc"]).unwrap().unwrap();
let (soc_node, _) = SocNode::deserialize(&soc_node, NodeContext::default()).unwrap();
let mut reg = soc_node.spi.reg;
assert_eq!(reg.next(), Some(RegBlock(0x7e20_4000, 0x1000)));
assert!(reg.next().is_none());
}

0 comments on commit c4de8bf

Please sign in to comment.