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 ax_ipi::mark_current_cpu_ready();
425}
426
427#[cfg(feature = "irq")]
428pub(crate) fn init_percpu_irq(cpu_id: usize) {
429 ax_hal::irq::cpu_online(cpu_id).expect("failed to mark CPU online for IRQ framework");
430 ax_hal::irq::init_common_irq_handler();
431
432 if ax_hal::percpu::this_cpu_is_bsp() {
433 let cpus = ax_hal::irq::CpuMask::first_n(ax_hal::cpu_num());
434 ax_hal::irq::request_percpu_irq(ax_hal::time::irq_num(), cpus, timer_irq_handler)
435 .expect("failed to register timer IRQ handler");
436
437 #[cfg(any(feature = "ipi", feature = "wake-ipi"))]
438 ax_hal::irq::request_percpu_irq(ax_hal::irq::ipi_irq(), cpus, ipi_irq_handler)
439 .expect("failed to register IPI IRQ handler");
440 }
441
442 init_timer();
443}
444
445#[cfg(all(feature = "irq", feature = "ipi"))]
446unsafe fn ax_ipi_run_on_cpu_sync(
447 cpu: usize,
448 f: unsafe fn(*mut ()),
449 arg: *mut (),
450) -> Result<(), ax_hal::irq::IrqError> {
451 unsafe { ax_ipi::run_on_cpu_sync_raw(cpu, f, arg) }
452}
453
454#[cfg(feature = "irq")]
455fn periodic_interval_nanos() -> u64 {
456 ax_hal::time::NANOS_PER_SEC / ticks_per_sec()
457}
458
459#[cfg(feature = "irq")]
460#[ax_percpu::def_percpu]
461static NEXT_PERIODIC_DEADLINE_NANOS: u64 = 0;
462
463#[cfg(feature = "irq")]
464fn with_periodic_deadline<R>(
465 operation: impl for<'scope> FnOnce(&ax_percpu::CpuPin<'scope>) -> R,
466) -> R {
467 unsafe { ax_percpu::with_cpu_pin(operation) }
471 .unwrap_or_else(|error| panic!("timer CPU-local state is invalid: {error}"))
472}
473
474#[cfg(feature = "irq")]
475fn init_timer() {
476 ax_hal::time::enable_timer_irq();
477 let now_ns = ax_hal::time::monotonic_time_nanos();
478 with_periodic_deadline(|pin| {
479 NEXT_PERIODIC_DEADLINE_NANOS
480 .write_current(pin, now_ns.saturating_add(periodic_interval_nanos()));
481 });
482 program_next_timer();
483}
484
485#[cfg(feature = "irq")]
486fn advance_periodic_timer(now_ns: u64) -> bool {
487 let mut deadline = with_periodic_deadline(|pin| NEXT_PERIODIC_DEADLINE_NANOS.read_current(pin));
488 if deadline == 0 {
489 with_periodic_deadline(|pin| {
490 NEXT_PERIODIC_DEADLINE_NANOS
491 .write_current(pin, now_ns.saturating_add(periodic_interval_nanos()));
492 });
493 return false;
494 }
495 if now_ns < deadline {
496 return false;
497 }
498
499 while deadline <= now_ns {
500 deadline = deadline.saturating_add(periodic_interval_nanos());
501 if deadline == u64::MAX {
502 break;
503 }
504 }
505 with_periodic_deadline(|pin| NEXT_PERIODIC_DEADLINE_NANOS.write_current(pin, deadline));
506 true
507}
508
509#[cfg(feature = "irq")]
510fn program_next_timer() {
511 let mut deadline = with_periodic_deadline(|pin| NEXT_PERIODIC_DEADLINE_NANOS.read_current(pin));
512 if deadline == 0 {
513 let now_ns = ax_hal::time::monotonic_time_nanos();
514 deadline = now_ns.saturating_add(periodic_interval_nanos());
515 with_periodic_deadline(|pin| NEXT_PERIODIC_DEADLINE_NANOS.write_current(pin, deadline));
516 }
517 #[cfg(feature = "multitask")]
518 if let Some(task_deadline) = ax_task::next_timer_deadline_nanos() {
519 deadline = core::cmp::min(deadline, task_deadline);
520 }
521
522 ax_hal::time::set_oneshot_timer(deadline);
523 #[cfg(feature = "multitask")]
524 ax_task::note_programmed_timer_deadline_nanos(deadline);
525}
526
527#[cfg(feature = "irq")]
528fn timer_irq_handler(ctx: ax_hal::irq::IrqContext) -> ax_hal::irq::IrqReturn {
529 let _ = ctx;
530 #[cfg(feature = "multitask")]
531 let scheduler_tick = advance_periodic_timer(ax_hal::time::monotonic_time_nanos());
532 #[cfg(not(feature = "multitask"))]
533 let _ = advance_periodic_timer(ax_hal::time::monotonic_time_nanos());
534 #[cfg(feature = "multitask")]
535 ax_task::on_timer_irq(scheduler_tick);
536 program_next_timer();
537 ax_hal::irq::IrqReturn::Handled
538}
539
540#[cfg(all(feature = "irq", feature = "ipi"))]
541fn ipi_irq_handler(_ctx: ax_hal::irq::IrqContext) -> ax_hal::irq::IrqReturn {
542 ax_ipi::ipi_handler();
543 ax_hal::irq::IrqReturn::Handled
544}
545
546#[cfg(all(feature = "irq", feature = "wake-ipi", not(feature = "ipi")))]
547fn ipi_irq_handler(_ctx: ax_hal::irq::IrqContext) -> ax_hal::irq::IrqReturn {
548 ax_hal::irq::IrqReturn::Handled
549}
550
551#[cfg(all(feature = "tls", not(feature = "multitask")))]
552fn init_tls() {
553 let main_tls = ax_hal::tls::TlsArea::alloc();
554 let kernel_tls = ax_hal::context::KernelTlsBase::new(main_tls.tls_ptr() as usize);
555 unsafe { ax_hal::asm::write_thread_pointer(kernel_tls) };
556 core::mem::forget(main_tls);
557}
558
559#[cfg(test)]
560mod tests {
561 #[test]
562 fn fs_init_accepts_bootargs_without_fs_feature() {
563 crate::fs::init(Some("root=/dev/nvme0n1"));
564 }
565}