use core::ptr::NonNull;
use fdt_parser::{Fdt, Status};
use pie_boot_if::{MemoryRegion, MemoryRegionKind};
use crate::{
boot_info,
common::{self, cpu::CPU_NUM},
lazy_static::LazyStatic,
mem::phys_to_virt,
};
#[unsafe(link_section = ".data")]
static TX: LazyStatic<any_uart::Sender> = LazyStatic::new();
#[unsafe(link_section = ".data")]
static RX: LazyStatic<any_uart::Receiver> = LazyStatic::new();
fn debug_uart_phys_to_virt(p: usize) -> *mut u8 {
if boot_info().debug_console.is_some() {
(p + crate::KLINER_OFFSET) as _
} else {
phys_to_virt(p)
}
}
pub(crate) fn init_debugcon(fdt: Option<NonNull<u8>>) -> Option<()> {
let uart = any_uart::init(fdt?, debug_uart_phys_to_virt)?;
TX.init(uart.tx?);
RX.init(uart.rx?);
crate::early_debug::set_tx_fun(write_byte);
crate::early_debug::set_rx_fun(read_byte);
Some(())
}
fn write_byte(b: u8) -> Result<(), crate::early_debug::TError> {
unsafe {
TX.edit(|tx| match tx.write(b) {
Ok(_) => Ok(()),
Err(e) => Err(match e {
any_uart::Error::WouldBlock => crate::early_debug::TError::ReTry,
any_uart::Error::Other(_e) => crate::early_debug::TError::Other,
}),
})
}
}
fn read_byte() -> Result<u8, crate::early_debug::RError> {
unsafe {
RX.edit(|tx| match tx.read() {
Ok(b) => Ok(b),
Err(e) => Err(match e {
any_uart::Error::WouldBlock => crate::early_debug::RError::NoData,
any_uart::Error::Other(_e) => crate::early_debug::RError::Other,
}),
})
}
}
pub fn setup_plat_info() -> Option<()> {
CPU_NUM.init(cpu_id_list().count());
find_rams()
}
fn fdt() -> Option<Fdt<'static>> {
boot_info().fdt.and_then(|fdt| Fdt::from_ptr(fdt).ok())
}
pub fn cpu_id_list() -> impl Iterator<Item = usize> {
let fdt = fdt().expect("FDT not found");
let nodes = fdt.find_nodes("/cpus/cpu");
nodes
.filter(|node| node.name().contains("cpu@"))
.filter(|node| !matches!(node.status(), Some(Status::Disabled)))
.map(|node| {
let reg = node
.reg()
.unwrap_or_else(|| panic!("cpu {} reg not found", node.name()))
.next()
.expect("cpu reg 0 not found");
reg.address as usize
})
}
pub fn find_rams() -> Option<()> {
let fdt = fdt()?;
for memory in fdt.memory() {
for region in memory.regions() {
let start = region.address as _;
if region.size == 0 {
continue; }
let v = MemoryRegion {
start,
end: start + region.size,
kind: MemoryRegionKind::Ram,
};
common::mem::with_regions(|regions| regions.push(v).ok())?;
}
}
for region in fdt.memory_reservation_block() {
let start = region.address as _;
let v = MemoryRegion {
start,
end: start + region.size,
kind: MemoryRegionKind::Reserved,
};
common::mem::with_regions(|regions| regions.push(v).ok())?;
}
if let Some(reserved_node) = fdt.reserved_memory().next() {
if let Some(region) = reserved_node.reg().and_then(|mut r| r.next())
&& let Some(size) = region.size
{
let start = region.address as _;
let v = MemoryRegion {
start,
end: start + size,
kind: MemoryRegionKind::Reserved,
};
common::mem::with_regions(|regions| regions.push(v).ok())?;
}
let parent_level = reserved_node.level;
let parent_name = reserved_node.name();
for child in reserved_node
.fdt()
.all_nodes()
.skip_while(move |n| n.name() != parent_name)
.skip(1)
.take_while(move |n| n.level > parent_level)
.filter(move |n| n.level == parent_level + 1)
{
if let Some(regs) = child.reg() {
for region in regs {
if let Some(size) = region.size {
let start = region.address as _;
let v = MemoryRegion {
start,
end: start + size,
kind: MemoryRegionKind::Reserved,
};
common::mem::with_regions(|regions| regions.push(v).ok())?;
}
}
}
}
}
Some(())
}