fdt_parser/cache/node/
chosen.rs1use 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 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 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 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 let earlycon = bootargs
58 .split_ascii_whitespace()
59 .find(|arg| arg.contains("earlycon"))?;
60
61 let mut tmp = earlycon.split('=');
62 let _ = tmp.next()?; let values = tmp.next()?;
64
65 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 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 let mut parts = values.split(',');
100 let _name = parts.next(); let _addr_part = parts.next(); let params = if let Some(param) = parts.next() {
103 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 Node(super::super::Node),
143 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}