sparreal_kernel/platform/
mod.rs1use 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}