sparreal_kernel/platform/
mod.rs

1use alloc::string::String;
2use alloc::vec::Vec;
3use core::ffi::CStr;
4use core::ops::Range;
5use core::ptr::NonNull;
6use rdrive::register::DriverRegister;
7pub use rdrive::intc::CpuId;
8
9use crate::globals::global_val;
10use crate::mem::PhysAddr;
11use crate::platform_if::*;
12use fdt::Fdt;
13
14pub mod fdt;
15
16pub enum PlatformInfoKind {
17    DeviceTree(Fdt),
18}
19
20impl PlatformInfoKind {
21    pub fn new_fdt(addr: NonNull<u8>) -> Self {
22        PlatformInfoKind::DeviceTree(Fdt::new(addr))
23    }
24
25    pub fn memorys(&self) -> impl Iterator<Item = Range<PhysAddr>> {
26        let mut out: [Option<Range<PhysAddr>>; 24] =
27            unsafe { core::mem::MaybeUninit::zeroed().assume_init() };
28        let mut len = 0;
29
30        match self {
31            PlatformInfoKind::DeviceTree(fdt) => {
32                for (i, m) in fdt
33                    .get()
34                    .memory()
35                    .flat_map(|m| m.regions())
36                    .map(|r| {
37                        let start = PhysAddr::from(r.address as usize);
38                        start..start + r.size
39                    })
40                    .enumerate()
41                {
42                    if i >= out.len() {
43                        break;
44                    }
45                    out[i] = Some(m);
46                    len += 1;
47                }
48            }
49        }
50
51        let mut iter = 0;
52        core::iter::from_fn(move || {
53            if iter >= len {
54                None
55            } else {
56                let m = out[iter].take().unwrap();
57                iter += 1;
58                Some(m)
59            }
60        })
61    }
62
63    pub fn main_memory(&self) -> Option<Range<PhysAddr>> {
64        let kernel_text = PlatformImpl::kernel_regions().text;
65
66        let mut first = None;
67
68        for m in self.memorys() {
69            let r = m.start.as_usize()..m.end.as_usize();
70            if r.contains(&kernel_text.end) {
71                return Some(m);
72            }
73            if first.is_none() {
74                first = Some(m);
75            }
76        }
77
78        first
79    }
80
81    pub fn debugcon(&self) -> Option<SerialPort> {
82        match self {
83            Self::DeviceTree(fdt) => fdt.debugcon(),
84        }
85    }
86}
87
88pub fn cpu_list() -> Vec<CPUInfo> {
89    match &global_val().platform_info {
90        PlatformInfoKind::DeviceTree(fdt) => fdt.cpus(),
91    }
92}
93
94pub fn cpu_id() -> CpuId {
95    PlatformImpl::cpu_id().into()
96}
97
98pub fn platform_name() -> String {
99    match &global_val().platform_info {
100        PlatformInfoKind::DeviceTree(fdt) => fdt.model_name().unwrap_or_default(),
101    }
102}
103
104pub fn shutdown() -> ! {
105    PlatformImpl::shutdown()
106}
107
108pub fn wait_for_interrupt() {
109    PlatformImpl::wait_for_interrupt();
110}
111
112pub fn kstack_size() -> usize {
113    PlatformImpl::kstack_size()
114}
115
116pub fn page_size() -> usize {
117    #[cfg(feature = "mmu")]
118    {
119        MMUImpl::page_size()
120    }
121
122    #[cfg(not(feature = "mmu"))]
123    {
124        0x1000
125    }
126}
127
128pub fn app_main() {
129    unsafe extern "C" {
130        fn __sparreal_rt_main();
131    }
132    unsafe { __sparreal_rt_main() }
133}
134
135#[derive(Debug)]
136pub struct CPUInfo {
137    pub cpu_id: CpuId,
138}
139
140#[derive(Debug, Clone, Copy)]
141pub struct SerialPort {
142    pub addr: PhysAddr,
143    pub size: Option<usize>,
144    compatible: [Option<[u8; 128]>; 4],
145}
146
147impl SerialPort {
148    pub fn new<'a>(
149        addr: PhysAddr,
150        size: Option<usize>,
151        compatibles: impl Iterator<Item = &'a str>,
152    ) -> Self {
153        let mut compatible_out = [None; 4];
154
155        for (i, c) in compatibles.enumerate() {
156            if i == compatible_out.len() {
157                break;
158            }
159            let bytes = c.as_bytes();
160            let mut bytes_out = [0u8; 128];
161            bytes_out[..bytes.len()].copy_from_slice(bytes);
162            compatible_out[i] = Some(bytes_out);
163        }
164
165        Self {
166            addr,
167            size,
168            compatible: compatible_out,
169        }
170    }
171
172    pub fn compatibles(&self) -> impl Iterator<Item = &str> {
173        let mut iter = 0;
174
175        core::iter::from_fn(move || {
176            if iter >= self.compatible.len() {
177                None
178            } else {
179                let bytes = self.compatible[iter].as_ref()?;
180                iter += 1;
181                CStr::from_bytes_until_nul(bytes).ok()?.to_str().ok()
182            }
183        })
184    }
185}
186
187pub fn module_registers() -> Vec<DriverRegister> {
188    PlatformImpl::driver_registers().as_slice().to_vec()
189}