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 #include <assert.h>
13 #include <string.h>
14 #include <time.h>
15 #include <stdbool.h>
16 #include <sys/mman.h>
17 #include <chcore/idman.h>
18 #include <chcore-internal/fs_defs.h>
19 #include <chcore/container/hashtable.h>
20 #include <chcore/proc.h>
21
22 #include "proc_node.h"
23 #include "procmgr_dbg.h"
24 #include "srvmgr.h"
25 #ifdef CHCORE_OH_TEE
26 #include "oh_mem_ops.h"
27 #endif /* CHCORE_OH_TEE */
28
29 /* For synchronization */
30 static pthread_mutex_t proc_nodes_lock;
31
32 /* For allocating pid to proc_node */
33 static struct id_manager pid_mgr;
34 static const int PID_MAX = 1024 * 1024;
35
36 /* Map: client_badge -> proc_node */
37 /*
38 * We use client_badge as the index of procnode.
39 */
40 static struct htable badge2proc;
41 #ifdef CHCORE_OH_TEE
42 static struct htable pid2proc;
43 #endif /* CHCORE_OH_TEE */
44
45 /* Max number of pcid on x86_64 is different from that (ASID) on aarch64. */
46 static struct id_manager pcid_mgr;
47 #if defined(CHCORE_ARCH_X86_64)
48 static const int PCID_MAX = 1 << 12;
49 #elif defined(CHCORE_ARCH_AARCH64)
50 static const int PCID_MAX = 1 << 16;
51 #elif defined(CHCORE_ARCH_RISCV64)
52 static const int PCID_MAX = 1 << 16;
53 #elif defined(CHCORE_ARCH_SPARC)
54 static const int PCID_MAX = 1 << 16;
55 #else
56 #error "Unsupported architecture"
57 #endif
58
59 #define HASH_TABLE_SIZE 509
60 /*
61 * PCID in range [0,10) is reserved for boot page table, root process,
62 * fsm, fs, lwip, procmgr and future servers (pcid 0 is not used).
63 * Thus the user apps' pcid starts at 10. (10 is used by init process)
64 */
65 static const int MAX_RESERVED_PCID = 10;
66
67 /* Only for handle_init */
68 static struct proc_node *proc_init;
69
generate_server_badge(void)70 static inline badge_t generate_server_badge(void)
71 {
72 static badge_t cur_server_badge = MIN_FREE_SERVER_BADGE;
73 BUG_ON(++cur_server_badge >= MIN_FREE_DRIVER_BADGE);
74 return cur_server_badge;
75 }
76
generate_driver_badge(void)77 static inline badge_t generate_driver_badge(void)
78 {
79 static badge_t cur_driver_badge = MIN_FREE_DRIVER_BADGE;
80 BUG_ON(++cur_driver_badge >= MIN_FREE_APP_BADGE);
81 return cur_driver_badge;
82 }
83
generate_app_badge(void)84 static inline badge_t generate_app_badge(void)
85 {
86 static badge_t cur_app_badge = MIN_FREE_APP_BADGE;
87 return cur_app_badge++;
88 }
89
__new_proc_node(struct proc_node * parent,char * name)90 static struct proc_node *__new_proc_node(struct proc_node *parent, char *name)
91 {
92 struct proc_node *proc = malloc(sizeof(*proc));
93 assert(proc);
94
95 /* Alloc pid */
96 pthread_mutex_lock(&proc_nodes_lock);
97 proc->pid = alloc_id(&pid_mgr);
98 BUG_ON(proc->pid == -EINVAL);
99 pthread_mutex_unlock(&proc_nodes_lock);
100
101 proc->name = name;
102 proc->parent = parent;
103 proc->state = PROC_STATE_INIT;
104 pthread_mutex_init(&proc->lock, NULL);
105 if (proc->parent) {
106 /* Add this proc to parent's child list. */
107 pthread_mutex_lock(&parent->lock);
108 list_add(&proc->node, &proc->parent->children);
109 pthread_mutex_unlock(&parent->lock);
110 }
111 init_list_head(&proc->children);
112 init_hlist_node(&proc->hash_node);
113 #ifdef CHCORE_OH_TEE
114 init_hlist_node(&proc->pid_hash_node);
115 #endif /* CHCORE_OH_TEE */
116
117 return proc;
118 }
119
init_proc_node_mgr(void)120 void init_proc_node_mgr(void)
121 {
122 init_id_manager(&pid_mgr, PID_MAX, DEFAULT_INIT_ID);
123
124 pthread_mutex_init(&proc_nodes_lock, NULL);
125 pthread_mutex_init(&recycle_lock, NULL);
126 /* Reserve the pcid for root process and servers. */
127 init_id_manager(&pcid_mgr, PCID_MAX, MAX_RESERVED_PCID);
128
129 init_htable(&badge2proc, HASH_TABLE_SIZE);
130 #ifdef CHCORE_OH_TEE
131 init_htable(&pid2proc, HASH_TABLE_SIZE);
132 #endif /* CHCORE_OH_TEE */
133 }
134
135 /*
136 * The name here should be a newly allocated memory that can be directly stored
137 * (and sometime later freed) in the proc_node.
138 */
new_proc_node(struct proc_node * parent,char * name,int proc_type)139 struct proc_node *new_proc_node(struct proc_node *parent, char *name,
140 int proc_type)
141 {
142 struct proc_node *proc = __new_proc_node(parent, name);
143
144 pthread_mutex_lock(&proc_nodes_lock);
145
146 /* Alloc pcid */
147 if (strcmp(name, "procmgr") == 0 && proc_type == SYSTEM_SERVER) {
148 proc->pcid = PROCMGR_PCID;
149 proc->badge = PROCMGR_BADGE;
150 } else if (strcmp(name, "fsm") == 0 && proc_type == SYSTEM_SERVER) {
151 proc->pcid = FSM_PCID;
152 proc->badge = FSM_BADGE;
153 } else if (strcmp(name, "lwip") == 0 && proc_type == SYSTEM_SERVER) {
154 proc->pcid = LWIP_PCID;
155 proc->badge = LWIP_BADGE;
156 } else if (proc_type == SYSTEM_SERVER) {
157 proc->pcid = alloc_id(&pcid_mgr);
158 proc->badge = generate_server_badge();
159 } else if (proc_type == SYSTEM_DRIVER) {
160 proc->pcid = alloc_id(&pcid_mgr);
161 proc->badge = generate_driver_badge();
162 } else if (proc_type == COMMON_APP) {
163 proc->pcid = alloc_id(&pcid_mgr);
164 proc->badge = generate_app_badge();
165 } else {
166 warn("new proc failed, proc type error %d\n", proc_type);
167 return NULL;
168 }
169 BUG_ON(proc->pcid == -EINVAL);
170
171 /* Generate badge and add to htable */
172 htable_add(&badge2proc, proc->badge, &proc->hash_node);
173 #ifdef CHCORE_OH_TEE
174 htable_add(&pid2proc, proc->pid, &proc->pid_hash_node);
175 #endif /* CHCORE_OH_TEE */
176
177 pthread_mutex_init(&proc->wait_lock, NULL);
178 pthread_cond_init(&proc->wait_cv, NULL);
179
180 pthread_mutex_unlock(&proc_nodes_lock);
181 debug("alloc pcid = %d\n", proc->pcid);
182 return proc;
183 }
184
free_proc_node_resource(struct proc_node * proc)185 void free_proc_node_resource(struct proc_node *proc)
186 {
187 int pid;
188 int pcid;
189
190 pthread_mutex_lock(&proc_nodes_lock);
191
192 pid = proc->pid;
193 pcid = (int)proc->pcid;
194
195 /* Just delete the node in the hash table. Free proc later. */
196 htable_del(&proc->hash_node);
197 #ifdef CHCORE_OH_TEE
198 htable_del(&proc->pid_hash_node);
199 clean_sharemem(proc->badge);
200 #endif /* CHCORE_OH_TEE */
201
202 free_id(&pid_mgr, pid);
203 free_id(&pcid_mgr, pcid);
204 debug("free pcid = %d\n", pcid);
205
206 if (proc->name)
207 free(proc->name);
208 pthread_mutex_unlock(&proc_nodes_lock);
209 }
210
211 /* Free the resource allocated in new_proc_node in a reverse order */
del_proc_node(struct proc_node * proc)212 void del_proc_node(struct proc_node *proc)
213 {
214 struct proc_node *child;
215 struct proc_node *tmp;
216
217 BUG_ON(proc->state != PROC_STATE_EXIT);
218
219 /*
220 * Step 1. Set the child proc node as orphan, delete the child list of
221 * the proc node and free all exited child node.
222 */
223 for_each_in_list_safe (child, tmp, node, &proc->children) {
224 child->parent = NULL;
225 /*
226 * NOTE: If we need keep the relationship between the child of the
227 * proc_node, we need append the child node to a new process(such
228 * as init).
229 */
230 /* Recycle exited child proc node. */
231 if (child->state == PROC_STATE_EXIT) {
232 free_proc_node_resource(child);
233 free(child);
234 }
235 }
236
237 /*
238 * Step2. If the proc is orphan, free the proc node.
239 */
240 if (!proc->parent) {
241 free_proc_node_resource(proc);
242 free(proc);
243 }
244 }
245
get_proc_node(badge_t client_badge)246 struct proc_node *get_proc_node(badge_t client_badge)
247 {
248 struct proc_node *proc;
249 struct hlist_head *buckets;
250
251 pthread_mutex_lock(&proc_nodes_lock);
252 buckets = htable_get_bucket(&badge2proc, client_badge);
253
254 for_each_in_hlist (proc, hash_node, buckets) {
255 if (client_badge == proc->badge) {
256 goto out;
257 }
258 }
259 /* NOTE: It should be reconstroction. */
260 pthread_mutex_unlock(&proc_nodes_lock);
261 return NULL;
262 out:
263 debug("Find badge = 0x%x, get proc = %p\n", client_badge, proc);
264 pthread_mutex_unlock(&proc_nodes_lock);
265
266 return proc;
267 }
268
269 #ifdef CHCORE_OH_TEE
get_proc_node_by_pid(int pid)270 struct proc_node *get_proc_node_by_pid(int pid)
271 {
272 struct proc_node *proc;
273 struct hlist_head *buckets;
274
275 pthread_mutex_lock(&proc_nodes_lock);
276 buckets = htable_get_bucket(&pid2proc, pid);
277
278 for_each_in_hlist (proc, pid_hash_node, buckets) {
279 if (pid == proc->pid) {
280 goto out;
281 }
282 }
283 /* NOTE: It should be reconstroction. */
284 pthread_mutex_unlock(&proc_nodes_lock);
285 return NULL;
286 out:
287 debug("Find pid = %d, get proc = %p\n", pid, proc);
288 pthread_mutex_unlock(&proc_nodes_lock);
289
290 return proc;
291 }
292 #endif /* CHCORE_OH_TEE */
293
init_root_proc_node(void)294 void init_root_proc_node(void)
295 {
296 /* Init the init node. */
297 proc_init = new_proc_node(NULL, strdup("procmgr"), SYSTEM_SERVER);
298 htable_add(&badge2proc, proc_init->badge, &proc_init->hash_node);
299 #ifdef CHCORE_OH_TEE
300 htable_add(&pid2proc, proc_init->pid, &proc_init->pid_hash_node);
301 #endif /* CHCORE_OH_TEE */
302
303 __sync_synchronize();
304 }
305