1use alloc::{
2 string::{String, ToString},
3 sync::Arc,
4};
5
6use ax_runtime::hal::cpu::uspace::UserContext;
7use ax_task::{AxTaskExt, spawn_task_with};
8
9use crate::{
10 file::{FD_TABLE, FileTable},
11 mm::{copy_from_kernel, load_user_app, new_user_aspace_empty},
12 pseudofs::{self, dev::tty},
13 sync::{Mutex, PreemptIrqSaveGuard, RwLock},
14 task::{
15 PidReservation, PidReservationKind, Process, ProcessData, ProcessDataInit, ProcessImage,
16 ROOT_PID_NS, Tgid, Thread, Tid, TidNumber, add_task_to_table, new_user_task,
17 spawn_alarm_task,
18 },
19 tracepoint::tracepoint_init,
20};
21
22pub fn init(args: &[String], envs: &[String]) {
24 static_keys::global_init();
25 crate::cgroup::init();
26
27 tracepoint_init().expect("Failed to initialize tracepoints");
28
29 crate::ebpf::init_ebpf();
30 crate::perf::perf_event_init();
31 crate::kmod::init_kmod();
32
33 pseudofs::mount_all().expect("Failed to mount pseudofs");
34 spawn_alarm_task();
35 if ax_driver::cpufreq::calibrate_wanted() {
39 run_opp_calibration();
40 } else {
41 spawn_cpufreq_governor();
42 }
43 pseudofs::usbfs::start_event_pump();
44
45 ax_alloc::register_page_reclaim_fn(ax_fs_ng::vfs::page_cache_reclaim);
46
47 let loc = ax_fs_ng::vfs::current_fs_context()
48 .lock()
49 .resolve(&args[0])
50 .expect("Failed to resolve executable path");
51 let path = loc
52 .absolute_path()
53 .expect("Failed to get executable absolute path");
54 let name = loc.name().into_owned();
55
56 let mut uspace = new_user_aspace_empty()
57 .and_then(|mut it| {
58 copy_from_kernel(&mut it)?;
59 Ok(it)
60 })
61 .expect("Failed to create user address space");
62
63 let (entry_vaddr, ustack_top, auxv) = load_user_app(&mut uspace, loc, &args[0], args, envs)
64 .unwrap_or_else(|e| panic!("Failed to load user app: {}", e));
65
66 let uctx = UserContext::new(entry_vaddr.into(), ustack_top, 0);
67 let mut task = new_user_task(&name, uctx, 0);
68 task.ctx_mut().set_page_table_root(uspace.page_table_root());
69
70 const INIT_PID: u32 = 1;
79 let reservation = PidReservation::reserve(&ROOT_PID_NS, PidReservationKind::ProcessLeader)
80 .expect("failed to reserve init PID identity");
81 let pid = reservation
82 .number_in(&ROOT_PID_NS)
83 .expect("init PID reservation has no root binding")
84 .get();
85 assert_eq!(pid, INIT_PID);
86 let identity = reservation
87 .publish()
88 .expect("failed to publish init PID identity");
89 let tid_lease = identity
90 .acquire_role::<Tid>()
91 .expect("failed to acquire init TID role");
92 let tgid_lease = identity
93 .acquire_role::<Tgid>()
94 .expect("failed to acquire init TGID role");
95 let proc = Process::new_init(identity.clone());
96 proc.add_thread(TidNumber::try_from(pid).expect("init TID must be non-zero"));
97
98 if let Err(err) = tty::bind_console_to(&proc) {
99 warn!("Failed to bind console tty: {err:?}");
100 }
101
102 let proc = ProcessData::new(
103 proc,
104 identity.clone(),
105 tgid_lease,
106 ProcessDataInit {
107 image: ProcessImage::new(
108 path.to_string(),
109 Arc::new(args.to_vec()),
110 Arc::new(envs.to_vec()),
111 auxv,
112 "/".to_string(),
113 "/".to_string(),
114 ),
115 aspace: Arc::new(Mutex::new(uspace)),
116 signal_actions: Arc::default(),
117 exit_signal: None,
118 wait_parent_tid: TidNumber::try_from(pid).expect("init TID must be non-zero"),
119 vm_aspace_shared: false,
120 },
121 );
122 crate::cgroup::attach_initial_process(&identity)
124 .expect("Failed to attach init process to cgroup root");
125
126 let mut scope = scope_local::Scope::new();
127 let mut fd_table = FileTable::new();
128 crate::file::add_stdio(&mut fd_table).expect("Failed to add stdio");
129 *FD_TABLE.scope_mut(&mut scope) = Arc::new(RwLock::new(fd_table));
130
131 let thr = Thread::new(
132 identity,
133 tid_lease,
134 proc,
135 None,
136 starry_signal::SignalSet::default(),
137 scope,
138 );
139 *task.task_ext_mut() = Some(AxTaskExt::from_impl(thr));
140
141 let task = {
142 let _guard = PreemptIrqSaveGuard::new();
143 let task = spawn_task_with(task, add_task_to_table);
144 tty::arm_console_irq();
145 task
146 };
147
148 let exit_code = task.join();
150 info!("Init process exited with code: {exit_code:?}");
151
152 let fs_context = ax_fs_ng::vfs::current_fs_context();
153 let cx = fs_context.lock();
154 if let Err(err) = cx.root_dir().unmount_all() {
160 warn!("shutdown: unmount_all failed (best-effort): {err:?}");
161 }
162 cx.root_dir()
163 .filesystem()
164 .flush()
165 .expect("Failed to flush rootfs");
166}
167
168fn run_opp_calibration() {
175 info!("cpufreq: running OPP calibration sweep (governor disabled this boot)");
176 for &(cluster_idx, cpu) in &[(0usize, 0usize), (1, 4), (2, 6)] {
177 let task = ax_task::spawn_raw(
178 move || {
179 ax_task::set_current_affinity(ax_task::AxCpuMask::one_shot(cpu));
180 ax_driver::cpufreq::calibrate_cluster(cluster_idx, cpu);
181 },
182 String::from("cpufreq-cal"),
183 ax_task::default_task_stack_size(),
184 );
185 task.join();
186 }
187 info!("cpufreq: OPP calibration sweep complete");
188}
189
190fn spawn_cpufreq_governor() {
203 if !ax_driver::cpufreq::governor_wanted() {
204 return;
205 }
206 info!("Initialize cpufreq ondemand governor...");
207 ax_task::spawn_raw(
208 cpufreq_governor_loop,
209 String::from("cpufreq-gov"),
210 ax_task::default_task_stack_size(),
211 );
212}
213
214fn cpufreq_governor_loop() {
220 let period = core::time::Duration::from_millis(ax_driver::cpufreq::governor_period_ms());
221 loop {
222 ax_task::sleep(period);
223 let mut busy = [0u64; 8];
226 for (cpu, slot) in busy.iter_mut().enumerate() {
227 *slot = ax_task::cpu_busy_ticks(cpu);
228 }
229 ax_driver::cpufreq::governor_poll(&busy);
230 }
231}