fdt_parser/base/node/
chosen.rs

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