use core::{
fmt::{self, Display, Formatter},
iter::FusedIterator,
};
use fallible_iterator::{DoubleEndedFallibleIterator, FallibleIterator};
use crate::{blob::Property, util, Cells, DeserializeProperty, Error, NodeContext, Result};
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AddressCells(pub Cells);
impl Default for AddressCells {
fn default() -> Self {
Self(2)
}
}
impl<'dtb> DeserializeProperty<'dtb> for AddressCells {
#[inline]
fn deserialize(blob_prop: Property<'dtb>, cx: NodeContext<'_>) -> Result<Self> {
let cells = u32::deserialize(blob_prop, cx)?;
if cells > 4 {
return Err(Error::TooManyCells);
}
Ok(Self(cells as u8))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SizeCells(pub Cells);
impl Default for SizeCells {
#[inline]
fn default() -> Self {
Self(1)
}
}
impl<'dtb> DeserializeProperty<'dtb> for SizeCells {
#[inline]
fn deserialize(blob_prop: Property<'dtb>, cx: NodeContext<'_>) -> Result<Self> {
let cells = u32::deserialize(blob_prop, cx)?;
if cells > 4 {
return Err(Error::TooManyCells);
}
Ok(Self(cells as u8))
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Status<'a> {
#[default]
Ok,
Disabled,
Reserved,
Fail,
FailCondition(&'a str),
}
impl<'dtb> DeserializeProperty<'dtb> for Status<'dtb> {
fn deserialize(blob_prop: Property<'dtb>, cx: NodeContext<'_>) -> Result<Self> {
<&str>::deserialize(blob_prop, cx)?.try_into()
}
}
impl<'a> TryFrom<&'a str> for Status<'a> {
type Error = Error;
fn try_from(string: &'a str) -> Result<Self, Self::Error> {
let ret = match string {
"okay" => Self::Ok,
"disabled" => Self::Disabled,
"reserved" => Self::Reserved,
"fail" => Self::Fail,
_ => Self::FailCondition(
string
.strip_prefix("fail-")
.ok_or(Error::UnsuitableProperty)?,
),
};
Ok(ret)
}
}
impl Display for Status<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match *self {
Self::Ok => f.write_str("okay"),
Self::Disabled => f.write_str("disabled"),
Self::Reserved => f.write_str("reserved"),
Self::Fail => f.write_str("fail"),
Self::FailCondition(condition) => write!(f, "fail-{condition}"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Strings<'a> {
value: &'a [u8],
}
impl<'a> Strings<'a> {
pub const EMPTY: Self = Self { value: &[] };
#[inline]
pub fn new(value: &'a [u8]) -> Option<Self> {
matches!(value, [.., 0]).then_some(Self { value })
}
}
impl<'dtb> DeserializeProperty<'dtb> for Strings<'dtb> {
fn deserialize(blob_prop: Property<'dtb>, _cx: NodeContext<'_>) -> Result<Self> {
Self::new(blob_prop.value()).ok_or(Error::UnsuitableProperty)
}
}
impl<'a> FallibleIterator for Strings<'a> {
type Item = &'a str;
type Error = Error;
fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
let Some(idx) = self.value.iter().position(|&b| b == 0) else {
return Ok(None);
};
let bytes = &self.value[..idx];
self.value = &self.value[idx + 1..];
let s = util::str_from_ascii(bytes).ok_or(Error::UnsuitableProperty)?;
Ok(Some(s))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
if self.value.is_empty() {
(0, Some(0))
} else {
(1, Some(self.value.len()))
}
}
}
impl<'a> DoubleEndedFallibleIterator for Strings<'a> {
fn next_back(&mut self) -> Result<Option<Self::Item>, Self::Error> {
let [value @ .., _] = self.value else {
return Ok(None);
};
let idx = value.iter().rposition(|&b| b == 0).map_or(0, |i| i + 1);
self.value = &self.value[..idx];
let s = util::str_from_ascii(&value[idx..]).ok_or(Error::UnsuitableProperty)?;
Ok(Some(s))
}
}
impl Default for Strings<'_> {
#[inline]
fn default() -> Self {
Self::EMPTY
}
}
#[derive(Clone, Debug, Default)]
pub struct Reg<'dtb> {
pub(crate) value: &'dtb [u32],
pub(crate) address_cells: Cells,
pub(crate) size_cells: Cells,
}
impl<'dtb> Reg<'dtb> {
pub fn new(value: &'dtb [u32], address_cells: Cells, size_cells: Cells) -> Result<Self> {
if address_cells > 4 || size_cells > 4 {
return Err(Error::TooManyCells);
}
if value.len() % (address_cells + size_cells) as usize != 0 {
return Err(Error::UnsuitableProperty);
}
Ok(Self {
value,
address_cells,
size_cells,
})
}
}
impl<'dtb> DeserializeProperty<'dtb> for Reg<'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)
}
}
impl Iterator for Reg<'_> {
type Item = RegBlock;
fn next(&mut self) -> Option<Self::Item> {
RegBlock::parse(&mut self.value, self.address_cells, self.size_cells)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.value.len() / (self.address_cells + self.size_cells) as usize;
(len, Some(len))
}
fn nth(&mut self, n: usize) -> Option<RegBlock> {
let idx = usize::checked_mul(n, (self.address_cells + self.size_cells) as usize)?;
self.value = self.value.get(idx..)?;
self.next()
}
}
impl DoubleEndedIterator for Reg<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
let size = util::parse_cells_back(&mut self.value, self.size_cells)?;
let address = util::parse_cells_back(&mut self.value, self.address_cells).unwrap();
Some(RegBlock(address, size))
}
}
impl ExactSizeIterator for Reg<'_> {}
impl FusedIterator for Reg<'_> {}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RegBlock(pub u128, pub u128);
impl RegBlock {
pub fn parse(bytes: &mut &[u32], address_cells: Cells, size_cells: Cells) -> Option<Self> {
let address = util::parse_cells(bytes, address_cells)?;
let size = util::parse_cells(bytes, size_cells)?;
Some(Self(address, size))
}
#[inline]
pub fn end_address(self) -> Result<u128> {
let Self(address, size) = self;
u128::checked_add(address, size).ok_or(Error::IntOverflow)
}
pub fn map_to_parent(self, range: RangesBlock) -> Result<Option<Self>> {
let Self(child_address, size) = self;
let Some(parent_address) = range.map_to_parent(child_address)? else {
return Ok(None);
};
Ok((self.end_address()? <= range.child_end_address()?)
.then_some(Self(parent_address, size)))
}
pub fn map_to_child(self, range: RangesBlock) -> Result<Option<Self>> {
let Self(parent_address, size) = self;
let Some(child_address) = range.map_to_child(parent_address)? else {
return Ok(None);
};
Ok((self.end_address()? <= range.parent_end_address()?)
.then_some(Self(child_address, size)))
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Ranges<'dtb> {
value: &'dtb [u32],
address_cells: Cells,
}
impl<'dtb> Ranges<'dtb> {
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);
}
Ok(Self {
value: <&[u32]>::deserialize(blob_prop, cx)?,
address_cells: cx.address_cells,
})
}
}
#[derive(Clone, Debug)]
pub struct RangesIter<'dtb> {
pub(crate) value: &'dtb [u32],
pub(crate) child_address_cells: Cells,
pub(crate) address_cells: Cells,
pub(crate) child_size_cells: Cells,
}
impl<'dtb> RangesIter<'dtb> {
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() % (child_address_cells + address_cells + child_size_cells) as usize != 0 {
return Err(Error::UnsuitableProperty);
}
Ok(Self {
value,
child_address_cells,
address_cells,
child_size_cells,
})
}
fn ranges_block_cells(&self) -> Cells {
self.child_address_cells + self.address_cells + self.child_size_cells
}
}
impl Iterator for RangesIter<'_> {
type Item = RangesBlock;
fn next(&mut self) -> Option<Self::Item> {
RangesBlock::parse(
&mut self.value,
self.child_address_cells,
self.address_cells,
self.child_size_cells,
)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.value.len() / self.ranges_block_cells() as usize;
(len, Some(len))
}
fn nth(&mut self, n: usize) -> Option<RangesBlock> {
let idx = usize::checked_mul(n, self.ranges_block_cells() as usize)?;
self.value = self.value.get(idx..)?;
self.next()
}
}
impl DoubleEndedIterator for RangesIter<'_> {
fn next_back(&mut self) -> Option<Self::Item> {
let size = 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.child_address_cells).unwrap();
Some(RangesBlock(child_bus_address, parent_bus_address, size))
}
}
impl ExactSizeIterator for RangesIter<'_> {}
impl FusedIterator for RangesIter<'_> {}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RangesBlock(pub u128, pub u128, pub u128);
impl RangesBlock {
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 size = util::parse_cells(bytes, child_size_cells)?;
Some(Self(child_bus_address, parent_bus_address, size))
}
#[inline]
pub fn child_end_address(self) -> Result<u128> {
let Self(child_bus_address, _, size) = self;
u128::checked_add(child_bus_address, size).ok_or(Error::IntOverflow)
}
#[inline]
pub fn parent_end_address(self) -> Result<u128> {
let Self(_, parent_bus_address, size) = self;
u128::checked_add(parent_bus_address, size).ok_or(Error::IntOverflow)
}
pub fn map_to_parent(self, child_address: u128) -> Result<Option<u128>> {
let Self(child_bus_address, parent_bus_address, size) = self;
match u128::checked_sub(child_address, child_bus_address) {
Some(offset) if offset < size => u128::checked_add(parent_bus_address, offset)
.map_or(Err(Error::IntOverflow), |a| Ok(Some(a))),
_ => Ok(None),
}
}
pub fn map_to_child(self, parent_address: u128) -> Result<Option<u128>> {
let Self(child_bus_address, parent_bus_address, size) = self;
match u128::checked_sub(parent_address, parent_bus_address) {
Some(offset) if offset < size => u128::checked_add(child_bus_address, offset)
.map_or(Err(Error::IntOverflow), |a| Ok(Some(a))),
_ => Ok(None),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct InitialMappedArea {
effective_address: u64,
physical_address: u64,
size: u32,
}
impl<'dtb> DeserializeProperty<'dtb> for InitialMappedArea {
fn deserialize(blob_prop: Property<'dtb>, cx: NodeContext<'_>) -> Result<Self> {
let mut bytes = <&[u32]>::deserialize(blob_prop, cx)?;
if bytes.len() != 5 {
return Err(Error::UnsuitableProperty);
}
Ok(Self {
effective_address: util::parse_cells(&mut bytes, 2).unwrap() as u64,
physical_address: util::parse_cells(&mut bytes, 2).unwrap() as u64,
size: util::parse_cells(&mut bytes, 1).unwrap() as u32,
})
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct SmallU64(pub u64);
impl<'dtb> DeserializeProperty<'dtb> for SmallU64 {
fn deserialize(blob_prop: Property<'dtb>, _cx: NodeContext<'_>) -> Result<Self> {
let value = blob_prop.value();
if let Ok(arr) = <[u8; 4]>::try_from(value) {
Ok(Self(u32::from_be_bytes(arr) as u64))
} else if let Ok(arr) = <[u8; 8]>::try_from(value) {
Ok(Self(u64::from_be_bytes(arr)))
} else {
Err(Error::UnsuitableProperty)
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceTypeMemory;
impl<'dtb> DeserializeProperty<'dtb> for DeviceTypeMemory {
fn deserialize(blob_prop: Property<'dtb>, _cx: NodeContext<'_>) -> Result<Self> {
if blob_prop.value() == b"memory\0" {
Ok(Self)
} else {
Err(Error::InvalidDeviceType)
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct DeviceTypeCpu;
impl<'dtb> DeserializeProperty<'dtb> for DeviceTypeCpu {
fn deserialize(blob_prop: Property<'dtb>, _cx: NodeContext<'_>) -> Result<Self> {
if blob_prop.value() == b"cpu\0" {
Ok(Self)
} else {
Err(Error::InvalidDeviceType)
}
}
}