moa_fdt 0.1.4

FDT (Flattened Device Tree) 零拷贝解析器
Documentation
// Based on fdt 0.1.5 (MPL-2.0) by repnop, with modifications:
// - Single lifetime
// - stdout_path returns &str instead of resolving to FdtNode

use crate::node::{Compatible, FdtNode, MemoryRegion, NodeProperty};

/// `/chosen` 节点
#[derive(Debug, Clone, Copy)]
pub struct Chosen<'a> {
    pub(crate) node: FdtNode<'a>,
}

impl<'a> Chosen<'a> {
    /// `bootargs` 属性值
    #[inline(always)]
    pub fn bootargs(self) -> Option<&'a str> {
        self.node.property("bootargs")?.as_str()
    }

    /// `stdout-path` 属性值
    #[inline(always)]
    pub fn stdout_path(self) -> Option<&'a str> {
        self.node.property("stdout-path")?.as_str()
    }

    /// `stdin-path` 属性值
    #[inline(always)]
    pub fn stdin_path(self) -> Option<&'a str> {
        self.node.property("stdin-path")?.as_str()
    }
}

/// 根节点 (`/`)
#[derive(Debug, Clone, Copy)]
pub struct Root<'a> {
    pub(crate) node: FdtNode<'a>,
}

impl<'a> Root<'a> {
    /// `model` 属性
    #[inline(always)]
    pub fn model(self) -> Option<&'a str> {
        self.node.property("model")?.as_str()
    }

    /// `compatible` 属性
    #[inline(always)]
    pub fn compatible(self) -> Option<Compatible<'a>> {
        self.node.compatible()
    }

    /// 遍历所有属性
    #[inline(always)]
    pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> {
        self.node.properties()
    }

    /// 获取底层节点
    #[inline(always)]
    pub fn node(self) -> FdtNode<'a> {
        self.node
    }
}

/// `/cpus/cpu@*` 节点
#[derive(Debug, Clone, Copy)]
pub struct Cpu<'a> {
    pub(crate) parent: FdtNode<'a>,
    pub(crate) node: FdtNode<'a>,
}

impl<'a> Cpu<'a> {
    /// CPU 的 reg ID(RISC-V 为 hart-id,AArch64 为 MPIDR)
    #[moa_sec_macros::init]
    #[allow(clippy::cast_possible_truncation)]
    pub fn id(self) -> Option<usize> {
        let address_cells = self.node.parent_cell_sizes().address_cells;
        let prop = self.node.property("reg")?;
        let mut stream = crate::parsing::FdtData::new(prop.value);
        match address_cells {
            1 => Some(stream.u32()? as usize),
            2 => Some(stream.u64()? as usize),
            _ => None,
        }
    }

    /// `clock-frequency` 属性
    #[inline(always)]
    #[allow(clippy::cast_possible_truncation)]
    pub fn clock_frequency(self) -> Option<usize> {
        let prop = self
            .node
            .property("clock-frequency")
            .or_else(|| self.parent.property("clock-frequency"))?;
        prop.as_usize()
    }

    /// `timebase-frequency` 属性
    #[inline(always)]
    #[allow(clippy::cast_possible_truncation)]
    pub fn timebase_frequency(self) -> Option<usize> {
        let prop = self
            .node
            .property("timebase-frequency")
            .or_else(|| self.parent.property("timebase-frequency"))?;
        prop.as_usize()
    }

    /// 遍历所有属性
    #[inline(always)]
    pub fn properties(self) -> impl Iterator<Item = NodeProperty<'a>> {
        self.node.properties()
    }

    /// 获取底层节点
    #[inline(always)]
    pub fn node(self) -> FdtNode<'a> {
        self.node
    }
}

/// 所有 `/memory` 节点的聚合视图
#[derive(Clone, Copy)]
pub struct Memory<'a> {
    pub(crate) structs: &'a [u8],
    pub(crate) strings: &'a [u8],
}

impl<'a> Memory<'a> {
    /// 内存区域迭代器(聚合所有 `memory` / `memory@*` 节点的 reg)
    #[inline(always)]
    pub fn regions(self) -> MemoryRegions<'a> {
        MemoryRegions {
            nodes: crate::node::AllNodes::new(self.structs, self.strings),
            current: None,
        }
    }
}

/// 内存区域迭代器
pub struct MemoryRegions<'a> {
    nodes: crate::node::AllNodes<'a>,
    current: Option<crate::node::RegIter<'a>>,
}

impl Iterator for MemoryRegions<'_> {
    type Item = MemoryRegion;

    #[moa_sec_macros::init]
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(ref mut reg) = self.current {
                if let Some(region) = reg.next() {
                    return Some(region);
                }
                self.current = None;
            }
            let n = self.nodes.next()?;
            if n.name == "memory" || n.name.starts_with("memory@") {
                self.current = n.reg();
            }
        }
    }
}