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 ax_driver::cpufreq::log_frequency_readout();
45 pseudofs::usbfs::start_event_pump();
46
47 ax_alloc::register_page_reclaim_fn(ax_fs_ng::vfs::page_cache_reclaim);
48
49 let loc = ax_fs_ng::vfs::current_fs_context()
50 .lock()
51 .resolve(&args[0])
52 .expect("Failed to resolve executable path");
53 let path = loc
54 .absolute_path()
55 .expect("Failed to get executable absolute path");
56 let name = loc.name().into_owned();
57
58 let mut uspace = new_user_aspace_empty()
59 .and_then(|mut it| {
60 copy_from_kernel(&mut it)?;
61 Ok(it)
62 })
63 .expect("Failed to create user address space");
64
65 let (entry_vaddr, ustack_top, auxv) = load_user_app(&mut uspace, loc, &args[0], args, envs)
66 .unwrap_or_else(|e| panic!("Failed to load user app: {}", e));
67
68 let uctx = UserContext::new(entry_vaddr.into(), ustack_top, 0);
69 let mut task = new_user_task(&name, uctx, 0);
70 task.ctx_mut().set_page_table_root(uspace.page_table_root());
71
72 const INIT_PID: u32 = 1;
81 let reservation = PidReservation::reserve(&ROOT_PID_NS, PidReservationKind::ProcessLeader)
82 .expect("failed to reserve init PID identity");
83 let pid = reservation
84 .number_in(&ROOT_PID_NS)
85 .expect("init PID reservation has no root binding")
86 .get();
87 assert_eq!(pid, INIT_PID);
88 let identity = reservation
89 .publish()
90 .expect("failed to publish init PID identity");
91 let tid_lease = identity
92 .acquire_role::<Tid>()
93 .expect("failed to acquire init TID role");
94 let tgid_lease = identity
95 .acquire_role::<Tgid>()
96 .expect("failed to acquire init TGID role");
97 let proc = Process::new_init(identity.clone());
98 proc.add_thread(TidNumber::try_from(pid).expect("init TID must be non-zero"));
99
100 if let Err(err) = tty::bind_console_to(&proc) {
101 warn!("Failed to bind console tty: {err:?}");
102 }
103
104 let proc = ProcessData::new(
105 proc,
106 identity.clone(),
107 tgid_lease,
108 ProcessDataInit {
109 image: ProcessImage::new(
110 path.to_string(),
111 Arc::new(args.to_vec()),
112 Arc::new(envs.to_vec()),
113 auxv,
114 "/".to_string(),
115 "/".to_string(),
116 ),
117 aspace: Arc::new(Mutex::new(uspace)),
118 signal_actions: Arc::default(),
119 exit_signal: None,
120 wait_parent_tid: TidNumber::try_from(pid).expect("init TID must be non-zero"),
121 vm_aspace_shared: false,
122 },
123 );
124 crate::cgroup::attach_initial_process(&identity)
126 .expect("Failed to attach init process to cgroup root");
127
128 let mut scope = scope_local::Scope::new();
129 let mut fd_table = FileTable::new();
130 crate::file::add_stdio(&mut fd_table).expect("Failed to add stdio");
131 *FD_TABLE.scope_mut(&mut scope) = Arc::new(RwLock::new(fd_table));
132
133 let thr = Thread::new(
134 identity,
135 tid_lease,
136 proc,
137 None,
138 starry_signal::SignalSet::default(),
139 scope,
140 );
141 *task.task_ext_mut() = Some(AxTaskExt::from_impl(thr));
142
143 let task = {
144 let _guard = PreemptIrqSaveGuard::new();
145 let task = spawn_task_with(task, add_task_to_table);
146 tty::arm_console_irq();
147 task
148 };
149
150 let exit_code = task.join();
152 info!("Init process exited with code: {exit_code:?}");
153
154 let fs_context = ax_fs_ng::vfs::current_fs_context();
155 let cx = fs_context.lock();
156 if let Err(err) = cx.root_dir().unmount_all() {
162 warn!("shutdown: unmount_all failed (best-effort): {err:?}");
163 }
164 cx.root_dir()
165 .filesystem()
166 .flush()
167 .expect("Failed to flush rootfs");
168}
169
170fn run_opp_calibration() {
177 info!("cpufreq: running OPP calibration sweep (governor disabled this boot)");
178 for &(cluster_idx, cpu) in &[(0usize, 0usize), (1, 4), (2, 6)] {
179 let task = ax_task::spawn_raw(
180 move || {
181 ax_task::set_current_affinity(ax_task::AxCpuMask::one_shot(cpu));
182 ax_driver::cpufreq::calibrate_cluster(cluster_idx, cpu);
183 },
184 String::from("cpufreq-cal"),
185 ax_task::default_task_stack_size(),
186 );
187 task.join();
188 }
189 info!("cpufreq: OPP calibration sweep complete");
190}
191
192fn spawn_cpufreq_governor() {
205 if !ax_driver::cpufreq::governor_wanted() {
206 return;
207 }
208 info!("Initialize cpufreq ondemand governor...");
209 ax_task::spawn_raw(
210 cpufreq_governor_loop,
211 String::from("cpufreq-gov"),
212 ax_task::default_task_stack_size(),
213 );
214}
215
216fn cpufreq_governor_loop() {
222 let period = core::time::Duration::from_millis(ax_driver::cpufreq::governor_period_ms());
223 loop {
224 ax_task::sleep(period);
225 let mut busy = [0u64; 8];
228 for (cpu, slot) in busy.iter_mut().enumerate() {
229 *slot = ax_task::cpu_busy_ticks(cpu);
230 }
231 ax_driver::cpufreq::governor_poll(&busy);
232 }
233}