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