1#![feature(extern_item_impls)]
33#![cfg_attr(not(test), no_std)]
34#![allow(missing_abi)]
35
36#[macro_use]
37extern crate ax_log;
38
39extern crate ax_driver as _;
40
41#[cfg(all(target_os = "none", not(feature = "std-compat"), not(test)))]
42mod lang_items;
43#[cfg(all(
44 feature = "stack-protector",
45 any(target_os = "none", target_env = "musl"),
46 not(test)
47))]
48mod stack_protector;
49
50#[cfg(feature = "smp")]
51mod mp;
52
53mod klib;
54
55mod devices;
56mod fs;
57#[cfg(feature = "irq")]
58pub mod irq;
59mod registers;
60#[cfg(feature = "serial")]
61pub mod serial;
62
63#[cfg(all(feature = "net", feature = "fs"))]
64mod unix_ns;
65
66#[cfg(feature = "aic8800-wifi")]
67mod wifi_glue;
68
69pub use ax_hal as hal;
70
71pub(crate) mod build_info {
72 include!(concat!(env!("OUT_DIR"), "/build_info.rs"));
73}
74
75#[cfg(feature = "smp")]
76pub use self::mp::rust_main_secondary;
77
78extern crate alloc;
79
80#[cfg(feature = "fs")]
81pub(crate) fn runtime_default_task_stack_size() -> usize {
82 build_info::TASK_STACK_SIZE
83}
84
85#[cfg(feature = "irq")]
86fn ticks_per_sec() -> u64 {
87 build_info::TICKS_PER_SEC as u64
88}
89
90const LOGO: &str = r#"
91 d8888 .d88888b. .d8888b.
92 d88888 d88P" "Y88b d88P Y88b
93 d88P888 888 888 Y88b.
94 d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b.
95 d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b.
96 d88P 888 888 888 88888888 888 888 "888
97 d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P
98d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P"
99"#;
100
101#[eii]
102fn ax_app_entry() {
103 #[cfg(not(test))]
104 unsafe extern "C" {
105 safe fn main();
107 }
108 #[cfg(not(test))]
110 main();
111}
112
113struct LogIfImpl;
114
115#[cfg(feature = "paging")]
116fn runtime_page_fault_handler(
117 addr: ax_memory_addr::VirtAddr,
118 flags: ax_hal::trap::PageFaultFlags,
119) -> bool {
120 #[cfg(feature = "stack-guard-page")]
121 if ax_task::diagnose_current_stack_guard_page_fault(addr) {
122 return false;
123 }
124
125 ax_mm::kernel_aspace().lock().handle_page_fault(addr, flags)
126}
127
128#[ax_crate_interface::impl_interface]
129impl ax_log::LogIf for LogIfImpl {
130 fn console_write_str(s: &str) {
131 #[cfg(feature = "serial")]
132 if serial::route_console_bytes(s.as_bytes()).is_some() {
133 return;
134 }
135 ax_hal::console::write_text_bytes(s.as_bytes());
136 }
137
138 fn current_time() -> core::time::Duration {
139 ax_hal::time::monotonic_time()
140 }
141
142 fn current_cpu_id() -> Option<usize> {
143 #[cfg(feature = "smp")]
144 if is_init_ok() {
145 Some(ax_hal::percpu::this_cpu_id())
146 } else {
147 None
148 }
149 #[cfg(not(feature = "smp"))]
150 Some(0)
151 }
152
153 fn current_task_id() -> Option<u64> {
154 if is_init_ok() {
155 #[cfg(feature = "multitask")]
156 {
157 ax_task::current_may_uninit().map(|curr| curr.id().as_u64())
158 }
159 #[cfg(not(feature = "multitask"))]
160 None
161 } else {
162 None
163 }
164 }
165}
166
167use core::sync::atomic::{AtomicUsize, Ordering};
168
169static INITED_CPUS: AtomicUsize = AtomicUsize::new(0);
171
172fn is_init_ok() -> bool {
173 INITED_CPUS.load(Ordering::Acquire) == ax_hal::cpu_num()
174}
175
176#[cfg_attr(not(test), ax_plat::main)]
187pub fn rust_main(cpu_id: usize, arg: usize) -> ! {
188 ax_hal::percpu::init_primary(cpu_id);
189 ax_alloc::init_percpu_slab(cpu_id);
192 ax_hal::init_early(cpu_id, arg);
193 let log_level = option_env!("AX_LOG").unwrap_or("info");
194
195 ax_println!("{}", LOGO);
196 ax_println!(
197 indoc::indoc! {"
198 arch = {}
199 platform = {}
200 target = {}
201 build_mode = {}
202 log_level = {}
203 backtrace = {}
204 smp = {}
205 "},
206 build_info::ARCH,
207 hal::platform_name(),
208 build_info::TARGET,
209 build_info::MODE,
210 log_level,
211 axbacktrace::is_enabled(),
212 ax_hal::cpu_num()
213 );
214
215 ax_log::init();
216 ax_log::set_max_level(log_level); info!("Logging is enabled.");
218 info!("Primary CPU {cpu_id} started, arg = {arg:#x}.");
219
220 info!("Found physcial memory regions:");
221 for r in ax_hal::mem::memory_regions() {
222 info!(
223 " [{:x?}, {:x?}) {} ({:?})",
224 r.paddr,
225 r.paddr + r.size,
226 r.name,
227 r.flags
228 );
229 }
230
231 init_allocator();
232
233 let (kernel_space_start, kernel_space_size) = ax_hal::mem::kernel_aspace();
234
235 {
236 use core::ops::Range;
237
238 unsafe extern "C" {
239 safe static _stext: [u8; 0];
240 safe static _etext: [u8; 0];
241 }
242
243 let fp_range_start = kernel_space_start.as_usize();
244 let fp_range_end = fp_range_start.saturating_add(kernel_space_size);
245 axbacktrace::init(
246 Range {
247 start: _stext.as_ptr() as usize,
248 end: _etext.as_ptr() as usize,
249 },
250 Range {
251 start: fp_range_start,
252 end: fp_range_end,
253 },
254 );
255 }
256
257 info!(
258 "kernel aspace: [{:#x?}, {:#x?})",
259 kernel_space_start,
260 kernel_space_start + kernel_space_size,
261 );
262
263 #[cfg(feature = "paging")]
264 {
265 ax_mm::init_memory_management();
266 ax_hal::trap::set_page_fault_handler(runtime_page_fault_handler);
267 }
268
269 info!("Initialize platform devices...");
270 ax_hal::init_later(cpu_id, arg);
271 if rdrive::is_initialized() {
272 registers::append_linker_registers();
273 #[cfg(feature = "irq")]
274 ax_hal::irq::init_boot_irqs(cpu_id)
275 .unwrap_or_else(|err| panic!("failed to initialize boot IRQs: {err:?}"));
276 #[cfg(not(feature = "irq"))]
277 rdrive::probe_pre_kernel()
278 .unwrap_or_else(|err| panic!("failed to run pre-kernel driver probes: {err:?}"));
279 } else {
280 warn!("rdrive is not initialized; skip pre-kernel driver probe");
281 }
282
283 #[cfg(feature = "multitask")]
284 ax_task::init_scheduler();
285
286 #[cfg(feature = "ipi")]
287 {
288 ax_ipi::init();
289 #[cfg(feature = "irq")]
290 ax_hal::irq::set_run_on_cpu_sync(ax_ipi_run_on_cpu_sync);
291 }
292
293 #[cfg(feature = "irq")]
294 {
295 info!("Initialize interrupt handlers...");
296 init_interrupt();
297 }
298
299 #[cfg(feature = "aic8800-wifi")]
305 wifi_glue::install_runtime();
306
307 devices::probe_all_devices();
308
309 #[cfg(feature = "serial")]
310 serial::init(cpu_id);
311
312 #[cfg(feature = "rtc")]
313 ax_println!(
314 "Boot at {}\n",
315 chrono::DateTime::from_timestamp_nanos(ax_hal::time::wall_time_nanos() as _),
316 );
317
318 fs::init(ax_hal::boot::bootargs());
319
320 #[cfg(feature = "display")]
321 devices::init_display();
322
323 #[cfg(feature = "input")]
324 devices::init_input();
325
326 #[cfg(feature = "net")]
327 devices::init_net();
328
329 #[cfg(feature = "vsock")]
330 devices::init_vsock();
331
332 #[cfg(feature = "smp")]
333 self::mp::start_secondary_cpus(cpu_id);
334
335 #[cfg(all(feature = "tls", not(feature = "multitask")))]
336 {
337 info!("Initialize thread local storage...");
338 init_tls();
339 }
340
341 ax_ctor_bare::call_ctors();
342
343 info!("Primary CPU {cpu_id} init OK.");
344 INITED_CPUS.fetch_add(1, Ordering::Release);
345
346 while !is_init_ok() {
347 core::hint::spin_loop();
348 }
349
350 #[cfg(all(feature = "irq", feature = "ipi"))]
351 ax_ipi::wait_for_all_cpus_ready();
352
353 ax_app_entry();
354
355 #[cfg(feature = "multitask")]
356 ax_task::exit(0);
357 #[cfg(not(feature = "multitask"))]
358 {
359 debug!("main task exited: exit_code={}", 0);
360 ax_hal::power::system_off();
361 }
362}
363
364fn init_allocator() {
365 use ax_hal::mem::{MemRegionFlags, memory_regions, phys_to_virt};
366
367 info!("Initialize global memory allocator...");
368 info!(" use {} allocator.", ax_alloc::global_allocator().name());
369
370 let mut max_region_size = 0;
386 let mut max_region_paddr = 0.into();
387
388 for r in memory_regions() {
389 if r.flags.contains(MemRegionFlags::FREE) && r.size > max_region_size {
390 max_region_size = r.size;
391 max_region_paddr = r.paddr;
392 }
393 }
394
395 for r in memory_regions() {
396 if r.flags.contains(MemRegionFlags::FREE) && r.paddr == max_region_paddr {
397 ax_alloc::global_init(phys_to_virt(r.paddr).as_usize(), r.size)
398 .expect("initialize global allocator failed");
399 break;
400 }
401 }
402
403 for r in memory_regions() {
404 if r.flags.contains(MemRegionFlags::FREE) && r.paddr != max_region_paddr {
405 ax_alloc::global_add_memory(phys_to_virt(r.paddr).as_usize(), r.size)
406 .expect("add heap memory region failed");
407 }
408 }
409}
410
411#[cfg(feature = "irq")]
412fn init_interrupt() {
413 init_percpu_irq(ax_hal::percpu::this_cpu_id());
414
415 ax_hal::asm::enable_irqs();
417
418 #[cfg(feature = "ipi")]
419 ax_ipi::mark_current_cpu_ready();
420}
421
422#[cfg(feature = "irq")]
423pub(crate) fn init_percpu_irq(cpu_id: usize) {
424 ax_hal::irq::cpu_online(cpu_id).expect("failed to mark CPU online for IRQ framework");
425 ax_hal::irq::init_common_irq_handler();
426
427 if ax_hal::percpu::this_cpu_is_bsp() {
428 let cpus = ax_hal::irq::CpuMask::first_n(ax_hal::cpu_num());
429 ax_hal::irq::request_percpu_irq(ax_hal::time::irq_num(), cpus, timer_irq_handler)
430 .expect("failed to register timer IRQ handler");
431
432 #[cfg(any(feature = "ipi", feature = "wake-ipi"))]
433 ax_hal::irq::request_percpu_irq(ax_hal::irq::ipi_irq(), cpus, ipi_irq_handler)
434 .expect("failed to register IPI IRQ handler");
435 }
436
437 init_timer();
438}
439
440#[cfg(all(feature = "irq", feature = "ipi"))]
441unsafe fn ax_ipi_run_on_cpu_sync(
442 cpu: usize,
443 f: unsafe fn(*mut ()),
444 arg: *mut (),
445) -> Result<(), ax_hal::irq::IrqError> {
446 unsafe { ax_ipi::run_on_cpu_sync_raw(cpu, f, arg) }
447}
448
449#[cfg(feature = "irq")]
450fn periodic_interval_nanos() -> u64 {
451 ax_hal::time::NANOS_PER_SEC / ticks_per_sec()
452}
453
454#[cfg(feature = "irq")]
455#[ax_percpu::def_percpu]
456static NEXT_PERIODIC_DEADLINE_NANOS: u64 = 0;
457
458#[cfg(feature = "irq")]
459fn with_periodic_deadline<R>(
460 operation: impl for<'scope> FnOnce(&ax_percpu::CpuPin<'scope>) -> R,
461) -> R {
462 unsafe { ax_percpu::with_cpu_pin(operation) }
466 .unwrap_or_else(|error| panic!("timer CPU-local state is invalid: {error}"))
467}
468
469#[cfg(feature = "irq")]
470fn init_timer() {
471 ax_hal::time::enable_timer_irq();
472 let now_ns = ax_hal::time::monotonic_time_nanos();
473 with_periodic_deadline(|pin| {
474 NEXT_PERIODIC_DEADLINE_NANOS
475 .write_current(pin, now_ns.saturating_add(periodic_interval_nanos()));
476 });
477 program_next_timer();
478}
479
480#[cfg(feature = "irq")]
481fn advance_periodic_timer(now_ns: u64) -> bool {
482 let mut deadline = with_periodic_deadline(|pin| NEXT_PERIODIC_DEADLINE_NANOS.read_current(pin));
483 if deadline == 0 {
484 with_periodic_deadline(|pin| {
485 NEXT_PERIODIC_DEADLINE_NANOS
486 .write_current(pin, now_ns.saturating_add(periodic_interval_nanos()));
487 });
488 return false;
489 }
490 if now_ns < deadline {
491 return false;
492 }
493
494 while deadline <= now_ns {
495 deadline = deadline.saturating_add(periodic_interval_nanos());
496 if deadline == u64::MAX {
497 break;
498 }
499 }
500 with_periodic_deadline(|pin| NEXT_PERIODIC_DEADLINE_NANOS.write_current(pin, deadline));
501 true
502}
503
504#[cfg(feature = "irq")]
505fn program_next_timer() {
506 let mut deadline = with_periodic_deadline(|pin| NEXT_PERIODIC_DEADLINE_NANOS.read_current(pin));
507 if deadline == 0 {
508 let now_ns = ax_hal::time::monotonic_time_nanos();
509 deadline = now_ns.saturating_add(periodic_interval_nanos());
510 with_periodic_deadline(|pin| NEXT_PERIODIC_DEADLINE_NANOS.write_current(pin, deadline));
511 }
512 #[cfg(feature = "multitask")]
513 if let Some(task_deadline) = ax_task::next_timer_deadline_nanos() {
514 deadline = core::cmp::min(deadline, task_deadline);
515 }
516
517 ax_hal::time::set_oneshot_timer(deadline);
518 #[cfg(feature = "multitask")]
519 ax_task::note_programmed_timer_deadline_nanos(deadline);
520}
521
522#[cfg(feature = "irq")]
523fn timer_irq_handler(ctx: ax_hal::irq::IrqContext) -> ax_hal::irq::IrqReturn {
524 let _ = ctx;
525 #[cfg(feature = "multitask")]
526 let scheduler_tick = advance_periodic_timer(ax_hal::time::monotonic_time_nanos());
527 #[cfg(not(feature = "multitask"))]
528 let _ = advance_periodic_timer(ax_hal::time::monotonic_time_nanos());
529 #[cfg(feature = "multitask")]
530 ax_task::on_timer_irq(scheduler_tick);
531 program_next_timer();
532 ax_hal::irq::IrqReturn::Handled
533}
534
535#[cfg(all(feature = "irq", feature = "ipi"))]
536fn ipi_irq_handler(_ctx: ax_hal::irq::IrqContext) -> ax_hal::irq::IrqReturn {
537 ax_ipi::ipi_handler();
538 ax_hal::irq::IrqReturn::Handled
539}
540
541#[cfg(all(feature = "irq", feature = "wake-ipi", not(feature = "ipi")))]
542fn ipi_irq_handler(_ctx: ax_hal::irq::IrqContext) -> ax_hal::irq::IrqReturn {
543 ax_hal::irq::IrqReturn::Handled
544}
545
546#[cfg(all(feature = "tls", not(feature = "multitask")))]
547fn init_tls() {
548 let main_tls = ax_hal::tls::TlsArea::alloc();
549 let kernel_tls = ax_hal::context::KernelTlsBase::new(main_tls.tls_ptr() as usize);
550 unsafe { ax_hal::asm::write_thread_pointer(kernel_tls) };
551 core::mem::forget(main_tls);
552}
553
554#[cfg(test)]
555mod tests {
556 #[test]
557 fn fs_init_accepts_bootargs_without_fs_feature() {
558 crate::fs::init(Some("root=/dev/vda"));
559 }
560}