#![cfg_attr(not(test), no_std)]
#![feature(doc_auto_cfg)]
#[macro_use]
extern crate axlog;
#[cfg(all(target_os = "none", not(test)))]
mod lang_items;
#[cfg(feature = "smp")]
mod mp;
#[cfg(feature = "smp")]
pub use self::mp::rust_main_secondary;
const LOGO: &str = r#"
d8888 .d88888b. .d8888b.
d88888 d88P" "Y88b d88P Y88b
d88P888 888 888 Y88b.
d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b.
d88P 888 888P" d88P" d8P Y8b 888 888 "Y88b.
d88P 888 888 888 88888888 888 888 "888
d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P
d88P 888 888 "Y8888P "Y8888 "Y88888P" "Y8888P"
"#;
extern "C" {
fn main();
}
struct LogIfImpl;
#[crate_interface::impl_interface]
impl axlog::LogIf for LogIfImpl {
fn console_write_str(s: &str) {
axhal::console::write_bytes(s.as_bytes());
}
fn current_time() -> core::time::Duration {
axhal::time::monotonic_time()
}
fn current_cpu_id() -> Option<usize> {
#[cfg(feature = "smp")]
if is_init_ok() {
Some(axhal::cpu::this_cpu_id())
} else {
None
}
#[cfg(not(feature = "smp"))]
Some(0)
}
fn current_task_id() -> Option<u64> {
if is_init_ok() {
#[cfg(feature = "multitask")]
{
axtask::current_may_uninit().map(|curr| curr.id().as_u64())
}
#[cfg(not(feature = "multitask"))]
None
} else {
None
}
}
}
use core::sync::atomic::{AtomicUsize, Ordering};
static INITED_CPUS: AtomicUsize = AtomicUsize::new(0);
fn is_init_ok() -> bool {
INITED_CPUS.load(Ordering::Acquire) == axconfig::SMP
}
#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) -> ! {
ax_println!("{}", LOGO);
ax_println!(
"\
arch = {}\n\
platform = {}\n\
target = {}\n\
smp = {}\n\
build_mode = {}\n\
log_level = {}\n\
",
option_env!("AX_ARCH").unwrap_or(""),
option_env!("AX_PLATFORM").unwrap_or(""),
option_env!("AX_TARGET").unwrap_or(""),
option_env!("AX_SMP").unwrap_or(""),
option_env!("AX_MODE").unwrap_or(""),
option_env!("AX_LOG").unwrap_or(""),
);
#[cfg(feature = "rtc")]
ax_println!(
"Boot at {}\n",
chrono::DateTime::from_timestamp_nanos(axhal::time::wall_time_nanos() as _),
);
axlog::init();
axlog::set_max_level(option_env!("AX_LOG").unwrap_or("")); info!("Logging is enabled.");
info!("Primary CPU {} started, dtb = {:#x}.", cpu_id, dtb);
info!("Found physcial memory regions:");
for r in axhal::mem::memory_regions() {
info!(
" [{:x?}, {:x?}) {} ({:?})",
r.paddr,
r.paddr + r.size,
r.name,
r.flags
);
}
#[cfg(feature = "alloc")]
init_allocator();
#[cfg(feature = "paging")]
axmm::init_memory_management();
info!("Initialize platform devices...");
axhal::platform_init();
#[cfg(feature = "multitask")]
axtask::init_scheduler();
#[cfg(any(feature = "fs", feature = "net", feature = "display"))]
{
#[allow(unused_variables)]
let all_devices = axdriver::init_drivers();
#[cfg(feature = "fs")]
axfs::init_filesystems(all_devices.block);
#[cfg(feature = "net")]
axnet::init_network(all_devices.net);
#[cfg(feature = "display")]
axdisplay::init_display(all_devices.display);
}
#[cfg(feature = "smp")]
self::mp::start_secondary_cpus(cpu_id);
#[cfg(feature = "irq")]
{
info!("Initialize interrupt handlers...");
init_interrupt();
}
#[cfg(all(feature = "tls", not(feature = "multitask")))]
{
info!("Initialize thread local storage...");
init_tls();
}
info!("Primary CPU {} init OK.", cpu_id);
INITED_CPUS.fetch_add(1, Ordering::Relaxed);
ctor_bare::call_ctors();
while !is_init_ok() {
core::hint::spin_loop();
}
unsafe { main() };
#[cfg(feature = "multitask")]
axtask::exit(0);
#[cfg(not(feature = "multitask"))]
{
debug!("main task exited: exit_code={}", 0);
axhal::misc::terminate();
}
}
#[cfg(feature = "alloc")]
fn init_allocator() {
use axhal::mem::{memory_regions, phys_to_virt, MemRegionFlags};
info!("Initialize global memory allocator...");
info!(" use {} allocator.", axalloc::global_allocator().name());
let mut max_region_size = 0;
let mut max_region_paddr = 0.into();
for r in memory_regions() {
if r.flags.contains(MemRegionFlags::FREE) && r.size > max_region_size {
max_region_size = r.size;
max_region_paddr = r.paddr;
}
}
for r in memory_regions() {
if r.flags.contains(MemRegionFlags::FREE) && r.paddr == max_region_paddr {
axalloc::global_init(phys_to_virt(r.paddr).as_usize(), r.size);
break;
}
}
for r in memory_regions() {
if r.flags.contains(MemRegionFlags::FREE) && r.paddr != max_region_paddr {
axalloc::global_add_memory(phys_to_virt(r.paddr).as_usize(), r.size)
.expect("add heap memory region failed");
}
}
}
#[cfg(feature = "irq")]
fn init_interrupt() {
use axhal::time::TIMER_IRQ_NUM;
const PERIODIC_INTERVAL_NANOS: u64 =
axhal::time::NANOS_PER_SEC / axconfig::TICKS_PER_SEC as u64;
#[percpu::def_percpu]
static NEXT_DEADLINE: u64 = 0;
fn update_timer() {
let now_ns = axhal::time::monotonic_time_nanos();
let mut deadline = unsafe { NEXT_DEADLINE.read_current_raw() };
if now_ns >= deadline {
deadline = now_ns + PERIODIC_INTERVAL_NANOS;
}
unsafe { NEXT_DEADLINE.write_current_raw(deadline + PERIODIC_INTERVAL_NANOS) };
axhal::time::set_oneshot_timer(deadline);
}
axhal::irq::register_handler(TIMER_IRQ_NUM, || {
update_timer();
#[cfg(feature = "multitask")]
axtask::on_timer_tick();
});
axhal::arch::enable_irqs();
}
#[cfg(all(feature = "tls", not(feature = "multitask")))]
fn init_tls() {
let main_tls = axhal::tls::TlsArea::alloc();
unsafe { axhal::arch::write_thread_pointer(main_tls.tls_ptr() as usize) };
core::mem::forget(main_tls);
}