fdt_parser/cache/node/
chosen.rs

1use core::{fmt::Debug, ops::Deref};
2
3use crate::cache::node::NodeBase;
4use alloc::{string::String, string::ToString};
5
6#[derive(Clone)]
7pub struct Chosen {
8    node: NodeBase,
9}
10
11impl Chosen {
12    pub(crate) fn new(node: NodeBase) -> Self {
13        Chosen { node }
14    }
15
16    /// Contains the bootargs, if they exist
17    pub fn bootargs(&self) -> Option<String> {
18        self.node
19            .find_property("bootargs")
20            .and_then(|prop| prop.str().ok())
21            .map(|s| s.to_string())
22    }
23
24    /// Searches for the node representing `stdout`, if the property exists,
25    /// attempting to resolve aliases if the node name doesn't exist as-is
26    pub fn stdout(&self) -> Option<Stdout> {
27        let prop = self.node.find_property("stdout-path")?;
28        let path = prop.str().ok()?;
29
30        let mut sp = path.split(':');
31        let name = sp.next()?;
32        let params = sp.next();
33
34        // 尝试在cache中找到节点
35        if let Some(node) = self.node.fdt.get_node_by_path(name) {
36            Some(Stdout {
37                params: params.map(|s| s.to_string()),
38                node,
39            })
40        } else {
41            None
42        }
43    }
44
45    pub fn debugcon(&self) -> Option<DebugConCache> {
46        if let Some(stdout) = self.stdout() {
47            Some(DebugConCache::Node(stdout.node))
48        } else {
49            self.fdt_bootargs_find_debugcon_info()
50        }
51    }
52
53    fn fdt_bootargs_find_debugcon_info(&self) -> Option<DebugConCache> {
54        let bootargs = self.bootargs()?;
55
56        // 查找 earlycon 参数
57        let earlycon = bootargs
58            .split_ascii_whitespace()
59            .find(|arg| arg.contains("earlycon"))?;
60
61        let mut tmp = earlycon.split('=');
62        let _ = tmp.next()?; // 跳过 "earlycon"
63        let values = tmp.next()?;
64
65        // 解析所有参数
66        let mut params_iter = values.split(',');
67        let name = params_iter.next()?;
68
69        if !name.contains("uart") {
70            return None;
71        }
72
73        let param2 = params_iter.next()?;
74
75        let addr_str = if param2.contains("0x") {
76            param2
77        } else {
78            params_iter.next()?
79        };
80
81        let mmio = u64::from_str_radix(addr_str.trim_start_matches("0x"), 16).ok()?;
82
83        // 先尝试在cache中查找对应节点
84        let all_nodes = self.node.fdt.all_nodes();
85        for node in all_nodes {
86            let Ok(reg) = node.reg() else {
87                continue;
88            };
89
90            for address in reg {
91                if address.address == mmio {
92                    return Some(DebugConCache::Node(node));
93                }
94            }
95        }
96
97        // 如果找不到对应节点,返回解析出的earlycon信息
98        // 重新分割字符串以获取剩余参数
99        let mut parts = values.split(',');
100        let _name = parts.next(); // 跳过name
101        let _addr_part = parts.next(); // 跳过地址部分
102        let params = if let Some(param) = parts.next() {
103            // 获取第一个剩余参数的位置,然后取剩余所有内容
104            let param_start = values.find(param).unwrap_or(0);
105            if param_start > 0 {
106                Some(values[param_start..].to_string())
107            } else {
108                Some(param.to_string())
109            }
110        } else {
111            None
112        };
113
114        Some(DebugConCache::EarlyConInfo {
115            name: name.to_string(),
116            mmio,
117            params,
118        })
119    }
120}
121
122impl Debug for Chosen {
123    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
124        f.debug_struct("Chosen")
125            .field("bootargs", &self.bootargs())
126            .field("stdout", &self.stdout())
127            .finish()
128    }
129}
130
131impl Deref for Chosen {
132    type Target = NodeBase;
133
134    fn deref(&self) -> &Self::Target {
135        &self.node
136    }
137}
138
139#[derive(Clone, Debug)]
140pub enum DebugConCache {
141    /// 找到了对应的设备树节点
142    Node(super::super::Node),
143    /// 仅在bootargs中找到earlycon参数,包含解析出的信息
144    EarlyConInfo {
145        name: String,
146        mmio: u64,
147        params: Option<String>,
148    },
149}
150
151#[derive(Clone)]
152pub struct Stdout {
153    pub params: Option<String>,
154    pub node: super::super::Node,
155}
156
157impl Stdout {}
158
159impl Debug for Stdout {
160    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
161        f.debug_struct("Stdout")
162            .field("name", &self.node.name())
163            .field("params", &self.params)
164            .finish()
165    }
166}