1use alloc::{
2 string::{String, ToString},
3 sync::Arc,
4};
5
6use ax_fs_ng::vfs::current_fs_context;
7use ax_runtime::hal::cpu::user::UserContext;
8
9use crate::{
10 file::{FD_TABLE, FileTable, new_file_table_scope},
11 mm::{MmHandle, load_user_app, new_user_image_builder},
12 namespace::NsProxy,
13 pseudofs::{self, dev::tty},
14 sync::{Mutex, RwLock},
15 task::{
16 PidReservation, PidReservationKind, Process, ProcessData, ProcessDataInit, ProcessImage,
17 ROOT_PID_NS, Tgid, Thread, Tid, TidNumber, UserThreadOptions, kernel_thread_builder,
18 new_user_task, prepare_user_thread, sleep, spawn_alarm_task,
19 },
20 tracepoint::tracepoint_init,
21};
22
23pub fn init(args: &[String], envs: &[String]) {
25 crate::rdrive_osal::init();
27
28 crate::stop_machine::init();
29 crate::trap::init_handlers();
30 static_keys::global_init();
31 crate::cgroup::init();
32
33 tracepoint_init().expect("Failed to initialize tracepoints");
34
35 crate::ebpf::init_ebpf();
36 crate::perf::perf_event_init();
37 crate::kmod::init_kmod();
38
39 pseudofs::mount_all().expect("Failed to mount pseudofs");
40 spawn_alarm_task();
41 crate::mm::spawn_reclaimer_task();
42 if ax_driver::cpufreq::calibrate_wanted() {
46 run_opp_calibration();
47 } else {
48 spawn_cpufreq_governor();
49 }
50 ax_driver::cpufreq::log_frequency_readout();
52 pseudofs::usbfs::start_event_pump();
53
54 ax_alloc::register_page_reclaim_fn(ax_fs_ng::vfs::page_cache_reclaim);
55
56 let loc = current_fs_context()
57 .lock()
58 .resolve(&args[0])
59 .expect("Failed to resolve executable path");
60 let path = loc
61 .absolute_path()
62 .expect("Failed to get executable absolute path");
63 let name = loc.name().into_owned();
64
65 let mut image_builder =
66 new_user_image_builder().expect("Failed to create unpublished user address space");
67 let loaded_image = load_user_app(
68 &mut image_builder,
69 loc,
70 &args[0],
71 args,
72 envs,
73 &crate::task::Cred::root(),
74 )
75 .unwrap_or_else(|error| panic!("Failed to load user app: {error}"));
76 let prepared_image = image_builder
77 .finish(loaded_image)
78 .expect("loaded init image token no longer matches its address space");
79 let (uspace, entry_vaddr, ustack_top, auxv) = prepared_image.into_parts();
80
81 let uctx = UserContext::new(entry_vaddr.into(), ustack_top, 0);
82
83 const INIT_PID: u32 = 1;
92 let reservation = PidReservation::reserve(&ROOT_PID_NS, PidReservationKind::ProcessLeader)
93 .expect("failed to reserve init PID identity");
94 let pid = reservation
95 .number_in(&ROOT_PID_NS)
96 .expect("init PID reservation has no root binding")
97 .get();
98 assert_eq!(pid, INIT_PID);
99 let identity = reservation.identity();
100 let tid_lease = identity
101 .acquire_role::<Tid>()
102 .expect("failed to acquire init TID role");
103 let tgid_lease = identity
104 .acquire_role::<Tgid>()
105 .expect("failed to acquire init TGID role");
106 let proc = Process::new_init(identity.clone()).expect("failed to prepare init process");
107 proc.add_thread(TidNumber::try_from(pid).expect("init TID must be non-zero"));
108
109 if let Err(error) = tty::bind_console_to(&proc) {
110 warn!("Failed to bind console tty: {error:?}");
111 }
112
113 let proc = ProcessData::new(
114 proc,
115 identity.clone(),
116 tgid_lease,
117 ProcessDataInit::new(
118 ProcessImage::new(
119 path.to_string(),
120 Arc::new(args.to_vec()),
121 Arc::new(envs.to_vec()),
122 auxv,
123 "/".to_string(),
124 "/".to_string(),
125 ),
126 MmHandle::from_arc(Arc::new(Mutex::new(uspace)))
127 .expect("init MM identity must be unique"),
128 Arc::default(),
129 NsProxy::new_root(),
130 None,
131 TidNumber::try_from(pid).expect("init TID must be non-zero"),
132 ),
133 );
134 crate::cgroup::attach_initial_process(&identity)
136 .expect("Failed to attach init process to cgroup root");
137
138 let mut scope = scope_local::Scope::new();
139 let mut fd_table = FileTable::new();
140 crate::file::add_stdio(&mut fd_table).expect("Failed to add stdio");
141 *FD_TABLE.scope_mut(&mut scope) = new_file_table_scope(Arc::new(RwLock::new(fd_table)));
142
143 let thr = Thread::new(
144 identity.clone(),
145 tid_lease,
146 proc,
147 None,
148 starry_signal::SignalSet::default(),
149 scope,
150 )
151 .expect("failed to prepare init thread state");
152 let prepared_task = prepare_user_thread(
153 new_user_task(
154 uctx,
155 0,
156 TidNumber::try_from(pid).expect("init TID must be non-zero"),
157 ),
158 thr,
159 UserThreadOptions::new(&name).expect("failed to prepare init thread name"),
160 )
161 .expect("failed to prepare init task");
162 let staged_task = prepared_task.stage().expect("failed to stage init task");
163 let published_identity = reservation
164 .publish()
165 .expect("failed to publish init PID identity");
166 debug_assert!(Arc::ptr_eq(&published_identity, &identity));
167 staged_task.with_task(|task| task.as_thread().attach_pid_task(task));
168 tty::arm_console_irq();
169 let task = staged_task.activate();
170
171 let exit_code = task.join();
173 info!("Init process exited with code: {exit_code:?}");
174
175 let fs_context = current_fs_context();
176 let cx = fs_context.lock();
177 if let Err(err) = cx.root_dir().unmount_all() {
183 warn!("shutdown: unmount_all failed (best-effort): {err:?}");
184 }
185 cx.root_dir()
186 .filesystem()
187 .flush()
188 .expect("Failed to flush rootfs");
189}
190
191fn run_opp_calibration() {
198 info!("cpufreq: running OPP calibration sweep (governor disabled this boot)");
199 for &(cluster_idx, cpu) in &[(0usize, 0usize), (1, 4), (2, 6)] {
200 let mut affinity = ax_runtime::task::sched::CpuSet::empty(ax_runtime::hal::cpu_num());
201 let cpu_id =
202 u32::try_from(cpu).unwrap_or_else(|_| panic!("cpufreq CPU id {cpu} is out of range"));
203 assert!(
204 affinity.insert(ax_runtime::task::sched::CpuId::new(cpu_id)),
205 "cpufreq calibration CPU {cpu} is outside the runtime topology"
206 );
207 let task = kernel_thread_builder(String::from("cpufreq-cal"))
208 .affinity(affinity)
209 .spawn(move || ax_driver::cpufreq::calibrate_cluster(cluster_idx, cpu))
210 .expect("failed to spawn kernel thread");
211 let _exit_code = task.join().expect("failed to join kernel thread");
212 }
213 info!("cpufreq: OPP calibration sweep complete");
214}
215
216fn spawn_cpufreq_governor() {
229 if !ax_driver::cpufreq::governor_wanted() {
230 return;
231 }
232 info!("Initialize cpufreq ondemand governor...");
233 let _ = kernel_thread_builder(String::from("cpufreq-gov"))
234 .spawn(cpufreq_governor_loop)
235 .expect("failed to spawn kernel thread");
236}
237
238fn cpufreq_governor_loop() {
244 let period = core::time::Duration::from_millis(ax_driver::cpufreq::governor_period_ms());
245 loop {
246 sleep(period);
247 let mut busy = [0u64; 8];
250 for (cpu, slot) in busy.iter_mut().enumerate() {
251 *slot = ax_runtime::task::sched::cpu_busy_runtime_ns(
252 ax_runtime::task::sched::CpuId::new(cpu as u32),
253 )
254 .unwrap_or(0);
255 }
256 ax_driver::cpufreq::governor_poll(&busy);
257 }
258}