1 /*
2 * Copyright (C) 2022 Huawei Technologies Co., Ltd.
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 "drv_thread.h"
13 #include <errno.h>
14 #include <securec.h>
15 #include <ipclib.h>
16 #include <tee_log.h>
17 #include <mem_page_ops.h>
18 #include <tee_drv_internal.h>
19 #include <ipclib_hal.h>
20 #include <semaphore.h>
21 #include "cs.h"
22
23 #define IPC_CHANNEL_NUM 2
24 static pthread_mutex_t g_drv_caller_info_mutex = PTHREAD_MUTEX_INITIALIZER;
25 static struct syscaller_info *g_syscaller_info = NULL;
26 static uint32_t g_thread_num = 1; /* one for main thread */
27 static sem_t g_thread_sem;
28
thread_syscaller_init(uint32_t thread_num)29 static int32_t thread_syscaller_init(uint32_t thread_num)
30 {
31 g_thread_num += thread_num;
32 uint32_t size = g_thread_num * sizeof(struct syscaller_info);
33
34 g_syscaller_info = malloc(size);
35 if (g_syscaller_info == NULL) {
36 tloge("cannot alloc for syscaller thread_num:%u\n", g_thread_num);
37 return -1;
38 }
39
40 if (memset_s(g_syscaller_info, size, 0, size) != 0) {
41 free(g_syscaller_info);
42 g_syscaller_info = NULL;
43 return -1;
44 }
45
46 uint32_t i;
47 for (i = 0; i < g_thread_num; i++)
48 g_syscaller_info[i].current_thread = INVALID_CALLER_PID;
49
50 return 0;
51 }
52
get_callerpid_and_job_handler_by_tid(tid_t tid,pid_t * caller_pid,uint64_t * job_handler)53 int32_t get_callerpid_and_job_handler_by_tid(tid_t tid, pid_t *caller_pid, uint64_t *job_handler)
54 {
55 if (caller_pid == NULL || job_handler == NULL) {
56 printf("invalid parameter\n");
57 return DRV_CALL_ERROR;
58 }
59
60 for (uint32_t i = 0; i < g_thread_num; i++) {
61 if (g_syscaller_info[i].current_thread == tid) {
62 *caller_pid = g_syscaller_info[i].caller_pid;
63 *job_handler = g_syscaller_info[i].job_handler;
64 return DRV_CALL_OK;
65 }
66 }
67
68 tloge("get caller pid and job_handler failed\n");
69
70 return DRV_CALL_ERROR;
71 }
72
get_callerpid_by_tid(tid_t tid,pid_t * caller_pid)73 int32_t get_callerpid_by_tid(tid_t tid, pid_t *caller_pid)
74 {
75 uint64_t job_handler;
76 int32_t ret = get_callerpid_and_job_handler_by_tid(tid, caller_pid, &job_handler);
77 return ret;
78 }
79
update_callerpid_by_tid(tid_t tid,pid_t caller_pid)80 void update_callerpid_by_tid(tid_t tid, pid_t caller_pid)
81 {
82 uint32_t i;
83 if (pthread_mutex_lock(&g_drv_caller_info_mutex) != 0) {
84 tloge("mutex lock failed\n");
85 return;
86 }
87
88 for (i = 0; i < g_thread_num; i++) {
89 if (g_syscaller_info[i].current_thread == tid) {
90 g_syscaller_info[i].caller_pid = caller_pid;
91 if (pthread_mutex_unlock(&g_drv_caller_info_mutex) != 0)
92 tloge("mutex unlock failed\n");
93 return;
94 }
95 }
96
97 for (i = 0; i < g_thread_num; i++) {
98 if (g_syscaller_info[i].current_thread == INVALID_CALLER_PID) {
99 g_syscaller_info[i].current_thread = tid;
100 g_syscaller_info[i].caller_pid = caller_pid;
101 if (pthread_mutex_unlock(&g_drv_caller_info_mutex) != 0)
102 tloge("mutex unlock failed\n");
103 return;
104 }
105 }
106
107 if (pthread_mutex_unlock(&g_drv_caller_info_mutex) != 0)
108 tloge("mutex unlock failed\n");
109 }
110
update_caller_info_by_tid(tid_t tid,pid_t caller_pid,uint64_t job_handler)111 void update_caller_info_by_tid(tid_t tid, pid_t caller_pid, uint64_t job_handler)
112 {
113 uint32_t i;
114 if (pthread_mutex_lock(&g_drv_caller_info_mutex) != 0) {
115 tloge("get mutex lock failed\n");
116 return;
117 }
118
119 for (i = 0; i < g_thread_num; i++) {
120 if (g_syscaller_info[i].current_thread == tid) {
121 g_syscaller_info[i].caller_pid = caller_pid;
122 g_syscaller_info[i].job_handler = job_handler;
123 if (pthread_mutex_unlock(&g_drv_caller_info_mutex) != 0)
124 tloge("mutex unlock failed\n");
125 return;
126 }
127 }
128
129 for (i = 0; i < g_thread_num; i++) {
130 if (g_syscaller_info[i].current_thread == INVALID_CALLER_PID) {
131 g_syscaller_info[i].current_thread = tid;
132 g_syscaller_info[i].caller_pid = caller_pid;
133 g_syscaller_info[i].job_handler = job_handler;
134 if (pthread_mutex_unlock(&g_drv_caller_info_mutex) != 0)
135 tloge("mutex unlock failed\n");
136 return;
137 }
138 }
139
140 if (pthread_mutex_unlock(&g_drv_caller_info_mutex) != 0)
141 tloge("mutex unlock failed\n");
142 }
143
tee_driver_thread(void * args)144 static void *tee_driver_thread(void *args)
145 {
146 struct thread_init_info *pthread_info = (struct thread_init_info *)args;
147 struct reg_items_st reg_items = { true, false, false };
148
149 cref_t channel = pthread_info->channel;
150 dispatch_fn_t dispatch_fns_thread[] = {
151 [0] = driver_dispatch,
152 };
153
154 int32_t ret = ipc_create_channel(NULL, IPC_CHANNEL_NUM, NULL, reg_items);
155 if (ret != 0) {
156 tloge("fail to create channel ret: 0x%x\n", ret);
157 return NULL;
158 }
159
160 sem_post(pthread_info->thread_sem);
161
162 cs_server_loop(channel, dispatch_fns_thread, ARRAY_SIZE(dispatch_fns_thread), NULL, pthread_info);
163
164 return NULL;
165 }
166
init_pthread_info(struct thread_init_info * pthread_info,cref_t channel,size_t stack_size,uint32_t thread_limit)167 static int32_t init_pthread_info(struct thread_init_info *pthread_info, cref_t channel,
168 size_t stack_size, uint32_t thread_limit)
169 {
170 pthread_info->channel = channel;
171 pthread_info->func = tee_driver_thread;
172 pthread_info->max_thread = thread_limit;
173 pthread_info->thread_sem = &g_thread_sem;
174 pthread_info->stack_size = stack_size;
175 return DRV_CALL_OK;
176 }
177
creat_server_thread(cref_t channel,size_t stack_size,uint32_t thread_limit)178 static void creat_server_thread(cref_t channel, size_t stack_size, uint32_t thread_limit)
179 {
180 pthread_attr_t attr;
181 struct thread_init_info *info = NULL;
182 int32_t ret;
183 pthread_t thread_id;
184
185 /* create thread, thread0 is common thread. */
186 info = malloc(sizeof(*info));
187 if (info == NULL)
188 tee_abort("malloc thread info mem error\n");
189
190 ret = pthread_attr_init(&attr);
191 if (ret != 0) {
192 free(info);
193 tee_abort("init pthread attr failed\n");
194 }
195
196 if (stack_size != 0) {
197 ret = pthread_attr_setstacksize(&attr, stack_size);
198 if (ret != 0) {
199 free(info);
200 (void)pthread_attr_destroy(&attr);
201 tee_abort("set attr stack size fail\n");
202 }
203 }
204
205 ret = init_pthread_info(info, channel, stack_size, thread_limit);
206 if (ret != DRV_CALL_OK) {
207 free(info);
208 tee_abort("init thread info error\n");
209 }
210
211 ret = pthread_create(&thread_id, &attr, tee_driver_thread, info);
212 if (ret != 0) {
213 free(info);
214 tee_abort("create pthread failed\n");
215 }
216 (void)pthread_attr_destroy(&attr);
217 }
218
thread_init_param_check(uint32_t thread_limit,uint32_t * stack_size)219 static int32_t thread_init_param_check(uint32_t thread_limit, uint32_t *stack_size)
220 {
221 /* thread_limit is 0 means only have main thread */
222 if (thread_limit > DRV_THREAD_MAX) {
223 tloge("thread limit:%u invalid\n", thread_limit);
224 return -1;
225 }
226
227 uint32_t stack = *stack_size;
228 uint32_t temp_stack = PAGE_ALIGN_UP(stack);
229 if (temp_stack < stack) {
230 tloge("invalid stack size:0x%x\n", stack);
231 return -1;
232 }
233
234 *stack_size = temp_stack;
235
236 return 0;
237 }
238
drv_thread_init(const char * thread_name,uint32_t stack_size,uint32_t thread_limit)239 int32_t drv_thread_init(const char *thread_name, uint32_t stack_size, uint32_t thread_limit)
240 {
241 cref_t channel;
242
243 if ((thread_name == NULL) || (strnlen(thread_name, DRV_NAME_MAX_LEN) == 0) ||
244 (strnlen(thread_name, DRV_NAME_MAX_LEN) >= DRV_NAME_MAX_LEN)) {
245 tloge("thread init invalid name\n");
246 return -1;
247 }
248
249 int32_t ret = ipc_create_channel_native(thread_name, &channel);
250 if (ret != 0)
251 tee_abort("%s: failed to create channel :%d\n", thread_name, ret);
252
253 return multi_drv_framwork_init(thread_limit, stack_size, channel);
254 }
255
multi_drv_framwork_init(uint32_t thread_limit,uint32_t stack_size,cref_t channel)256 int32_t multi_drv_framwork_init(uint32_t thread_limit, uint32_t stack_size, cref_t channel)
257 {
258 uint32_t stack = stack_size;
259 if (thread_init_param_check(thread_limit, &stack) != 0)
260 return -1;
261
262 if (g_syscaller_info != NULL)
263 return 0;
264
265 tlogd("thread_limit:%u stack_size:0x%x\n", thread_limit, stack_size);
266
267 int32_t ret = thread_syscaller_init(thread_limit);
268 if (ret != 0)
269 return -1;
270
271 if (thread_limit > 0) {
272 (void)sem_init(&g_thread_sem, 0, 0);
273 creat_server_thread(channel, stack, thread_limit);
274 if (sem_wait(&g_thread_sem) != 0)
275 tee_abort("sem wait failed\n");
276 }
277
278 return 0;
279 }
280