1use alloc::{string::String, sync::Arc};
2use axfs::{CURRENT_DIR, CURRENT_DIR_PATH, api::set_current_dir};
3use axhal::arch::UspaceContext;
4use axprocess::{Pid, init_proc};
5use axsignal::Signo;
6use axsync::Mutex;
7use starry_api::file::FD_TABLE;
8use starry_core::{
9 mm::{copy_from_kernel, load_user_app, map_trampoline, new_user_aspace_empty},
10 task::{ProcessData, TaskExt, ThreadData, add_thread_to_table, new_user_task},
11};
12
13pub fn run_user_app(args: &[String], envs: &[String]) -> Option<i32> {
14 let mut uspace = new_user_aspace_empty()
15 .and_then(|mut it| {
16 copy_from_kernel(&mut it)?;
17 map_trampoline(&mut it)?;
18 Ok(it)
19 })
20 .expect("Failed to create user address space");
21
22 let exe_path = args[0].clone();
23 let (dir, name) = exe_path.rsplit_once('/').unwrap_or(("", &exe_path));
24 set_current_dir(dir).expect("Failed to set current dir");
25
26 let (entry_vaddr, ustack_top) = load_user_app(&mut uspace, args, envs)
27 .unwrap_or_else(|e| panic!("Failed to load user app: {}", e));
28
29 let uctx = UspaceContext::new(entry_vaddr.into(), ustack_top, 2333);
30
31 let mut task = new_user_task(name, uctx, None);
32 task.ctx_mut().set_page_table_root(uspace.page_table_root());
33
34 let process_data = ProcessData::new(
35 exe_path,
36 Arc::new(Mutex::new(uspace)),
37 Arc::default(),
38 Some(Signo::SIGCHLD),
39 );
40
41 FD_TABLE
42 .deref_from(&process_data.ns)
43 .init_new(FD_TABLE.copy_inner());
44 CURRENT_DIR
45 .deref_from(&process_data.ns)
46 .init_new(CURRENT_DIR.copy_inner());
47 CURRENT_DIR_PATH
48 .deref_from(&process_data.ns)
49 .init_new(CURRENT_DIR_PATH.copy_inner());
50
51 let tid = task.id().as_u64() as Pid;
52 let process = init_proc().fork(tid).data(process_data).build();
53
54 let thread = process
55 .new_thread(tid)
56 .data(ThreadData::new(process.data().unwrap()))
57 .build();
58 add_thread_to_table(&thread);
59
60 task.init_task_ext(TaskExt::new(thread));
61
62 let task = axtask::spawn_task(task);
63
64 task.join()
66}