use crate::{
cell_collector::{BuildCellCollector, CellCollector, CollectCellsError},
parsing::{aligned::AlignedParser, NoPanic, Panic, ParserWithMode},
properties::{
cells::{CellSizes, SizeCells},
reg::Reg,
Compatible,
},
FdtError,
};
use super::{AsNode, FallibleNode, NodeChildrenIter, NodeName};
#[derive(Debug, Clone, Copy)]
pub struct Memory<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
pub(crate) node: FallibleNode<'a, P>,
}
impl<'a, P: ParserWithMode<'a>> Memory<'a, P> {
#[track_caller]
pub fn reg(&self) -> P::Output<Reg<'a>> {
P::to_output(self.node.reg().and_then(|m| m.ok_or(FdtError::MissingRequiredNode("reg"))))
}
#[track_caller]
pub fn initial_mapped_area(&self) -> P::Output<Option<MappedArea>> {
P::to_output(crate::tryblock!({
match self.node.properties()?.find("initial-mapped-area")? {
Some(prop) => {
let value = prop.value;
if value.len() != (8 + 8 + 4) {
return Err(FdtError::InvalidPropertyValue);
}
Ok(Some(MappedArea {
effective_address: u64::from_be_bytes(value[0..8].try_into().unwrap()),
physical_address: u64::from_be_bytes(value[8..16].try_into().unwrap()),
size: u32::from_be_bytes(value[16..20].try_into().unwrap()),
}))
}
None => Ok(None),
}
}))
}
#[track_caller]
pub fn hotpluggable(&self) -> P::Output<bool> {
P::to_output(crate::tryblock!({ Ok(self.node.properties()?.find("hotpluggable")?.is_some()) }))
}
}
impl<'a, P: ParserWithMode<'a>> AsNode<'a, P> for Memory<'a, P> {
fn as_node(&self) -> super::Node<'a, P> {
self.node.alt()
}
}
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MappedArea {
pub effective_address: u64,
pub physical_address: u64,
pub size: u32,
}
pub struct ReservedMemory<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
pub(crate) node: FallibleNode<'a, P>,
}
impl<'a, P: ParserWithMode<'a>> ReservedMemory<'a, P> {
#[inline]
#[track_caller]
#[allow(missing_docs)]
pub fn cell_sizes(&self) -> P::Output<CellSizes> {
P::to_output(
self.node
.property::<CellSizes>()
.and_then(|c| c.ok_or(FdtError::MissingRequiredNode("#address-cells/#size-cells"))),
)
}
#[inline]
#[track_caller]
#[allow(missing_docs)]
pub fn children(&self) -> P::Output<ReservedMemoryChildrenIter<'a, P>> {
P::to_output(crate::tryblock!({ Ok(ReservedMemoryChildrenIter { children: self.node.children()?.iter() }) }))
}
}
impl<'a, P: ParserWithMode<'a>> AsNode<'a, P> for ReservedMemory<'a, P> {
fn as_node(&self) -> super::Node<'a, P> {
self.node.alt()
}
}
#[allow(missing_docs)]
pub struct ReservedMemoryChildrenIter<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
children: NodeChildrenIter<'a, (P::Parser, NoPanic)>,
}
impl<'a, P: ParserWithMode<'a>> Iterator for ReservedMemoryChildrenIter<'a, P> {
type Item = P::Output<ReservedMemoryChild<'a, P>>;
#[track_caller]
fn next(&mut self) -> Option<Self::Item> {
match self.children.next()? {
Ok(node) => Some(P::to_output(Ok(ReservedMemoryChild { node }))),
Err(e) => Some(P::to_output(Err(e))),
}
}
}
#[allow(missing_docs)]
pub struct ReservedMemoryChild<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
node: FallibleNode<'a, P>,
}
impl<'a, P: ParserWithMode<'a>> ReservedMemoryChild<'a, P> {
#[allow(missing_docs)]
pub fn name(&self) -> P::Output<NodeName<'a>> {
P::to_output(self.node.name())
}
pub fn reg(&self) -> P::Output<Option<Reg<'a>>> {
P::to_output(self.node.reg())
}
pub fn size<C: CellCollector>(&self) -> P::Output<Option<Result<C::Output, CollectCellsError>>> {
P::to_output(crate::tryblock!({
let Some(size) = self.node.properties()?.find("size")? else {
return Ok(None);
};
let size_cells = self.node.parent().unwrap().property::<SizeCells>()?.unwrap_or(SizeCells(1));
if size.value.len() % size_cells.0 != 0 {
return Err(FdtError::InvalidPropertyValue);
}
let mut builder = <C as CellCollector>::Builder::default();
for component in size.value.chunks_exact(4) {
if builder.push(u32::from_be_bytes(component.try_into().unwrap())).is_err() {
return Ok(Some(Err(CollectCellsError)));
}
}
Ok(Some(Ok(C::map(builder.finish()))))
}))
}
pub fn alignment<C: CellCollector>(&self) -> P::Output<Option<Result<C::Output, CollectCellsError>>> {
P::to_output(crate::tryblock!({
let Some(alignment) = self.node.properties()?.find("alignment")? else {
return Ok(None);
};
let size_cells = self.node.parent().unwrap().property::<SizeCells>()?.unwrap_or(SizeCells(1));
if alignment.value.len() % size_cells.0 != 0 {
return Err(FdtError::InvalidPropertyValue);
}
let mut builder = <C as CellCollector>::Builder::default();
for component in alignment.value.chunks_exact(4) {
if builder.push(u32::from_be_bytes(component.try_into().unwrap())).is_err() {
return Ok(Some(Err(CollectCellsError)));
}
}
Ok(Some(Ok(C::map(builder.finish()))))
}))
}
pub fn compatible(&self) -> P::Output<Option<Compatible<'a>>> {
P::to_output(self.node.property::<Compatible<'a>>())
}
pub fn no_map(&self) -> P::Output<bool> {
P::to_output(self.node.properties().and_then(|p| p.find("no-map").map(|p| p.is_some())))
}
pub fn reusable(&self) -> P::Output<bool> {
P::to_output(self.node.properties().and_then(|p| p.find("no-map").map(|p| p.is_some())))
}
#[cfg(feature = "linux-dt-bindings")]
pub fn cma_default(&self) -> P::Output<bool> {
P::to_output(self.node.properties().and_then(|p| p.find("no-map").map(|p| p.is_some())))
}
#[cfg(feature = "linux-dt-bindings")]
pub fn dma_default(&self) -> P::Output<bool> {
P::to_output(self.node.properties().and_then(|p| p.find("no-map").map(|p| p.is_some())))
}
}
impl<'a, P: ParserWithMode<'a>> AsNode<'a, P> for ReservedMemoryChild<'a, P> {
fn as_node(&self) -> super::Node<'a, P> {
self.node.alt()
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MemoryRegion {
#[allow(missing_docs)]
pub starting_address: u64,
#[allow(missing_docs)]
pub size: Option<usize>,
}