1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12 #define _GNU_SOURCE
13 #include <chcore/ipc.h>
14 #include <chcore/launcher.h>
15 #include <chcore/proc.h>
16 #include <chcore/syscall.h>
17 #include <chcore-internal/procmgr_defs.h>
18 #include <pthread.h>
19 #include <string.h>
20 #include <malloc.h>
21 #include <sys/mman.h>
22 #include <sched.h>
23 #include <errno.h>
24 #include <chcore/pthread.h>
25
26 #include "proc_node.h"
27 #include "procmgr_dbg.h"
28 #include "srvmgr.h"
29 #include "oh_mem_ops.h"
30
31 #define READ_ONCE(t) (*(volatile typeof((t)) *)(&(t)))
32
str_join(char * delimiter,char * strings[],int n)33 static char *str_join(char *delimiter, char *strings[], int n)
34 {
35 char buf[256];
36 size_t size = 256 - 1; /* 1 for the trailing \0. */
37 size_t dlen = strlen(delimiter);
38 char *dst = buf;
39 int i;
40 for (i = 0; i < n; ++i) {
41 size_t l = strlen(strings[i]);
42 if (i > 0)
43 l += dlen;
44 if (l > size) {
45 printf("str_join string buffer overflow\n");
46 break;
47 }
48 if (i > 0) {
49 strlcpy(dst, delimiter, size);
50 strlcpy(dst + dlen, strings[i], size - dlen);
51 } else {
52 strlcpy(dst, strings[i], size);
53 }
54 dst += l;
55 size -= l;
56 }
57 *dst = 0;
58 return strdup(buf);
59 }
60
61 #ifdef CHCORE_OH_TEE
62 #define MAX_ARGC_SPAWN_PROC_NAME 3
63
handle_spawn(ipc_msg_t * ipc_msg,badge_t client_badge,struct proc_request * pr)64 static void handle_spawn(ipc_msg_t *ipc_msg, badge_t client_badge,
65 struct proc_request *pr)
66 {
67 int input_argc = pr->spawn.argc;
68 int envp_argc = pr->spawn.envc;
69 char *input_argv[PROC_REQ_ARGC_MAX];
70 char *envp_argv[PROC_REQ_ENVC_MAX];
71 struct proc_node *proc_node;
72 struct new_process_args np_args;
73
74 /* Translate to argv pointers from argv offsets. */
75 for (int i = 0; i < input_argc; ++i)
76 input_argv[i] = &pr->spawn.argv_text[pr->spawn.argv_off[i]];
77
78 for (int i = 0; i < envp_argc; ++i)
79 envp_argv[i] = &pr->spawn.envp_text[pr->spawn.envp_off[i]];
80
81 np_args.envp_argc = envp_argc;
82 np_args.envp_argv = envp_argv;
83 if (pr->spawn.attr_valid) {
84 np_args.stack_size = pr->spawn.attr.stack_size;
85 np_args.heap_size = pr->spawn.attr.heap_size;
86 memcpy(&np_args.puuid, &pr->spawn.attr.uuid, sizeof(spawn_uuid_t));
87 } else {
88 np_args.stack_size = MAIN_THREAD_STACK_SIZE;
89 np_args.heap_size = (unsigned long)-1;
90 memset(&np_args.puuid, 0, sizeof(spawn_uuid_t));
91 }
92
93 proc_node =
94 procmgr_launch_process(input_argc,
95 input_argv,
96 str_join(" ",
97 &input_argv[0],
98 input_argc < MAX_ARGC_SPAWN_PROC_NAME ?
99 input_argc :
100 MAX_ARGC_SPAWN_PROC_NAME),
101 true,
102 client_badge,
103 &np_args,
104 COMMON_APP);
105 if (proc_node == NULL) {
106 ipc_return(ipc_msg, -1);
107 } else {
108 pr->spawn.main_thread_id = usys_get_thread_id(proc_node->proc_mt_cap);
109 ipc_return(ipc_msg, proc_node->pid);
110 }
111 }
112 #endif /* CHCORE_OH_TEE */
113
handle_newproc(ipc_msg_t * ipc_msg,badge_t client_badge,struct proc_request * pr)114 static void handle_newproc(ipc_msg_t *ipc_msg, badge_t client_badge,
115 struct proc_request *pr)
116 {
117 int input_argc = pr->newproc.argc;
118 char *input_argv[PROC_REQ_ARGC_MAX];
119 struct proc_node *proc_node;
120
121 if (input_argc > PROC_REQ_ARGC_MAX) {
122 ipc_return(ipc_msg, -EINVAL);
123 }
124
125 /* Translate to argv pointers from argv offsets. */
126 for (int i = 0; i < input_argc; ++i) {
127 if (pr->newproc.argv_off[i] >= PROC_REQ_TEXT_SIZE) {
128 ipc_return(ipc_msg, -EINVAL);
129 }
130 input_argv[i] = &pr->newproc.argv_text[pr->newproc.argv_off[i]];
131 }
132 pr->newproc.argv_text[PROC_REQ_TEXT_SIZE - 1] = '\0';
133
134 proc_node =
135 procmgr_launch_process(input_argc,
136 input_argv,
137 str_join(" ", &input_argv[0], input_argc),
138 true,
139 client_badge,
140 NULL,
141 COMMON_APP);
142 if (proc_node == NULL) {
143 ipc_return(ipc_msg, -1);
144 } else {
145 ipc_return(ipc_msg, proc_node->pid);
146 }
147 }
148
handle_kill(ipc_msg_t * ipc_msg,struct proc_request * pr)149 static void handle_kill(ipc_msg_t *ipc_msg, struct proc_request *pr)
150 {
151 pid_t pid = pr->kill.pid;
152 struct proc_node *proc_to_kill;
153 int proc_cap, ret;
154
155 debug("Kill process with pid: %d\n", pid);
156
157 /* We only support to kill a process with the specified pid. */
158 if (pid <= 0) {
159 error("kill: We only support positive pid. pid: %d\n", pid);
160 ipc_return(ipc_msg, -EINVAL);
161 }
162
163 proc_to_kill = get_proc_node_by_pid(pid);
164 if (!proc_to_kill) {
165 error("kill: No process with pid: %d\n", pid);
166 ipc_return(ipc_msg, -ESRCH);
167 }
168
169 proc_cap = proc_to_kill->proc_cap;
170 ret = usys_kill_group(proc_cap);
171 debug("[procmgr] usys_kill_group return value: %d\n", ret);
172 if (ret) {
173 error("kill: usys_kill_group returns an error value: %d\n", ret);
174 ipc_return(ipc_msg, -EINVAL);
175 }
176
177 ipc_return(ipc_msg, 0);
178 }
179
handle_wait(ipc_msg_t * ipc_msg,badge_t client_badge,struct proc_request * pr)180 static void handle_wait(ipc_msg_t *ipc_msg, badge_t client_badge,
181 struct proc_request *pr)
182 {
183 struct proc_node *client_proc;
184 struct proc_node *child;
185 struct proc_node *proc;
186 pid_t ret_pid;
187
188 /* Get client_proc */
189 client_proc = get_proc_node(client_badge);
190 assert(client_proc);
191
192 while (1) {
193 /* Use a lock to synsynchronize this function and del_proc_node */
194 pthread_mutex_lock(&client_proc->lock);
195 child = NULL;
196 for_each_in_list (
197 proc, struct proc_node, node, &client_proc->children) {
198 if (proc->pid == pr->wait.pid || pr->wait.pid == -1) {
199 child = proc;
200 break;
201 }
202 }
203
204 if (!child || (child->pid != pr->wait.pid && pr->wait.pid != -1)) {
205 /* wrong pid */
206 pthread_mutex_unlock(&client_proc->lock);
207 ipc_return(ipc_msg, -ESRCH);
208 }
209
210 /* Found. */
211 debug("Found process with pid=%d proc=%p\n", pr->pid, child);
212
213 pthread_mutex_lock(&child->wait_lock);
214 if (READ_ONCE(child->state) == PROC_STATE_EXIT) {
215 /*
216 * The exit status has been set but the node
217 * has not been removed from its parent process`s
218 * child list.
219 */
220 debug("Process (pid=%d, proc=%p) exits with %d\n",
221 pr->wait.pid,
222 child,
223 child->exitstatus);
224 pr->wait.exitstatus = child->exitstatus;
225 ret_pid = child->pid;
226 /*
227 * Delete the child node from the children list of
228 * parent. and recycle the proc node of child.
229 */
230 pthread_mutex_lock(&recycle_lock);
231 list_del(&child->node);
232 free_proc_node_resource(child);
233 free(child);
234 pthread_mutex_unlock(&recycle_lock);
235 pthread_mutex_unlock(&child->wait_lock);
236 pthread_mutex_unlock(&client_proc->lock);
237 ipc_return(ipc_msg, ret_pid);
238 } else {
239 pthread_mutex_unlock(&client_proc->lock);
240 pthread_cond_wait(&child->wait_cv, &child->wait_lock);
241 pthread_mutex_unlock(&child->wait_lock);
242 }
243 }
244 }
245
handle_get_thread_cap(ipc_msg_t * ipc_msg,badge_t client_badge,struct proc_request * pr)246 static void handle_get_thread_cap(ipc_msg_t *ipc_msg, badge_t client_badge,
247 struct proc_request *pr)
248 {
249 struct proc_node *client_proc;
250 struct proc_node *child;
251 struct proc_node *proc;
252 cap_t proc_mt_cap;
253
254 /* Get client_proc */
255 client_proc = get_proc_node(client_badge);
256 assert(client_proc);
257
258 pthread_mutex_lock(&client_proc->lock);
259
260 child = NULL;
261 for_each_in_list (proc, struct proc_node, node, &client_proc->children) {
262 if (proc->pid == pr->get_mt_cap.pid) {
263 child = proc;
264 }
265 }
266 if (!child
267 || (child->pid != pr->get_mt_cap.pid && pr->get_mt_cap.pid != -1)) {
268 pthread_mutex_unlock(&client_proc->lock);
269 ipc_return(ipc_msg, -ENOENT);
270 }
271
272 /* Found. */
273 debug("Found process with pid=%d proc=%p\n", pr->get_mt_cap.pid, child);
274
275 proc_mt_cap = child->proc_mt_cap;
276
277 pthread_mutex_unlock(&client_proc->lock);
278
279 /*
280 * Set the main-thread cap in the ipc_msg and
281 * the following ipc_return_with_cap will transfer the cap.
282 */
283 ipc_msg->cap_slot_number = 1;
284 ipc_set_msg_cap(ipc_msg, 0, proc_mt_cap);
285 ipc_return_with_cap(ipc_msg, 0);
286 }
287
288 #ifdef CHCORE_OH_TEE
handle_info_proc_by_pid(ipc_msg_t * ipc_msg,badge_t client_badge,struct proc_request * pr)289 static void handle_info_proc_by_pid(ipc_msg_t *ipc_msg, badge_t client_badge,
290 struct proc_request *pr)
291 {
292 struct proc_node *proc;
293 int ret = 0;
294
295 proc = get_proc_node_by_pid(pr->info_proc_by_pid.pid);
296
297 if (proc == NULL) {
298 ret = -ENOENT;
299 goto out;
300 }
301
302 memcpy(&pr->info_proc_by_pid.info.uuid, &proc->puuid, sizeof(spawn_uuid_t));
303 pr->info_proc_by_pid.info.stack_size = proc->stack_size;
304
305 out:
306 ipc_return(ipc_msg, ret);
307 }
308 #endif /* CHCORE_OH_TEE */
309
init_procmgr(void)310 static int init_procmgr(void)
311 {
312 /* Init proc_node manager */
313 init_proc_node_mgr();
314
315 /* Init server manager */
316 init_srvmgr();
317
318 #ifdef CHCORE_OH_TEE
319 oh_mem_ops_init();
320 #endif /* CHCORE_OH_TEE */
321
322 return 0;
323 }
324
procmgr_dispatch(ipc_msg_t * ipc_msg,badge_t client_badge)325 void procmgr_dispatch(ipc_msg_t *ipc_msg, badge_t client_badge)
326 {
327 struct proc_request *pr;
328
329 debug("new request from client_badge: 0x%x\n", client_badge);
330
331 if (ipc_msg->data_len < sizeof(pr->req)) {
332 error("procmgr: no operation num\n");
333 ipc_return(ipc_msg, -EINVAL);
334 }
335
336 pr = (struct proc_request *)ipc_get_msg_data(ipc_msg);
337 debug("req: %d\n", pr->req);
338
339 switch (pr->req) {
340 case PROC_REQ_NEWPROC:
341 handle_newproc(ipc_msg, client_badge, pr);
342 break;
343 case PROC_REQ_WAIT:
344 handle_wait(ipc_msg, client_badge, pr);
345 break;
346 case PROC_REQ_GET_MT_CAP:
347 handle_get_thread_cap(ipc_msg, client_badge, pr);
348 break;
349 /*
350 * Get server_cap by server_id.
351 * Skip get_proc_node for the following IPC REQ.
352 * This is because FSM will invoke this IPC but it is not
353 * booted by procmgr and @client_proc is not required in the IPC.
354 */
355 case PROC_REQ_GET_SERVER_CAP:
356 handle_get_server_cap(ipc_msg, pr);
357 break;
358 case PROC_REQ_KILL:
359 handle_kill(ipc_msg, pr);
360 break;
361 #ifdef CHCORE_OH_TEE
362 case PROC_REQ_SPAWN:
363 handle_spawn(ipc_msg, client_badge, pr);
364 break;
365 case PROC_REQ_INFO_PROC_BY_PID:
366 handle_info_proc_by_pid(ipc_msg, client_badge, pr);
367 break;
368 case PROC_REQ_TASK_MAP_NS:
369 handle_task_map_ns(ipc_msg, client_badge);
370 break;
371 case PROC_REQ_TASK_UNMAP_NS:
372 handle_task_unmap_ns(ipc_msg, client_badge);
373 break;
374 case PROC_REQ_TEE_ALLOC_SHM:
375 handle_tee_alloc_sharemem(ipc_msg, client_badge);
376 break;
377 case PROC_REQ_TEE_GET_SHM:
378 handle_tee_get_sharemem(ipc_msg, client_badge);
379 break;
380 case PROC_REQ_TEE_FREE_SHM:
381 handle_tee_free_sharemem(ipc_msg, client_badge);
382 break;
383 #endif /* CHCORE_OH_TEE */
384 default:
385 error("Invalid request type!\n");
386 /* Client should check if the return value is correct */
387 ipc_return(ipc_msg, -EBADRQC);
388 break;
389 }
390 }
391
392 void *recycle_routine(void *arg);
393
394 /*
395 * Procmgr is the first user process and there is no system services now.
396 * So, override the default libc_connect_services.
397 */
libc_connect_services(char * envp[])398 void libc_connect_services(char *envp[])
399 {
400 procmgr_ipc_struct->conn_cap = 0;
401 procmgr_ipc_struct->server_id = PROC_MANAGER;
402 return;
403 }
404
boot_default_servers(void)405 void boot_default_servers(void)
406 {
407 char *srv_path;
408 cap_t tmpfs_cap;
409 struct proc_node *proc_node;
410
411 /* Do not modify the order of creating system servers */
412 printf("User Init: booting fs server (FSMGR and real FS) \n");
413
414 srv_path = "/tmpfs.srv";
415 proc_node =
416 procmgr_launch_basic_server(1, &srv_path, "tmpfs", true, INIT_BADGE);
417 if (proc_node == NULL) {
418 BUG("procmgr_launch_basic_server tmpfs failed");
419 }
420 tmpfs_cap = proc_node->proc_mt_cap;
421 /*
422 * We set the cap of tmpfs before starting fsm to ensure that tmpfs is
423 * available after fsm is started.
424 */
425 set_tmpfs_cap(tmpfs_cap);
426
427 /* FSM gets badge 2 and tmpfs uses the fixed badge (10) for it */
428 srv_path = "/fsm.srv";
429 proc_node =
430 procmgr_launch_basic_server(1, &srv_path, "fsm", true, INIT_BADGE);
431 if (proc_node == NULL) {
432 BUG("procmgr_launch_basic_server fsm failed");
433 }
434 fsm_server_cap = proc_node->proc_mt_cap;
435 fsm_ipc_struct->server_id = FS_MANAGER;
436 }
437
handler_thread_routine(void * arg)438 void *handler_thread_routine(void *arg)
439 {
440 int ret;
441 ret =
442 ipc_register_server(procmgr_dispatch, DEFAULT_CLIENT_REGISTER_HANDLER);
443 printf("[procmgr] register server value = %d\n", ret);
444 usys_wait(usys_create_notifc(), 1, NULL);
445 return NULL;
446 }
447
boot_default_apps(void)448 void boot_default_apps(void)
449 {
450 #ifdef CHCORE_OH_TEE
451 char *chanmgr_argv = "/chanmgr.srv";
452 struct proc_node *chanmgr_node = procmgr_launch_process(
453 1, &chanmgr_argv, "chanmgr", true, INIT_BADGE, NULL, COMMON_APP);
454 set_chanmgr_cap(chanmgr_node->proc_mt_cap);
455 /* Start OH-TEE gtask. */
456 char *gtask_argv = "/gtask.elf";
457 struct proc_node *gtask_node = procmgr_launch_process(
458 1, >ask_argv, "gtask", true, INIT_BADGE, NULL, COMMON_APP);
459 printf("procmgr_launch_process gtask pid %d\n", gtask_node->pid);
460 #endif /* CHCORE_OH_TEE */
461 }
462
main(int argc,char * argv[],char * envp[])463 int main(int argc, char *argv[], char *envp[])
464 {
465 cap_t cap;
466 pthread_t recycle_thread;
467 pthread_t procmgr_handler_tid;
468
469 pthread_create(&recycle_thread, NULL, recycle_routine, NULL);
470
471 init_procmgr();
472 cap = chcore_pthread_create(
473 &procmgr_handler_tid, NULL, handler_thread_routine, NULL);
474
475 __procmgr_server_cap = cap;
476
477 init_root_proc_node();
478
479 boot_default_servers();
480
481 boot_default_apps();
482
483 /* Boot some configurable servers which should be booted lazily */
484 boot_secondary_servers();
485
486 usys_wait(usys_create_notifc(), 1, NULL);
487 return 0;
488 }
489