1#![cfg_attr(not(test), no_std)]
34#![allow(missing_abi)]
35
36#[macro_use]
37extern crate axlog;
38
39#[cfg(all(target_arch = "x86_64", feature = "driver-dyn"))]
40extern crate axplat_x86_qemu_q35;
41
42#[cfg(all(target_arch = "aarch64", feature = "driver-dyn"))]
43extern crate axplat_dyn;
44
45#[cfg(all(target_arch = "aarch64", feature = "driver-dyn"))]
46extern crate somehal;
47
48#[cfg(all(target_os = "none", not(test)))]
49mod lang_items;
50
51#[cfg(feature = "smp")]
52mod mp;
53
54#[cfg(feature = "smp")]
55pub use self::mp::rust_main_secondary;
56
57const LOGO: &str = r#"
58 d8888 .d88888b. .d8888b.
59 d88888 d88P" "Y88b d88P Y88b
60 d88P888 888 888 Y88b.
61 d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b.
62 d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b.
63 d88P 888 888 888 88888888 888 888 "888
64 d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P
65d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P"
66"#;
67
68unsafe extern "C" {
69 fn main();
71}
72
73struct LogIfImpl;
74
75#[crate_interface::impl_interface]
76impl axlog::LogIf for LogIfImpl {
77 fn console_write_str(s: &str) {
78 axhal::console::write_bytes(s.as_bytes());
79 }
80
81 fn current_time() -> core::time::Duration {
82 axhal::time::monotonic_time()
83 }
84
85 fn current_cpu_id() -> Option<usize> {
86 #[cfg(feature = "smp")]
87 if is_init_ok() {
88 Some(axhal::percpu::this_cpu_id())
89 } else {
90 None
91 }
92 #[cfg(not(feature = "smp"))]
93 Some(0)
94 }
95
96 fn current_task_id() -> Option<u64> {
97 if is_init_ok() {
98 #[cfg(feature = "multitask")]
99 {
100 axtask::current_may_uninit().map(|curr| curr.id().as_u64())
101 }
102 #[cfg(not(feature = "multitask"))]
103 None
104 } else {
105 None
106 }
107 }
108}
109
110use core::sync::atomic::{AtomicUsize, Ordering};
111
112static INITED_CPUS: AtomicUsize = AtomicUsize::new(0);
113
114#[cfg(feature = "driver-dyn")]
115fn is_init_ok() -> bool {
116 let cpu_num = cpu_count();
117 INITED_CPUS.load(Ordering::Acquire) == cpu_num
118}
119
120#[cfg(not(feature = "driver-dyn"))]
121fn is_init_ok() -> bool {
122 let cpu_num = axconfig::plat::CPU_NUM;
123 INITED_CPUS.load(Ordering::Acquire) == cpu_num
124}
125
126#[cfg_attr(not(test), axplat::main)]
137pub fn rust_main(cpu_id: usize, arg: usize) -> ! {
138 unsafe { axhal::mem::clear_bss() };
139 axhal::percpu::init_primary(cpu_id);
140 axhal::init_early(cpu_id, arg);
141
142 ax_println!("{}", LOGO);
143 #[cfg(feature = "driver-dyn")]
144 ax_println!("smp = {}", cpu_count());
145
146 #[cfg(not(feature = "driver-dyn"))]
147 ax_println!(
148 indoc::indoc! {"
149 arch = {}
150 platform = {}
151 target = {}
152 build_mode = {}
153 log_level = {}
154 backtrace = {}
155 smp = {}
156 "},
157 axconfig::ARCH,
158 axconfig::PLATFORM,
159 option_env!("AX_TARGET").unwrap_or(""),
160 option_env!("AX_MODE").unwrap_or(""),
161 option_env!("AX_LOG").unwrap_or(""),
162 axbacktrace::is_enabled(),
163 axconfig::plat::CPU_NUM,
164 );
165
166 #[cfg(feature = "rtc")]
167 ax_println!(
168 "Boot at {}\n",
169 chrono::DateTime::from_timestamp_nanos(axhal::time::wall_time_nanos() as _),
170 );
171
172 axlog::init();
173 log::set_max_level(log::LevelFilter::Trace);
174 info!("Logging is enabled.");
176 info!("Primary CPU {cpu_id} started, arg = {arg:#x}.");
177
178 axhal::mem::init();
179 info!("Found physcial memory regions:");
180 for r in axhal::mem::memory_regions() {
181 info!(
182 " [{:x?}, {:x?}) {} ({:?})",
183 r.paddr,
184 r.paddr + r.size,
185 r.name,
186 r.flags
187 );
188 }
189
190 #[cfg(feature = "alloc")]
191 init_allocator();
192
193 let (kernel_space_start, kernel_space_size) = axhal::mem::kernel_aspace();
194
195 info!(
196 "kernel aspace: [{:#x?}, {:#x?})",
197 kernel_space_start,
198 kernel_space_start + kernel_space_size,
199 );
200
201 #[cfg(feature = "paging")]
202 axmm::init_memory_management();
203
204 #[cfg(feature = "driver-dyn")]
205 axdriver::setup(arg);
206
207 info!("Initialize platform devices...");
208 axhal::init_later(cpu_id, arg);
209
210 #[cfg(feature = "multitask")]
211 axtask::init_scheduler();
212
213 #[cfg(any(feature = "fs", feature = "net", feature = "display"))]
214 {
215 #[allow(unused_variables)]
216 let all_devices = axdriver::init_drivers();
217
218 #[cfg(feature = "fs")]
219 axfs::init_filesystems(all_devices.block, axhal::dtb::get_chosen_bootargs());
220
221 #[cfg(feature = "net")]
222 axnet::init_network(all_devices.net);
223
224 #[cfg(feature = "display")]
225 axdisplay::init_display(all_devices.display);
226 }
227
228 #[cfg(feature = "smp")]
229 self::mp::start_secondary_cpus(cpu_id);
230
231 #[cfg(feature = "irq")]
232 {
233 info!("Initialize interrupt handlers...");
234 init_interrupt();
235 }
236
237 #[cfg(all(feature = "tls", not(feature = "multitask")))]
238 {
239 info!("Initialize thread local storage...");
240 init_tls();
241 }
242
243 ctor_bare::call_ctors();
244
245 info!("Primary CPU {cpu_id} init OK.");
246 INITED_CPUS.fetch_add(1, Ordering::Release);
247
248 while !is_init_ok() {
249 core::hint::spin_loop();
250 }
251
252 unsafe { main() };
253
254 #[cfg(feature = "multitask")]
255 axtask::exit(0);
256 #[cfg(not(feature = "multitask"))]
257 {
258 debug!("main task exited: exit_code={}", 0);
259 axhal::power::system_off();
260 }
261}
262
263#[cfg(feature = "alloc")]
264fn init_allocator() {
265 use axhal::mem::{MemRegionFlags, memory_regions, phys_to_virt, virt_to_phys};
266
267 info!("Initialize global memory allocator...");
268 info!(" use {} allocator.", axalloc::global_allocator().name());
269
270 let mut max_region_size = 0;
271 let mut max_region_paddr = 0.into();
272 let mut use_next_free = false;
273
274 for r in memory_regions() {
275 if r.name == ".bss" {
276 use_next_free = true;
277 } else if r.flags.contains(MemRegionFlags::FREE) {
278 if use_next_free {
279 max_region_paddr = r.paddr;
280 break;
281 } else if r.size > max_region_size {
282 max_region_size = r.size;
283 max_region_paddr = r.paddr;
284 }
285 }
286 }
287
288 #[cfg(feature = "hv")]
289 {
290 struct AddrTranslatorImpl;
291 impl axalloc::AddrTranslator for AddrTranslatorImpl {
292 fn virt_to_phys(&self, va: usize) -> Option<usize> {
293 Some(virt_to_phys(va.into()).as_usize())
294 }
295 }
296
297 static TRANSLATOR: AddrTranslatorImpl = AddrTranslatorImpl;
298
299 for r in memory_regions() {
300 if r.flags.contains(MemRegionFlags::FREE) && r.paddr == max_region_paddr {
301 axalloc::global_init(phys_to_virt(r.paddr).as_usize(), r.size, &TRANSLATOR);
302 break;
303 }
304 }
305 }
306
307 #[cfg(not(feature = "hv"))]
308 {
309 for r in memory_regions() {
310 if r.flags.contains(MemRegionFlags::FREE) && r.paddr == max_region_paddr {
311 axalloc::global_init(phys_to_virt(r.paddr).as_usize(), r.size);
312 break;
313 }
314 }
315 }
316
317 for r in memory_regions() {
318 if r.flags.contains(MemRegionFlags::FREE) && r.paddr != max_region_paddr {
319 axalloc::global_add_memory(phys_to_virt(r.paddr).as_usize(), r.size)
320 .expect("add heap memory region failed");
321 }
322 }
323}
324
325#[cfg(feature = "irq")]
326fn init_interrupt() {
327 const PERIODIC_INTERVAL_NANOS: u64 =
329 axhal::time::NANOS_PER_SEC / axconfig::TICKS_PER_SEC as u64;
330
331 #[percpu::def_percpu]
332 static NEXT_DEADLINE: u64 = 0;
333
334 fn update_timer() {
335 let now_ns = axhal::time::monotonic_time_nanos();
336 let mut deadline = unsafe { NEXT_DEADLINE.read_current_raw() };
338 if now_ns >= deadline {
339 deadline = now_ns + PERIODIC_INTERVAL_NANOS;
340 }
341 unsafe { NEXT_DEADLINE.write_current_raw(deadline + PERIODIC_INTERVAL_NANOS) };
342 axhal::time::set_oneshot_timer(deadline);
343 }
344
345 axhal::irq::register(axhal::time::irq_num(), || {
347 update_timer();
348 #[cfg(feature = "multitask")]
349 axtask::on_timer_tick();
350 });
351
352 #[cfg(feature = "ipi")]
353 axhal::irq::register(axhal::irq::IPI_IRQ, || {
354 axipi::ipi_handler();
355 });
356
357 axhal::asm::enable_irqs();
359}
360
361#[cfg(all(feature = "tls", not(feature = "multitask")))]
362fn init_tls() {
363 let main_tls = axhal::tls::TlsArea::alloc();
364 unsafe { axhal::asm::write_thread_pointer(main_tls.tls_ptr() as usize) };
365 core::mem::forget(main_tls);
366}
367
368#[cfg(feature = "driver-dyn")]
369fn smp() -> Option<usize> {
370 let mut smp = None;
371 let s = option_env!("AXVISOR_SMP");
372 if let Some(s) = s
373 && let Ok(n) = s.parse::<usize>()
374 {
375 smp = Some(n);
376 }
377 smp
378}
379
380#[cfg(feature = "driver-dyn")]
382pub fn cpu_count() -> usize {
383 let mut cpu_count;
384
385 cfg_if::cfg_if! {
386 if #[cfg(all(target_arch = "x86_64", target_os = "none"))] {
387 cpu_count = axplat_x86_qemu_q35::cpu_count()
388 } else if #[cfg(target_arch = "aarch64")] {
389 cpu_count = somehal::mem::cpu_id_list().count()
390 } else {
391 cpu_count = 1;
392 }
393 }
394
395 if let Some(smp) = smp() {
396 cpu_count = smp.min(cpu_count);
397 }
398
399 cpu_count
400}