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_precpu_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 = "ax-driver")]
231 {
232 #[allow(unused_variables)]
233 let all_devices = ax_driver::init_drivers();
234
235 cfg_if::cfg_if! {
236 if #[cfg(feature = "fs-ng")] {
237 ax_fs_ng::init_filesystems(all_devices.block, ax_hal::dtb::get_chosen_bootargs());
238 } else
239 if #[cfg(feature = "fs")] {
240 ax_fs::init_filesystems(all_devices.block, ax_hal::dtb::get_chosen_bootargs());
241 }
242 }
243
244 cfg_if::cfg_if! {
245 if #[cfg(feature = "net-ng")] {
246 ax_net_ng::init_network(all_devices.net);
247
248 #[cfg(feature = "vsock")]
249 ax_net_ng::init_vsock(all_devices.vsock);
250 } else if #[cfg(feature = "net")] {
251 ax_net::init_network(all_devices.net);
252 }
253 }
254
255 #[cfg(feature = "display")]
256 ax_display::init_display(all_devices.display);
257
258 #[cfg(feature = "input")]
259 ax_input::init_input(all_devices.input);
260 }
261
262 #[cfg(feature = "smp")]
263 self::mp::start_secondary_cpus(cpu_id);
264
265 #[cfg(feature = "irq")]
266 {
267 info!("Initialize interrupt handlers...");
268 init_interrupt();
269 }
270
271 #[cfg(all(feature = "tls", not(feature = "multitask")))]
272 {
273 info!("Initialize thread local storage...");
274 init_tls();
275 }
276
277 ax_ctor_bare::call_ctors();
278
279 info!("Primary CPU {cpu_id} init OK.");
280 INITED_CPUS.fetch_add(1, Ordering::Release);
281
282 while !is_init_ok() {
283 core::hint::spin_loop();
284 }
285
286 unsafe { main() };
287
288 #[cfg(feature = "multitask")]
289 ax_task::exit(0);
290 #[cfg(not(feature = "multitask"))]
291 {
292 debug!("main task exited: exit_code={}", 0);
293 ax_hal::power::system_off();
294 }
295}
296
297#[cfg(feature = "alloc")]
298fn init_allocator() {
299 use ax_hal::mem::{MemRegionFlags, memory_regions, phys_to_virt};
300
301 info!("Initialize global memory allocator...");
302 info!(" use {} allocator.", ax_alloc::global_allocator().name());
303
304 let mut max_region_size = 0;
305 let mut max_region_paddr = 0.into();
306 let mut use_next_free = false;
307
308 for r in memory_regions() {
309 if r.name == ".bss" {
310 use_next_free = true;
311 } else if r.flags.contains(MemRegionFlags::FREE) {
312 if use_next_free {
313 max_region_paddr = r.paddr;
314 break;
315 } else if r.size > max_region_size {
316 max_region_size = r.size;
317 max_region_paddr = r.paddr;
318 }
319 }
320 }
321
322 for r in memory_regions() {
323 if r.flags.contains(MemRegionFlags::FREE) && r.paddr == max_region_paddr {
324 ax_alloc::global_init(phys_to_virt(r.paddr).as_usize(), r.size)
325 .expect("initialize global allocator failed");
326 break;
327 }
328 }
329
330 for r in memory_regions() {
331 if r.flags.contains(MemRegionFlags::FREE) && r.paddr != max_region_paddr {
332 ax_alloc::global_add_memory(phys_to_virt(r.paddr).as_usize(), r.size)
333 .expect("add heap memory region failed");
334 }
335 }
336}
337
338#[cfg(feature = "irq")]
339fn init_interrupt() {
340 const PERIODIC_INTERVAL_NANOS: u64 =
342 ax_hal::time::NANOS_PER_SEC / ax_config::TICKS_PER_SEC as u64;
343
344 #[ax_percpu::def_percpu]
345 static NEXT_DEADLINE: u64 = 0;
346
347 fn update_timer() {
348 let now_ns = ax_hal::time::monotonic_time_nanos();
349 let mut deadline = unsafe { NEXT_DEADLINE.read_current_raw() };
351 if now_ns >= deadline {
352 deadline = now_ns + PERIODIC_INTERVAL_NANOS;
353 }
354 unsafe { NEXT_DEADLINE.write_current_raw(deadline + PERIODIC_INTERVAL_NANOS) };
355 ax_hal::time::set_oneshot_timer(deadline);
356 }
357
358 ax_hal::irq::register(ax_hal::time::irq_num(), || {
359 update_timer();
360 #[cfg(feature = "multitask")]
361 ax_task::on_timer_tick();
362 });
363
364 #[cfg(feature = "ipi")]
365 ax_hal::irq::register(ax_hal::irq::IPI_IRQ, || {
366 ax_ipi::ipi_handler();
367 });
368
369 update_timer();
372
373 ax_hal::asm::enable_irqs();
375}
376
377#[cfg(all(feature = "tls", not(feature = "multitask")))]
378fn init_tls() {
379 let main_tls = ax_hal::tls::TlsArea::alloc();
380 unsafe { ax_hal::asm::write_thread_pointer(main_tls.tls_ptr() as usize) };
381 core::mem::forget(main_tls);
382}