use crate::node::{CellSizes, FdtNode, NodeProperty};
use crate::parsing::{BigEndianU32, BigEndianU64, FdtData};
use crate::{Error, Fdt, Result};
#[derive(Debug, Clone, Copy)]
pub struct Chosen<'b, 'a: 'b> {
pub(crate) node: FdtNode<'b, 'a>,
}
impl<'b, 'a: 'b> Chosen<'b, 'a> {
pub fn bootargs(self) -> Option<&'a str> {
self.node.properties().find(|n| n.name == "bootargs").and_then(|n| n.as_str())
}
pub fn stdout(self) -> Option<StdInOutPath<'b, 'a>> {
self.node
.properties()
.find(|n| n.name == "stdout-path")
.and_then(|n| n.as_str())
.map(Self::split_stdinout_property)
.and_then(|(name, params)| {
self.node.header.find_node(name).map(|node| StdInOutPath::new(node, params))
})
}
pub fn stdin(self) -> Option<StdInOutPath<'b, 'a>> {
self.node
.properties()
.find(|n| n.name == "stdin-path")
.and_then(|n| n.as_str())
.map(Self::split_stdinout_property)
.and_then(|(name, params)| {
self.node.header.find_node(name).map(|node| StdInOutPath::new(node, params))
})
.or_else(|| self.stdout())
}
fn split_stdinout_property(property: &str) -> (&str, Option<&str>) {
property
.split_once(':')
.map_or_else(|| (property, None), |(name, params)| (name, Some(params)))
}
}
pub struct StdInOutPath<'b, 'a> {
pub(crate) node: FdtNode<'b, 'a>,
pub(crate) params: Option<&'a str>,
}
impl<'b, 'a> StdInOutPath<'b, 'a> {
fn new(node: FdtNode<'b, 'a>, params: Option<&'a str>) -> Self {
Self { node, params }
}
pub fn node(&self) -> FdtNode<'b, 'a> {
self.node
}
pub fn params(&self) -> Option<&'a str> {
self.params
}
}
#[derive(Debug, Clone, Copy)]
pub struct Root<'b, 'a: 'b> {
pub(crate) node: FdtNode<'b, 'a>,
}
impl<'b, 'a: 'b> Root<'b, 'a> {
pub fn cell_sizes(self) -> CellSizes {
self.node.cell_sizes()
}
pub fn model(self) -> &'a str {
self.node
.properties()
.find(|p| p.name == "model")
.and_then(|p| p.as_str())
.unwrap_or_default()
}
pub fn compatible(self) -> Compatible<'a> {
self.node.compatible().unwrap_or_default()
}
pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> + 'b {
self.node.properties()
}
pub fn property(self, name: &str) -> Option<NodeProperty<'a>> {
self.node.properties().find(|p| p.name == name)
}
}
#[derive(Debug, Clone, Copy)]
pub struct Aliases<'b, 'a: 'b> {
pub(crate) header: &'b Fdt<'a>,
pub(crate) node: FdtNode<'b, 'a>,
}
impl<'b, 'a: 'b> Aliases<'b, 'a> {
pub fn resolve(self, alias: &str) -> Option<&'a str> {
self.node.properties().find(|p| p.name == alias).and_then(|p| p.as_str())
}
pub fn resolve_node(self, alias: &str) -> Option<FdtNode<'b, 'a>> {
self.resolve(alias).and_then(|name| self.header.find_node(name))
}
pub fn all(self) -> impl Iterator<Item = (&'a str, &'a str)> + 'b {
self.node.properties().filter_map(|p| Some((p.name, p.as_str()?)))
}
}
#[derive(Debug, Clone, Copy)]
pub struct Cpu<'b, 'a: 'b> {
pub(crate) parent: FdtNode<'b, 'a>,
pub(crate) node: FdtNode<'b, 'a>,
}
impl<'b, 'a: 'b> Cpu<'b, 'a> {
pub fn ids(self) -> Result<CpuIds<'a>> {
let reg = self.node.properties().find(|p| p.name == "reg").ok_or(Error::CpuNoReg)?;
let address_cells = self.node.parent_cell_sizes().address_cells.to_usize();
Ok(CpuIds { reg, address_cells })
}
pub fn clock_frequency(self) -> Result<usize> {
self.node
.properties()
.find(|p| p.name == "clock-frequency")
.or_else(|| self.parent.property("clock-frequency"))
.map(|p| match p.value.len() {
4 => Some(BigEndianU32::from_bytes(p.value)?.get() as usize),
8 => Some(BigEndianU64::from_bytes(p.value)?.get() as usize),
_ => None,
})
.ok_or(Error::BadCellSize(0))?
.ok_or(Error::CpuNoClockHz)
}
pub fn timebase_frequency(self) -> Result<usize> {
self.node
.properties()
.find(|p| p.name == "timebase-frequency")
.or_else(|| self.parent.property("timebase-frequency"))
.map(|p| match p.value.len() {
4 => Some(BigEndianU32::from_bytes(p.value)?.get() as usize),
8 => Some(BigEndianU64::from_bytes(p.value)?.get() as usize),
_ => None,
})
.ok_or(Error::BadCellSize(0))?
.ok_or(Error::CpuNoTimebaseHz)
}
pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> + 'b {
self.node.properties()
}
pub fn property(self, name: &str) -> Option<NodeProperty<'a>> {
self.node.properties().find(|p| p.name == name)
}
}
#[derive(Debug, Clone, Copy)]
pub struct CpuIds<'a> {
pub(crate) reg: NodeProperty<'a>,
pub(crate) address_cells: usize,
}
impl<'a> CpuIds<'a> {
pub fn first(self) -> Result<usize> {
match self.address_cells {
1 => Ok(BigEndianU32::from_bytes(self.reg.value).ok_or(Error::BadCell)?.get() as usize),
2 => Ok(BigEndianU64::from_bytes(self.reg.value).ok_or(Error::BadCell)?.get() as usize),
n => Err(Error::BadCellSize(n)),
}
}
pub fn all(self) -> impl Iterator<Item = usize> + 'a {
let mut vals = FdtData::new(self.reg.value);
core::iter::from_fn(move || match vals.remaining() {
[] => None,
_ => match self.address_cells {
1 => Some(vals.u32()?.get() as usize),
2 => Some(vals.u64()?.get() as usize),
_ => None,
},
})
}
}
#[derive(Clone, Copy, Debug)]
pub struct Compatible<'a> {
pub(crate) data: &'a [u8],
}
impl<'a> Compatible<'a> {
pub const fn new() -> Self {
Self { data: &[] }
}
pub fn first(self) -> Option<&'a str> {
self.all().next()
}
pub fn all(self) -> impl Iterator<Item = &'a str> {
let mut data =
core::str::from_utf8(self.data).ok().map(|s| s.trim_end_matches('\0').split('\0'));
core::iter::from_fn(move || match data.as_mut() {
Some(d) => d.next(),
None => None,
})
}
}
impl<'a> Default for Compatible<'a> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy)]
pub struct Memory<'b, 'a: 'b> {
pub(crate) node: FdtNode<'b, 'a>,
}
impl<'a> Memory<'_, 'a> {
pub fn regions(&self) -> impl Iterator<Item = MemoryRegion> + 'a {
self.node.reg()
}
pub fn initial_mapped_area(&self) -> Result<MappedArea> {
let init_mapped_area =
self.node.property("initial-mapped-area").ok_or(Error::MemoryNoInitialMapped)?;
let mut stream = FdtData::new(init_mapped_area.value);
let effective_address = stream.u64().ok_or(Error::MappedNoEffectiveAddr)?;
let physical_address = stream.u64().ok_or(Error::MappedNoPhysicalAddr)?;
let size = stream.u32().ok_or(Error::MappedNoSize)?;
Ok(MappedArea {
effective_address: effective_address.get() as usize,
physical_address: physical_address.get() as usize,
size: size.get() as usize,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct MappedArea {
pub effective_address: usize,
pub physical_address: usize,
pub size: usize,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MemoryRegion {
pub starting_address: *const u8,
pub size: Option<usize>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MemoryRange {
pub child_bus_address: usize,
pub child_bus_address_hi: u32,
pub parent_bus_address: usize,
pub size: usize,
}