use core::{fmt::Debug, ops::Deref};
use crate::cache::node::NodeBase;
use alloc::{string::String, string::ToString};
#[derive(Clone)]
pub struct Chosen {
node: NodeBase,
}
impl Chosen {
pub(crate) fn new(node: NodeBase) -> Self {
Chosen { node }
}
pub fn bootargs(&self) -> Option<String> {
self.node
.find_property("bootargs")
.and_then(|prop| prop.str().ok())
.map(|s| s.to_string())
}
pub fn stdout(&self) -> Option<Stdout> {
let prop = self.node.find_property("stdout-path")?;
let path = prop.str().ok()?;
let mut sp = path.split(':');
let name = sp.next()?;
let params = sp.next();
if let Some(node) = self.node.fdt.get_node_by_path(name) {
Some(Stdout {
params: params.map(|s| s.to_string()),
node,
})
} else {
None
}
}
pub fn debugcon(&self) -> Option<DebugConCache> {
if let Some(stdout) = self.stdout() {
Some(DebugConCache::Node(stdout.node))
} else {
self.fdt_bootargs_find_debugcon_info()
}
}
fn fdt_bootargs_find_debugcon_info(&self) -> Option<DebugConCache> {
let bootargs = self.bootargs()?;
let earlycon = bootargs
.split_ascii_whitespace()
.find(|arg| arg.contains("earlycon"))?;
let mut tmp = earlycon.split('=');
let _ = tmp.next()?; let values = tmp.next()?;
let mut params_iter = values.split(',');
let name = params_iter.next()?;
if !name.contains("uart") {
return None;
}
let param2 = params_iter.next()?;
let addr_str = if param2.contains("0x") {
param2
} else {
params_iter.next()?
};
let mmio = u64::from_str_radix(addr_str.trim_start_matches("0x"), 16).ok()?;
let all_nodes = self.node.fdt.all_nodes();
for node in all_nodes {
let Ok(reg) = node.reg() else {
continue;
};
for address in reg {
if address.address == mmio {
return Some(DebugConCache::Node(node));
}
}
}
let mut parts = values.split(',');
let _name = parts.next(); let _addr_part = parts.next(); let params = if let Some(param) = parts.next() {
let param_start = values.find(param).unwrap_or(0);
if param_start > 0 {
Some(values[param_start..].to_string())
} else {
Some(param.to_string())
}
} else {
None
};
Some(DebugConCache::EarlyConInfo {
name: name.to_string(),
mmio,
params,
})
}
}
impl Debug for Chosen {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Chosen")
.field("bootargs", &self.bootargs())
.field("stdout", &self.stdout())
.finish()
}
}
impl Deref for Chosen {
type Target = NodeBase;
fn deref(&self) -> &Self::Target {
&self.node
}
}
#[derive(Clone, Debug)]
pub enum DebugConCache {
Node(super::super::Node),
EarlyConInfo {
name: String,
mmio: u64,
params: Option<String>,
},
}
#[derive(Clone)]
pub struct Stdout {
pub params: Option<String>,
pub node: super::super::Node,
}
impl Stdout {}
impl Debug for Stdout {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Stdout")
.field("name", &self.node.name())
.field("params", &self.params)
.finish()
}
}