• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 #define _GNU_SOURCE
14 
15 #include "ta_mt.h"
16 #include <stdlib.h>
17 #include <string.h>
18 #include <inttypes.h>
19 #include <dlfcn.h>
20 #include <pthread.h>
21 #include <ipclib.h>
22 #include <unistd.h>
23 #include <ta_framework.h>
24 #include <tee_log.h>
25 #include "load_init.h"
26 #include <ipclib_hal.h>
27 #include <spawn_ext.h>
28 #include <priorities.h>
29 
30 #ifndef THREAD_STACK_SIZE
31 #define THREAD_STACK_SIZE (4096 * 4 * 5)
32 #endif
33 
34 #define CREATE_IPC_CHANNEL_NUM 2
35 
36 struct thread_info {
37     struct {
38         ta_entry_type ta_entry;
39         uint32_t inited;
40         int32_t priority;
41         const char *name;
42         const struct ta_routine_info *append_args;
43     } args;
44     pthread_t thread;  /* pthread handler */
45     cref_t thread_ref; /* thread cref, used to terminated it. */
46     uint32_t tid;
47     cref_t t_channel[CH_CNT_MAX];
48     cref_t t_msghdl;
49 };
50 static struct thread_info g_tinfos[TA_SESSION_MAX];
51 
52 struct create_thread_info {
53     size_t stack_size;
54     int32_t priority;
55 };
56 
find_thread_by_tid(uint32_t tid)57 static struct thread_info *find_thread_by_tid(uint32_t tid)
58 {
59     for (int32_t i = 0; i < TA_SESSION_MAX; i++) {
60         if (g_tinfos[i].thread != 0 && g_tinfos[i].tid == tid)
61             return &g_tinfos[i];
62     }
63 
64     return NULL;
65 }
66 
get_free_thread_info_slot(void)67 static struct thread_info *get_free_thread_info_slot(void)
68 {
69     for (int32_t i = 0; i < TA_SESSION_MAX; i++) {
70         if (g_tinfos[i].thread == 0)
71             return &g_tinfos[i];
72     }
73 
74     return NULL;
75 }
76 
77 /* pti: no concurrent write access, write access is atomic. */
release_thread_info(struct thread_info * pti)78 static void release_thread_info(struct thread_info *pti)
79 {
80     pti->thread = 0;
81 }
82 
83 #define INVALID_SENDER 0xffffffffU
84 /*
85  * This is a wrapper of ipc_msg_rcv_a.
86  * It use to process the possible result of ipc_msg_rcv_a,
87  * So no need to process this function's return value.
88  * if ipc_msg_rcv_a return NOT OK, only log it and return.
89  * if ipc_msg_rcv_a return OK, but the MsgSender is NOT GLOBAL_HANDLE,
90  * then try ipc_msg_rcv_a again, until get the Msg from globaltask.
91  */
msg_rcv_elf(uint32_t timeout,uint32_t * msg_id,void * msgp,uint16_t size)92 static void msg_rcv_elf(uint32_t timeout, uint32_t *msg_id, void *msgp, uint16_t size)
93 {
94     uint32_t ret;
95     uint32_t sender = INVALID_SENDER;
96 
97     while (sender != GLOBAL_HANDLE) {
98         ret = ipc_msg_rcv_a(timeout, msg_id, msgp, size, &sender);
99         if (ret != SRE_OK) {
100             tloge("Msg rcv failed, ret = %u\n", ret);
101             return;
102         }
103 
104         if (sender != GLOBAL_HANDLE)
105             tlogw("Msg recv from sender = %u\n", sender);
106     }
107 }
108 
remove_all_ipc_channel(uint32_t tid,const struct thread_info * pti)109 static void remove_all_ipc_channel(uint32_t tid, const struct thread_info *pti)
110 {
111     int32_t i;
112     int32_t rc;
113     pid_t pid;
114 
115     for (i = 0; i < CH_CNT_MAX; i++) {
116         pid = getpid();
117         if (pid == -1) {
118             tloge("get pid failed\n");
119             continue;
120         }
121 
122         rc = ipc_remove_channel((taskid_t)pid_to_taskid(tid, pid), NULL, i, pti->t_channel[i]);
123         if (rc != 0)
124             tloge("remove ipc channel #%d failed: rc=%d\n", i, rc);
125     }
126 }
127 
ta_recycle_thread(uint32_t tid)128 static TEE_Result ta_recycle_thread(uint32_t tid)
129 {
130     struct thread_info *pti = NULL;
131     int32_t rc;
132 
133     pti = find_thread_by_tid(tid);
134     if ((pti == NULL) || (pti->thread == NULL)) {
135         tloge("Cannot find dest thread to recycle, tid = 0x%x\n", tid);
136         return TEE_ERROR_GENERIC;
137     }
138     tlogi("Suspend thread, tid=0x%x\n", tid);
139 
140     /* cleanup thread resources, ignore any failed cleanup */
141     rc = thread_terminate(pti->thread);
142     if (rc != 0)
143         tloge("terminate thread failed tid=0x%" PRIx32 " rc=%d\n", tid, rc);
144 
145     rc = pthread_join(pti->thread, NULL);
146     if (rc != 0)
147         tloge("pthread join failed: rc=%d\n", rc);
148 
149     remove_all_ipc_channel(tid, pti);
150     ipc_msg_delete_hdl(pti->t_msghdl);
151     /* clear thread info struct */
152     release_thread_info(pti);
153 
154     return TEE_SUCCESS;
155 }
156 
is_agent(const char * task_name)157 static bool is_agent(const char *task_name)
158 {
159     return strncmp(task_name, SSA_SERVICE_NAME, sizeof(SSA_SERVICE_NAME)) == 0;
160 }
161 
create_ipc_channel(const char * task_name,cref_t * ch[])162 static int32_t create_ipc_channel(const char *task_name, cref_t *ch[])
163 {
164     bool reg_tamgr = is_agent(task_name);
165     struct reg_items_st reg_items;
166     reg_items.reg_pid = true;
167     reg_items.reg_name = false;
168     reg_items.reg_tamgr = reg_tamgr;
169     if (ipc_create_channel(task_name, CREATE_IPC_CHANNEL_NUM, ch, reg_items) != 0) {
170         tloge("Cannot create thread channel\n");
171         return -1;
172     }
173 
174     return 0;
175 }
176 
call_task_entry(const struct thread_info * pti)177 static void call_task_entry(const struct thread_info *pti)
178 {
179     int32_t rc = set_priority(pti->args.priority);
180     if (rc < 0)
181         tloge("set priority failed: %x\n", rc);
182 
183     /* call real TA entry */
184     if (pti->args.append_args != NULL)
185         (*pti->args.ta_entry.ta_entry)(pti->args.inited, pti->args.append_args);
186     else
187         (*pti->args.ta_entry.ta_entry_orig)(pti->args.inited);
188 
189     /* should never get here, crash myself */
190     tee_abort("tee task entry exit!\n");
191 }
192 
tee_task_entry_thread(void * data)193 static void *tee_task_entry_thread(void *data)
194 {
195     struct thread_info *pti = data;
196     int32_t tid;
197     cref_t msghdl;
198     cref_t *ch[CH_CNT_MAX];
199     int32_t i;
200     const char *name = pti->args.name;
201 
202     /* get self tid */
203     tid = gettid();
204     if (tid < 0) {
205         tloge("thread self failed: ret=%d\n", tid);
206         goto err_get_tid;
207     }
208     pti->tid = (uint32_t)tid;
209 
210     /* prepare message handle */
211     msghdl = ipc_msg_create_hdl();
212     if (!check_ref_valid(msghdl)) {
213         tloge("Cannot create msg_hdl\n");
214         goto err_get_tid;
215     }
216     pti->t_msghdl = msghdl;
217 
218     /* store msghdl in self tls */
219     if(ipc_save_my_msghdl(msghdl) != 0) {
220         tloge("save hdl error");
221         goto err_save_hdl;
222     }
223     /* create IPC channel, and save to tls */
224     for (i = 0; i < CH_CNT_MAX; i++)
225         ch[i] = &pti->t_channel[i];
226 
227     if (create_ipc_channel(name, ch) != 0)
228         goto err_save_hdl;
229 
230     /* send tid reply to gtask, just pass msg id as 0 */
231     if (ipc_msg_qsend(pti->tid, GLOBAL_HANDLE, SECOND_CHANNEL) != SRE_OK) {
232         tloge("Msg send failed\n");
233         goto err_reply_tid;
234     }
235 
236     call_task_entry(pti);
237 
238 err_reply_tid:
239     remove_all_ipc_channel(tid, pti);
240 
241 err_save_hdl:
242     ipc_msg_delete_hdl(pti->t_msghdl);
243 
244 err_get_tid:
245     /* reply error for TaskCreate */
246     if (ipc_msg_qsend(CREATE_THREAD_FAIL, GLOBAL_HANDLE, SECOND_CHANNEL) != SRE_OK)
247         tloge("Msg send 1 failed\n");
248     release_thread_info(pti);
249     return NULL;
250 }
251 
ta_create_thread(ta_entry_type entry,uint32_t inited,const struct create_thread_info * info,const char * name,const struct ta_routine_info * append_args)252 static TEE_Result ta_create_thread(ta_entry_type entry, uint32_t inited, const struct create_thread_info *info,
253     const char *name, const struct ta_routine_info *append_args)
254 {
255     int32_t rc;
256     pthread_attr_t attr;
257     struct thread_info *pti = NULL;
258 
259     pti = get_free_thread_info_slot();
260     if (pti == NULL) {
261         tloge("out of thread\n");
262         return TEE_ERROR_SESSION_MAXIMUM;
263     }
264 
265     if (pthread_attr_init(&attr) != 0) {
266         tloge("pthread attr init failed\n");
267         goto err_out;
268     }
269 
270     /* set stack size for new thread */
271     if (pthread_attr_setstacksize(&attr, info->stack_size) != 0) {
272         tloge("pthread attr set stack size failed, size=0x%zx\n", info->stack_size);
273         goto err_out;
274     }
275 
276     /* set thread args */
277     pti->args.ta_entry = entry;
278     pti->args.inited = inited;
279     pti->args.priority = info->priority;
280     pti->args.name = name;
281     pti->args.append_args = append_args;
282 
283     /* create working thread, and get its thread ref */
284     rc = pthread_create(&pti->thread, &attr, tee_task_entry_thread, pti);
285     if (rc) {
286         tloge("pthread create failed: %d\n", rc);
287         goto err_out;
288     }
289 
290     return TEE_SUCCESS;
291 
292 err_out:
293     release_thread_info(pti);
294     return TEE_ERROR_GENERIC;
295 }
296 
close_ta2ta_session(uint32_t tid)297 static void close_ta2ta_session(uint32_t tid)
298 {
299     void (*delete_ta2ta_session)(uint32_t tid) = NULL;
300     void *libtee_handle = NULL;
301 
302     libtee_handle = get_libtee_handle();
303     if (libtee_handle == NULL) {
304         tloge("libtee has not open\n");
305         return;
306     }
307 
308     delete_ta2ta_session = dlsym(libtee_handle, "delete_all_ta2ta_session");
309     if (delete_ta2ta_session == NULL) {
310         tloge("cannot get delete ta2ta session symbol\n");
311         return;
312     }
313     delete_ta2ta_session(tid);
314 }
315 
clear_session(uint32_t session_id)316 static void clear_session(uint32_t session_id)
317 {
318     void (*clear_session_ops)(uint32_t session_id) = NULL;
319     void *libtee_handle = NULL;
320 
321     libtee_handle = get_libtee_handle();
322     if (libtee_handle == NULL) {
323         tloge("libtee has not open\n");
324         return;
325     }
326 
327     clear_session_ops = dlsym(libtee_handle, "clear_session_exception");
328     if (clear_session_ops == NULL) {
329         tloge("cannot get clear session symbol\n");
330         return;
331     }
332     clear_session_ops(session_id);
333 }
334 
close_session_exception(uint32_t session_id)335 static void close_session_exception(uint32_t session_id)
336 {
337     clear_session(session_id);
338 }
339 
handle_thread_create(ta_entry_type entry,const struct create_thread_info * info,const char * name,const struct ta_routine_info * append_args)340 static void handle_thread_create(ta_entry_type entry, const struct create_thread_info *info, const char *name,
341     const struct ta_routine_info *append_args)
342 {
343     TEE_Result ret;
344 
345     ret = ta_create_thread(entry, NON_INIT_BUILD, info, name, append_args);
346     if (ret != TEE_SUCCESS) {
347         tloge("ta create thread error!!! %x\n", ret);
348         if (ipc_msg_qsend(CREATE_THREAD_FAIL, GLOBAL_HANDLE, SECOND_CHANNEL) != SRE_OK)
349             tloge("Msg send failed\n");
350     }
351 }
352 
handle_thread_remove(uint32_t tid,uint32_t session_id)353 static void handle_thread_remove(uint32_t tid, uint32_t session_id)
354 {
355     TEE_Result ret;
356     ret = ta_recycle_thread(tid);
357     if (ret != TEE_SUCCESS)
358         tloge("ta recycle thread stack error!!! %x\n", ret);
359     /* close all ta2ta session opened by this thread */
360     close_ta2ta_session(tid);
361     close_session_exception(session_id);
362     /* send reply to gtask, just pass msg id as 0, ret as TEE_SUCCESS for success */
363     if (ipc_msg_qsend((uint32_t)ret, GLOBAL_HANDLE, SECOND_CHANNEL) != SRE_OK)
364         tloge("Msg send failed\n");
365 }
366 
tee_task_entry_handle(ta_entry_type ta_entry,int32_t priority,const char * name,const struct ta_routine_info * append_args)367 static void tee_task_entry_handle(ta_entry_type ta_entry, int32_t priority, const char *name,
368     const struct ta_routine_info *append_args)
369 {
370     uint32_t cmd;
371     uint32_t tid;
372     uint32_t session_id;
373     struct create_thread_info info;
374     while (1) {
375         struct global_to_service_thread_msg entry_msg = { { { 0 } } };
376         cmd = 0;
377         tlogd("++ Service TA task enter suspend\n");
378         msg_rcv_elf(OS_WAIT_FOREVER, (uint32_t *)(&cmd), &entry_msg, sizeof(entry_msg));
379         tlogd("-- Service TA rsv cmd : 0x%x\n", cmd);
380         switch (cmd) {
381         case CALL_TA_CREATE_THREAD:
382             tlogd("++ CALL TA CREATE THREAD\n");
383             info.stack_size = entry_msg.create_msg.stack_size;
384             info.priority = priority;
385             handle_thread_create(ta_entry, &info, name, append_args);
386             break;
387         case CALL_TA_REMOVE_THREAD:
388             tlogd("++ CALL TA REMOVE THREAD\n");
389             tid = entry_msg.remove_msg.tid;
390             session_id = entry_msg.remove_msg.session_id;
391             handle_thread_remove(tid, session_id);
392             break;
393         case CALL_TA_STHREAD_EXIT: /* no need to break, cos this proc exit directly */
394             tlogd("++ CALL TA STHREAD EXIT\n");
395             exit(0);
396         default:
397             tloge("invalid cmdid 0x%x\n", cmd);
398             break;
399         }
400     }
401 }
402 
403 /* return from this function will cause taldr crash itself */
tee_task_entry_mt(ta_entry_type ta_entry,int32_t priority,const char * name,const struct ta_routine_info * append_args)404 void tee_task_entry_mt(ta_entry_type ta_entry, int32_t priority, const char *name,
405     const struct ta_routine_info *append_args)
406 {
407     TEE_Result ret;
408     size_t stack_size;
409     struct create_thread_info info;
410 
411     /* no need check ta_entry_orig since ta_entry_type is a union */
412     if (ta_entry.ta_entry == NULL || name == NULL) {
413         tloge("bad TA entry\n");
414         return;
415     }
416 
417     stack_size = getstacksize();
418     if (stack_size == 0) {
419         tloge("get stack size failed, use default stack size 0x%x\n", THREAD_STACK_SIZE);
420         stack_size = THREAD_STACK_SIZE;
421     }
422 
423     info.stack_size = stack_size;
424     info.priority = priority;
425     /* Create a working thread at startup */
426     ret = ta_create_thread(ta_entry, INIT_BUILD, &info, name, append_args);
427     if (ret != TEE_SUCCESS) {
428         tloge("ta create thread error!!! %x\n", ret);
429         /* notify gtask that thread creating fails */
430         if (ipc_msg_qsend(CREATE_THREAD_FAIL, GLOBAL_HANDLE, SECOND_CHANNEL) != SRE_OK)
431             tloge("Msg send failed\n");
432         return;
433     }
434 
435     tee_task_entry_handle(ta_entry, priority, name, append_args);
436 }
437