use alloc::{
string::{String, ToString},
sync::Arc,
};
use ax_kernel_guard::NoPreemptIrqSave;
use ax_runtime::hal::cpu::uspace::UserContext;
use ax_sync::Mutex;
use ax_task::{AxTaskExt, spawn_task_with};
use starry_process::{Pid, Process};
use crate::{
file::FD_TABLE,
mm::{copy_from_kernel, load_user_app, new_user_aspace_empty},
pseudofs::{self, dev::tty},
task::{ProcessData, ProcessImage, Thread, add_task_to_table, new_user_task, spawn_alarm_task},
tracepoint::tracepoint_init,
};
pub fn init(args: &[String], envs: &[String]) {
static_keys::global_init();
crate::cgroup::init();
tracepoint_init().expect("Failed to initialize tracepoints");
crate::ebpf::init_ebpf();
crate::perf::perf_event_init();
crate::kmod::init_kmod();
pseudofs::mount_all().expect("Failed to mount pseudofs");
spawn_alarm_task();
if ax_driver::cpufreq::calibrate_wanted() {
run_opp_calibration();
} else {
spawn_cpufreq_governor();
}
pseudofs::usbfs::start_event_pump();
ax_alloc::register_page_reclaim_fn(ax_fs_ng::vfs::page_cache_reclaim);
let loc = ax_fs_ng::vfs::current_fs_context()
.lock()
.resolve(&args[0])
.expect("Failed to resolve executable path");
let path = loc
.absolute_path()
.expect("Failed to get executable absolute path");
let name = loc.name().into_owned();
let mut uspace = new_user_aspace_empty()
.and_then(|mut it| {
copy_from_kernel(&mut it)?;
Ok(it)
})
.expect("Failed to create user address space");
let (entry_vaddr, ustack_top, auxv) = load_user_app(&mut uspace, loc, &args[0], args, envs)
.unwrap_or_else(|e| panic!("Failed to load user app: {}", e));
let uctx = UserContext::new(entry_vaddr.into(), ustack_top, 0);
let mut task = new_user_task(&name, uctx, 0);
task.ctx_mut().set_page_table_root(uspace.page_table_root());
const INIT_PID: Pid = 1;
let pid = INIT_PID;
let proc = Process::new_init(pid);
proc.add_thread(pid);
if let Err(err) = tty::bind_console_to(&proc) {
warn!("Failed to bind console tty: {err:?}");
}
let proc = ProcessData::new(
proc,
ProcessImage::new(
path.to_string(),
Arc::new(args.to_vec()),
Arc::new(envs.to_vec()),
auxv,
"/".to_string(),
"/".to_string(),
),
Arc::new(Mutex::new(uspace)),
Arc::default(),
None,
pid,
false,
);
crate::cgroup::attach_initial_process(pid)
.expect("Failed to attach init process to cgroup root");
let mut scope = scope_local::Scope::new();
crate::file::add_stdio(&mut FD_TABLE.scope_mut(&mut scope).write())
.expect("Failed to add stdio");
let thr = Thread::new(pid, proc, None, starry_signal::SignalSet::default(), scope);
*task.task_ext_mut() = Some(AxTaskExt::from_impl(thr));
let task = {
let _guard = NoPreemptIrqSave::new();
let task = spawn_task_with(task, add_task_to_table);
tty::arm_console_irq();
task
};
let exit_code = task.join();
info!("Init process exited with code: {exit_code:?}");
let fs_context = ax_fs_ng::vfs::current_fs_context();
let cx = fs_context.lock();
if let Err(err) = cx.root_dir().unmount_all() {
warn!("shutdown: unmount_all failed (best-effort): {err:?}");
}
cx.root_dir()
.filesystem()
.flush()
.expect("Failed to flush rootfs");
}
fn run_opp_calibration() {
info!("cpufreq: running OPP calibration sweep (governor disabled this boot)");
for &(cluster_idx, cpu) in &[(0usize, 0usize), (1, 4), (2, 6)] {
let task = ax_task::spawn_raw(
move || {
ax_task::set_current_affinity(ax_task::AxCpuMask::one_shot(cpu));
ax_driver::cpufreq::calibrate_cluster(cluster_idx, cpu);
},
String::from("cpufreq-cal"),
ax_task::default_task_stack_size(),
);
task.join();
}
info!("cpufreq: OPP calibration sweep complete");
}
fn spawn_cpufreq_governor() {
if !ax_driver::cpufreq::governor_wanted() {
return;
}
info!("Initialize cpufreq ondemand governor...");
ax_task::spawn_raw(
cpufreq_governor_loop,
String::from("cpufreq-gov"),
ax_task::default_task_stack_size(),
);
}
fn cpufreq_governor_loop() {
let period = core::time::Duration::from_millis(ax_driver::cpufreq::governor_period_ms());
loop {
ax_task::sleep(period);
let mut busy = [0u64; 8];
for (cpu, slot) in busy.iter_mut().enumerate() {
*slot = ax_task::cpu_busy_ticks(cpu);
}
ax_driver::cpufreq::governor_poll(&busy);
}
}