Skip to main content

starry_kernel/
entry.rs

1use alloc::{
2    string::{String, ToString},
3    sync::Arc,
4};
5
6use ax_kernel_guard::NoPreemptIrqSave;
7use ax_runtime::hal::cpu::uspace::UserContext;
8use ax_sync::Mutex;
9use ax_task::{AxTaskExt, spawn_task};
10use starry_process::{Pid, Process};
11
12use crate::{
13    file::FD_TABLE,
14    mm::{copy_from_kernel, load_user_app, new_user_aspace_empty},
15    pseudofs::{self, dev::tty},
16    task::{ProcessData, ProcessImage, Thread, add_task_to_table, new_user_task, spawn_alarm_task},
17    tracepoint::tracepoint_init,
18};
19
20/// Initialize and run initproc.
21pub fn init(args: &[String], envs: &[String]) {
22    static_keys::global_init();
23
24    tracepoint_init().expect("Failed to initialize tracepoints");
25
26    crate::ebpf::init_ebpf();
27    crate::perf::perf_event_init();
28    crate::kmod::init_kmod();
29
30    pseudofs::mount_all().expect("Failed to mount pseudofs");
31    spawn_alarm_task();
32    pseudofs::usbfs::start_event_pump();
33
34    ax_alloc::register_page_reclaim_fn(ax_fs_ng::vfs::page_cache_reclaim);
35
36    let loc = ax_fs_ng::vfs::current_fs_context()
37        .lock()
38        .resolve(&args[0])
39        .expect("Failed to resolve executable path");
40    let path = loc
41        .absolute_path()
42        .expect("Failed to get executable absolute path");
43    let name = loc.name().into_owned();
44
45    let mut uspace = new_user_aspace_empty()
46        .and_then(|mut it| {
47            copy_from_kernel(&mut it)?;
48            Ok(it)
49        })
50        .expect("Failed to create user address space");
51
52    let (entry_vaddr, ustack_top, auxv) = load_user_app(&mut uspace, loc, &args[0], args, envs)
53        .unwrap_or_else(|e| panic!("Failed to load user app: {}", e));
54
55    let uctx = UserContext::new(entry_vaddr.into(), ustack_top, 0);
56    let mut task = new_user_task(&name, uctx, 0);
57    task.ctx_mut().set_page_table_root(uspace.page_table_root());
58
59    // PID 1 must really be 1: the init process is the root of the process
60    // hierarchy and userspace (e.g. systemd's `getpid() == 1` system-manager
61    // check) relies on it. The scheduler task id is an internal counter that is
62    // already past 1 by the time we spawn the user init (kernel helper tasks
63    // took the low ids), so we pin the user-visible pid/tid to 1 and leave the
64    // scheduler id untouched. `Thread::tid` is already decoupled from the
65    // scheduler id (see its field doc), so this only requires the table keys to
66    // follow the thread tid rather than `task.id()`.
67    const INIT_PID: Pid = 1;
68    let pid = INIT_PID;
69    let proc = Process::new_init(pid);
70    proc.add_thread(pid);
71
72    if let Err(err) = tty::bind_console_to(&proc) {
73        warn!("Failed to bind console tty: {err:?}");
74    }
75
76    let proc = ProcessData::new(
77        proc,
78        ProcessImage::new(
79            path.to_string(),
80            Arc::new(args.to_vec()),
81            Arc::new(envs.to_vec()),
82            auxv,
83            "/".to_string(),
84            "/".to_string(),
85        ),
86        Arc::new(Mutex::new(uspace)),
87        Arc::default(),
88        None,
89        pid,
90        false,
91    );
92
93    let mut scope = scope_local::Scope::new();
94    crate::file::add_stdio(&mut FD_TABLE.scope_mut(&mut scope).write())
95        .expect("Failed to add stdio");
96
97    let thr = Thread::new(pid, proc, None, starry_signal::SignalSet::default(), scope);
98    *task.task_ext_mut() = Some(AxTaskExt::from_impl(thr));
99
100    let task = {
101        let _guard = NoPreemptIrqSave::new();
102        let task = spawn_task(task);
103        add_task_to_table(&task);
104        tty::arm_console_irq();
105        task
106    };
107
108    // TODO: wait for all processes to finish
109    let exit_code = task.join();
110    info!("Init process exited with code: {exit_code:?}");
111
112    let fs_context = ax_fs_ng::vfs::current_fs_context();
113    let cx = fs_context.lock();
114    cx.root_dir()
115        .unmount_all()
116        .expect("Failed to unmount all filesystems");
117    cx.root_dir()
118        .filesystem()
119        .flush()
120        .expect("Failed to flush rootfs");
121}