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