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