fdt_edit/
ctx.rs

1use alloc::{collections::BTreeMap, string::String, vec::Vec};
2
3use fdt_raw::{Phandle, Status};
4
5use crate::{Node, RangesEntry};
6
7// ============================================================================
8// FDT 上下文
9// ============================================================================
10
11/// 遍历上下文,存储从根到当前节点的父节点引用栈
12#[derive(Clone, Default)]
13pub struct Context<'a> {
14    /// 父节点引用栈(从根节点到当前节点的父节点)
15    /// 栈底是根节点,栈顶是当前节点的直接父节点
16    pub parents: Vec<&'a Node>,
17
18    /// phandle 到节点引用的映射
19    /// 用于通过 phandle 快速查找节点(如中断父节点)
20    pub phandle_map: BTreeMap<Phandle, &'a Node>,
21}
22
23impl<'a> Context<'a> {
24    /// 创建新的上下文
25    pub fn new() -> Self {
26        Self::default()
27    }
28
29    pub fn current_path(&self) -> String {
30        self.parents
31            .iter()
32            .map(|n| n.name())
33            .collect::<Vec<_>>()
34            .join("/")
35    }
36
37    /// 创建用于根节点的上下文
38    pub fn for_root() -> Self {
39        Self::default()
40    }
41
42    /// 获取当前深度(父节点数量 + 1)
43    pub fn depth(&self) -> usize {
44        self.parents.len() + 1
45    }
46
47    /// 获取直接父节点
48    pub fn parent(&self) -> Option<&'a Node> {
49        self.parents.last().copied()
50    }
51
52    /// 获取父节点的 #address-cells
53    /// 优先从直接父节点获取,否则返回默认值 2
54    pub fn parent_address_cells(&self) -> u32 {
55        self.parent().and_then(|p| p.address_cells()).unwrap_or(2)
56    }
57
58    /// 获取父节点的 #size-cells
59    /// 优先从直接父节点获取,否则返回默认值 1
60    pub fn parent_size_cells(&self) -> u32 {
61        self.parent().and_then(|p| p.size_cells()).unwrap_or(1)
62    }
63
64    /// 查找中断父节点 phandle
65    /// 从当前父节点向上查找,返回最近的 interrupt-parent
66    pub fn interrupt_parent(&self) -> Option<Phandle> {
67        for parent in self.parents.iter().rev() {
68            if let Some(phandle) = parent.interrupt_parent() {
69                return Some(phandle);
70            }
71        }
72        None
73    }
74
75    /// 检查节点是否被禁用
76    /// 检查父节点栈中是否有任何节点被禁用
77    pub fn is_disabled(&self) -> bool {
78        for parent in &self.parents {
79            if matches!(parent.status(), Some(Status::Disabled)) {
80                return true;
81            }
82        }
83        false
84    }
85
86    /// 解析当前路径上所有父节点的 ranges,用于地址转换
87    /// 返回从根到父节点的 ranges 栈
88    pub fn collect_ranges(&self) -> Vec<Vec<RangesEntry>> {
89        let mut ranges_stack = Vec::new();
90        let mut prev_address_cells = 2; // 根节点默认
91
92        for parent in &self.parents {
93            if let Some(ranges) = parent.ranges(prev_address_cells) {
94                ranges_stack.push(ranges);
95            }
96            // 更新 address cells 为当前节点的值,供下一级使用
97            prev_address_cells = parent.address_cells().unwrap_or(2);
98        }
99
100        ranges_stack
101    }
102
103    /// 获取最近一层的 ranges(用于当前节点的地址转换)
104    pub fn current_ranges(&self) -> Option<Vec<RangesEntry>> {
105        // 需要父节点来获取 ranges
106        if self.parents.is_empty() {
107            return None;
108        }
109
110        let parent = self.parents.last()?;
111
112        // 获取父节点的父节点的 address_cells
113        let grandparent_address_cells = if self.parents.len() >= 2 {
114            self.parents[self.parents.len() - 2]
115                .address_cells()
116                .unwrap_or(2)
117        } else {
118            2 // 根节点默认
119        };
120        parent.ranges(grandparent_address_cells)
121    }
122
123    pub fn push(&mut self, node: &'a Node) {
124        self.parents.push(node);
125    }
126
127    /// 通过 phandle 查找节点
128    pub fn find_by_phandle(&self, phandle: Phandle) -> Option<&'a Node> {
129        self.phandle_map.get(&phandle).copied()
130    }
131
132    /// 从 Fdt 构建 phandle 映射
133    pub fn build_phandle_map_from_node(node: &'a Node, map: &mut BTreeMap<Phandle, &'a Node>) {
134        if let Some(phandle) = node.phandle() {
135            map.insert(phandle, node);
136        }
137        for child in node.children() {
138            Self::build_phandle_map_from_node(child, map);
139        }
140    }
141}