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