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