• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &gtask_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