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 "ta_framework.h"
13 #include "tee_log.h"
14 #include "tee_init.h"
15 #include "tee_ext_api.h"
16 #include "tee_ss_agent_api.h"
17 #include "sfs_internal.h"
18 #include "agent.h"
19 #include "securec.h"
20 #include "tee_internal_task_pub.h"
21 #include <ipclib_hal.h>
22
ssa_msgqueue_add(uint32_t cmd,const union ssa_agent_msg * msg,uint32_t sndr)23 static void ssa_msgqueue_add(uint32_t cmd, const union ssa_agent_msg *msg, uint32_t sndr)
24 {
25 errno_t rc;
26 ssa_cmd_t *cmd_oper = NULL;
27 struct ssa_agent_rsp rsp = {0};
28
29 uint32_t in = g_ssa_msg_queue.in;
30 tlogd("put msg %x to SSqueue[%u]\n", cmd, in);
31
32 if (in >= SS_AGENT_MSG_QUEUE_SIZE) {
33 tloge("invalid ssa msg queue in : [%u]\n", in);
34 goto send_msg_to_ta;
35 }
36
37 if (g_ssa_msg_queue.msg[in].msg_id == 0xFFFFFFFF) {
38 g_ssa_msg_queue.msg[in].msg_id = cmd;
39 g_ssa_msg_queue.msg[in].sender = sndr;
40 rc = memmove_s(&g_ssa_msg_queue.msg[in].msg, sizeof(g_ssa_msg_queue.msg[in].msg), msg,
41 sizeof(union ssa_agent_msg));
42 if (rc != EOK) {
43 g_ssa_msg_queue.msg[in].msg_id = 0xFFFFFFFF;
44
45 tloge("memmove ssa msg queue error %x\n", rc);
46 } else {
47 if (++in >= SS_AGENT_MSG_QUEUE_SIZE)
48 in = 0;
49
50 g_ssa_msg_queue.in = in;
51 }
52 } else {
53 tloge("SSqueue overflow\n");
54 for (uint32_t i = 0; i < SS_AGENT_MSG_QUEUE_SIZE; i++)
55 tloge("ssa queue:%u, cmd:0x%x, taskid:0x%x", i,
56 g_ssa_msg_queue.msg[i].msg_id, g_ssa_msg_queue.msg[i].sender);
57
58 goto send_msg_to_ta;
59 }
60
61 return;
62
63 send_msg_to_ta:
64 /* when set caller info failed, a message should be sent to TA
65 * to prevent TA from being suspended */
66 cmd_oper = ssa_find_cmd(cmd);
67 if (cmd_oper != NULL && cmd_oper->need_ack == 1) {
68 rsp.ret = TEE_ERROR_MSG_QUEUE_OVERFLOW;
69 TEE_Result ret_ack = (uint32_t)ipc_msg_snd(cmd, sndr, (void *)&rsp, sizeof(rsp));
70 if (ret_ack != SRE_OK)
71 tloge("msg snd error %x\n", ret_ack);
72 }
73 }
ssa_not_file_operate(uint32_t cmd,uint8_t * msg,uint32_t sndr)74 static TEE_Result ssa_not_file_operate(uint32_t cmd, uint8_t *msg, uint32_t sndr)
75 {
76 uint32_t need_ack;
77 uint32_t res_code;
78 ssa_cmd_t *cmd_oper = NULL;
79 struct ssa_agent_rsp rsp = { 0 };
80
81 tlogd("ssa_not_file_operate, cmd=%x", cmd);
82
83 cmd_oper = ssa_find_cmd(cmd);
84 if (cmd_oper == NULL) {
85 tloge("ssa_find_cmd failed : %x , from %x\n", cmd, sndr);
86 return TEE_ERROR_GENERIC;
87 }
88
89 if (cmd_oper->is_file_oper != NOT_FILE_OPERATION) {
90 tlogd("cmd is file operate: %x , from %x\n", cmd, sndr);
91 return TEE_ERROR_GENERIC;
92 }
93
94 rsp.ret = TEE_ERROR_GENERIC;
95 need_ack = cmd_oper->need_ack;
96 if (cmd_oper->fn != NULL) {
97 cmd_oper->fn((union ssa_agent_msg *)msg, sndr, &rsp);
98 } else {
99 tlogw("no process func for cmd %x, from %x", cmd, sndr);
100 }
101
102 if (need_ack) {
103 tlogd("send msg to %x\n", sndr);
104 res_code = (uint32_t)ipc_msg_snd(cmd, sndr, (void *)&rsp, sizeof(struct ssa_agent_rsp));
105 if (res_code != SRE_OK)
106 tlogw("msg snd error %x\n", res_code);
107 }
108
109 return TEE_SUCCESS;
110 }
ssa_deal_msg(uint32_t cmd,uint8_t * ret_msg,size_t msg_len,uint32_t sdr)111 static void ssa_deal_msg(uint32_t cmd, uint8_t *ret_msg, size_t msg_len, uint32_t sdr)
112 {
113 union ssa_agent_msg tmp_msg;
114 errno_t rc;
115
116 (void)memset_s(&tmp_msg, sizeof(tmp_msg), 0, sizeof(tmp_msg));
117 if (cmd == TEE_TASK_OPEN_TA_SESSION) {
118 rc = memcpy_s(&tmp_msg, sizeof(tmp_msg), ret_msg, msg_len);
119 if (rc != EOK) {
120 tloge("memcpy_s ssa msg failed, ret 0x%x\n", rc);
121 return;
122 }
123
124 tlogd("register task: %x-%x\n", tmp_msg.reg.taskid, tmp_msg.reg.uuid.timeLow);
125 ssa_register_uuid(&tmp_msg, sdr, NULL);
126
127 return;
128 } else if (cmd == TEE_TASK_CLOSE_TA_SESSION) {
129 rc = memcpy_s(&tmp_msg, sizeof(tmp_msg), ret_msg, msg_len);
130 if (rc != EOK) {
131 tloge("memcpy_s ssa msg failed, ret 0x%x\n", rc);
132 return;
133 }
134 if (pre_unregister_uuid(&tmp_msg, sdr) == 0) {
135 return; /* not mark as dead, has been remove the client directly. */
136 } else {
137 /* mark as dead, so need add msg to the queue */
138 }
139 } else {
140 if (ssa_not_file_operate(cmd, ret_msg, sdr) == TEE_SUCCESS)
141 return;
142 }
143
144 if (!is_client_register(sdr)) {
145 tloge("client is not registered, taskid:0x%x", sdr);
146 return;
147 }
148
149 ssa_msgqueue_add(cmd, (const union ssa_agent_msg *)ret_msg, sdr);
150 }
151
ssa_receive_msg(uint32_t uw_timeout,uint32_t * puw_msg_id,void * msgp,uint16_t size,uint32_t * puw_sender_pid)152 static uint32_t ssa_receive_msg(uint32_t uw_timeout, uint32_t *puw_msg_id, void *msgp,
153 uint16_t size, uint32_t *puw_sender_pid)
154 {
155 return (uint32_t)ipc_msg_rcv_a(uw_timeout, puw_msg_id, msgp, size, puw_sender_pid);
156 }
157
158 /* globaltask and TA's msgs will go here when SSA wait REE agent.
159 * 1. globaltask's msg which can goes here are either null msg, or send with struct union ssa_agent_msg.
160 * 2. TA's msgs are all use union ssa_agent_msg.
161 * 3. globaltask's msgs which use struct global_to_ta_msg are processed in ssa_obtain_agent_work_lock
162 * and ssa_agent_work_unlock, that means 'struct global_to_ta_msg' will never be used in this function.
163 */
ssa_wait_msg(uint32_t want_cmd,uint8_t * msg,uint32_t size,uint32_t want_sdr)164 static void ssa_wait_msg(uint32_t want_cmd, uint8_t *msg, uint32_t size, uint32_t want_sdr)
165 {
166 uint32_t cmd;
167 uint32_t sdr;
168 uint32_t ret;
169 uint32_t cp_size;
170 uint8_t ret_msg[sizeof(union ssa_agent_msg)];
171 errno_t rc;
172
173 while (1) {
174 cmd = 0;
175 sdr = 0;
176 rc = memset_s((void *)ret_msg, sizeof(union ssa_agent_msg), 0, sizeof(union ssa_agent_msg));
177 if (rc != EOK)
178 tloge("memset ret_msg failed %x\n", rc);
179
180 ret = ssa_receive_msg(OS_WAIT_FOREVER, (UINT32 *)(&cmd), (void *)ret_msg, sizeof(union ssa_agent_msg), &sdr);
181 if (ret != SRE_OK) {
182 tloge("ssa msg rcv error %x\n", ret);
183 continue;
184 }
185
186 tlogd("got msg %x from %x\n", cmd, sdr);
187
188 if (want_cmd == cmd && want_sdr == sdr) {
189 if (msg == NULL)
190 break;
191
192 cp_size = (size < sizeof(union ssa_agent_msg)) ? size : sizeof(union ssa_agent_msg);
193 rc = memmove_s(msg, size, ret_msg, cp_size);
194 if (rc != EOK)
195 tloge("memmove ssa msg, size %u error, ret %x\n", cp_size, rc);
196
197 break;
198 }
199
200 ssa_deal_msg(cmd, ret_msg, sizeof(union ssa_agent_msg), sdr);
201 }
202
203 return;
204 }
205
ssa_send_agent_cmd(uint32_t id,uint32_t cmd,uint32_t * cmd_buff)206 void ssa_send_agent_cmd(uint32_t id, uint32_t cmd, uint32_t *cmd_buff)
207 {
208 struct ta_to_global_msg send_msg;
209 errno_t rc;
210 uint32_t ret;
211
212 if (cmd_buff != NULL)
213 *cmd_buff = cmd;
214
215 rc = memset_s((void *)&send_msg, sizeof(send_msg), 0, sizeof(send_msg));
216 if (rc != EOK) {
217 tloge("memset send_msg failed %x\n", rc);
218 return;
219 }
220
221 send_msg.ret = TEE_PENDING2;
222 send_msg.agent_id = id;
223 send_msg.session_context = (void *)NULL;
224
225 __asm__ volatile("isb");
226 __asm__ volatile("dsb sy");
227
228 ret = ipc_msg_snd(TEE_TASK_AGENT_SMC_CMD, get_global_handle(), &send_msg, sizeof(send_msg));
229 if (ret != SRE_OK) {
230 tloge("msg snd error %x\n", ret);
231 return;
232 }
233
234 tlogd("ready to wait for rsp from nwd\n");
235
236 /* no need to verify return value here */
237 ssa_wait_msg(TEE_TASK_AGENT_SMC_ACK, NULL, 0, get_global_handle());
238 }
239
ssa_agent_lock_handler(uint32_t id,uint32_t lock_type)240 static void ssa_agent_lock_handler(uint32_t id, uint32_t lock_type)
241 {
242 struct ta_to_global_msg send_msg;
243 struct global_to_ta_msg ret_msg;
244 errno_t rc;
245 uint32_t i, ret;
246 uint8_t *ret_data = NULL;
247
248 rc = memset_s((void *)&send_msg, sizeof(send_msg), 0, sizeof(send_msg));
249 if (rc != EOK) {
250 tloge("memset failed %x\n", rc);
251 return;
252 }
253
254 send_msg.ret = TEE_PENDING2;
255 send_msg.agent_id = id;
256 send_msg.session_context = NULL;
257 /* Ask global task to lock the agent for us till the next invoke */
258 ret = (uint32_t)ipc_msg_snd(lock_type, get_global_handle(), &send_msg, sizeof(send_msg));
259 if (ret != SRE_OK) {
260 tloge("msg snd error %x\n", ret);
261 return;
262 }
263 /* Some form of error .... */
264 tlogd("ready to wait for locking agent\n");
265
266 do {
267 rc = memset_s((void *)&ret_msg, sizeof(ret_msg), 0, sizeof(ret_msg));
268 if (rc != EOK)
269 tlogw("memset fail");
270
271 ssa_wait_msg(TA_LOCK_ACK, (uint8_t *)&ret_msg, sizeof(ret_msg), get_global_handle());
272 /* Couldn't get lock... */
273 if (ret_msg.cmd_id != TEE_AGENT_LOCK) {
274 tloge("ssa get agent lock exception:msg %x, cmd 0x%x, sender 0x%x\n", TA_LOCK_ACK, ret_msg.cmd_id,
275 get_global_handle());
276
277 ret_data = (uint8_t *)(&ret_msg);
278 for (i = 0; i < sizeof(ret_msg); i++)
279 tloge("msg get from gtask is ret_data[%u] = 0x%x\n", i, ret_data[i]);
280
281 continue; /* rcv the ta_lock agent ack msg */
282 }
283
284 break;
285 } while (1);
286
287 return;
288 }
289
ssa_obtain_agent_work_lock(uint32_t id)290 void ssa_obtain_agent_work_lock(uint32_t id)
291 {
292 ssa_agent_lock_handler(id, TA_LOCK_AGENT);
293 }
294
295 /* In many cases we know when the agent can be unlocked so make sure to allow other tasks
296 * to use the agent ASAP */
ssa_agent_work_unlock(uint32_t id)297 void ssa_agent_work_unlock(uint32_t id)
298 {
299 ssa_agent_lock_handler(id, TA_UNLOCK_AGENT);
300 }
301
ssa_get_msg(uint32_t * cmd,uint8_t * msg,uint32_t size,uint32_t * sender)302 TEE_Result ssa_get_msg(uint32_t *cmd, uint8_t *msg, uint32_t size, uint32_t *sender)
303 {
304 uint32_t cp_size;
305 uint8_t buf[sizeof(union ssa_agent_msg)];
306 errno_t rc;
307 uint32_t out = g_ssa_msg_queue.out;
308
309 tlogd("start to get msg %u %u\n", g_ssa_msg_queue.in, g_ssa_msg_queue.out);
310
311 if (sender == NULL || cmd == NULL || msg == NULL)
312 return TEE_ERROR_BAD_PARAMETERS;
313
314 /* check if there are queued messages */
315 if (g_ssa_msg_queue.msg[out].msg_id != 0xFFFFFFFF) {
316 /* if there are, read them first */
317 tlogd("get msg %x from SSqueue[%u]\n", g_ssa_msg_queue.msg[out].msg_id, out);
318 *cmd = g_ssa_msg_queue.msg[out].msg_id;
319 *sender = g_ssa_msg_queue.msg[out].sender;
320
321 cp_size = (size < sizeof(union ssa_agent_msg)) ? size : sizeof(union ssa_agent_msg);
322
323 rc = memmove_s((void *)msg, size, (void *)(&g_ssa_msg_queue.msg[out].msg), cp_size);
324 if (rc != EOK)
325 return TEE_ERROR_SECURITY;
326
327 g_ssa_msg_queue.msg[out].msg_id = (uint32_t)0xFFFFFFFF;
328 if (++out >= SS_AGENT_MSG_QUEUE_SIZE)
329 out = 0;
330
331 g_ssa_msg_queue.out = out;
332 return TEE_SUCCESS;
333 }
334
335 do {
336 rc = memset_s((void *)buf, sizeof(union ssa_agent_msg), 0, sizeof(union ssa_agent_msg));
337 if (rc != EOK)
338 tlogw("memset failed %x\n", rc);
339
340 uint32_t ret =
341 (uint32_t)ipc_msg_rcv_a(OS_WAIT_FOREVER, (UINT32 *)(cmd), (void *)buf, sizeof(union ssa_agent_msg), sender);
342 if (ret != SRE_OK) {
343 tloge("ssa msg rcv error %x\n", ret);
344 continue;
345 }
346 tlogd("got msg %x from %x\n", *cmd, *sender);
347
348 cp_size = (size < sizeof(buf)) ? size : sizeof(buf);
349 rc = memmove_s(msg, size, buf, cp_size);
350 if (rc != EOK)
351 continue;
352
353 break;
354 } while (1);
355
356 return TEE_SUCCESS;
357 }
358
set_caller_info_proc(uint32_t task_id,uint32_t cmd)359 TEE_Result set_caller_info_proc(uint32_t task_id, uint32_t cmd)
360 {
361 uint32_t ret;
362 struct task_caller_info caller_proc_info;
363 ssa_cmd_t *cmd_oper = NULL;
364 uint8_t ret_msg[sizeof(union ssa_agent_msg)];
365 struct ssa_agent_rsp rsp;
366
367 caller_proc_info.taskid = task_id;
368 caller_proc_info.cmd = cmd;
369 ret = ipc_msg_snd(TEE_TASK_SET_CALLER_INFO, get_global_handle(), &caller_proc_info, sizeof(caller_proc_info));
370 if (ret != SRE_OK) {
371 tloge("ssa send caller info failed 0x%x\n", ret);
372 goto send_msg_to_ta;
373 } else {
374 (void)ssa_wait_msg(TEE_TASK_SET_CALLER_INFO_ACK, ret_msg, sizeof(ret_msg), get_global_handle());
375 if (((union ssa_agent_msg *)ret_msg)->ret != TEE_SUCCESS) {
376 tloge("set callerinfo fail, recv_ret:0x%x", ((union ssa_agent_msg *)ret_msg)->ret);
377 goto send_msg_to_ta;
378 }
379 }
380
381 return TEE_SUCCESS;
382
383 send_msg_to_ta:
384 /* when set caller info failed, a message should be sent to TA
385 * to prevent TA from being suspended */
386 cmd_oper = ssa_find_cmd(cmd);
387 if (cmd_oper != NULL && cmd_oper->need_ack == 1) {
388 rsp.ret = TEE_ERROR_GENERIC;
389 ret = (uint32_t)ipc_msg_snd(cmd, task_id, (void *)&rsp, sizeof(rsp));
390 if (ret != SRE_OK)
391 tloge("msg snd error %x\n", ret);
392 }
393 return TEE_ERROR_COMMUNICATION;
394 }
395
396