[FOSS_TLK]kernel: ote: Coverity fixes
[3rdparty/ote_partner/tlk.git] / kernel / ote_intf.c
1 /*
2  * Copyright (c) 2012-2015, NVIDIA CORPORATION. All rights reserved
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 #include <debug.h>
25 #include <errno.h>
26 #include <stddef.h>
27 #include <list.h>
28 #include <malloc.h>
29 #include <err.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <kernel/thread.h>
33 #include <kernel/event.h>
34 #include <platform/memmap.h>
35
36 #include <ote_intf.h>
37
38 #include <lib/ote/ote_protocol.h>
39
40 #define MAX_ARGS_PER_CMD        0x8
41
42 #define PRINT_UUID(s,u)                                                    \
43         dprintf(CRITICAL, "%s: uuid: 0x%x 0x%x 0x%x 0x%x%x 0x%x%x%x%x%x%x\n",  \
44                 s, (u)->time_low, (u)->time_mid,                           \
45                 (u)->time_hi_and_version,                                  \
46                 (u)->clock_seq_and_node[0],                                \
47                 (u)->clock_seq_and_node[1],                                \
48                 (u)->clock_seq_and_node[2],                                \
49                 (u)->clock_seq_and_node[3],                                \
50                 (u)->clock_seq_and_node[4],                                \
51                 (u)->clock_seq_and_node[5],                                \
52                 (u)->clock_seq_and_node[6],                                \
53                 (u)->clock_seq_and_node[7]);
54
55 static event_t task_event;
56 static unsigned int nactive_sessions;
57 /* global session id list */
58 static struct list_node session_list;
59 static struct list_node completion_list;
60
61 typedef struct {
62         struct list_node node;
63         bool active;
64         task_map_t *mptr;
65 } persist_map_t;
66
67 typedef struct {
68         struct list_node node;
69         struct list_node cmd_node;
70
71         unsigned int session_id;
72         struct list_node persist_maps;
73         void *context;
74         thread_t *thread;
75 } session_t;
76
77 typedef struct te_command {
78         struct list_node node;
79
80         te_entry_point_message_t msg;
81         session_t *session;
82
83         task_map_t *mptr[MAX_ARGS_PER_CMD];
84         u_int maps;
85         task_t *requesting_task;
86
87         uint32_t returning_cmd;
88 } te_command_t;
89
90 /* Check if client is restriced access.
91  * 'task_issued' is true when client is secure task.
92  * returns true if access is denied.
93  * returns false otherwise.  */
94 static bool check_restrict_access(task_t *task, bool task_issued)
95 {
96         ASSERT(task != NULL);
97
98         u_int restricted = task->props.restrict_access;
99         if (task_issued && (restricted & OTE_RESTRICT_SECURE_TASKS)) {
100                 dprintf(SPEW, "%s: Secure task client type denied access\n",
101                                 __func__);
102                 return true;
103         }
104         if (!task_issued && (restricted & OTE_RESTRICT_NON_SECURE_APPS)) {
105                 dprintf(SPEW, "%s: Non-secure app client type denied access\n",
106                                 __func__);
107                 return true;
108         }
109
110         if (task->task_state == TASK_STATE_BLOCKED) {
111                 dprintf(INFO, "%s: Task administratively blocked -- access denied\n",
112                         __func__);
113                 return true;
114         }
115
116         if (task->task_state != TASK_STATE_ACTIVE) {
117                 dprintf(INFO, "%s: Task is not in active state (%d) -- access denied\n",
118                         __func__, task->task_state);
119                 return true;
120         }
121
122         return false;
123 }
124
125 static char *te_get_fd_str(uint32_t fd)
126 {
127         char *fd_str;
128
129         switch (fd) {
130         case TE_INTERFACE:
131                 fd_str = "INTERFACE";
132                 break;
133         case TE_RESULT:
134                 fd_str = "RESULT";
135                 break;
136         case TE_INFO:
137                 fd_str = "INFO";
138                 break;
139         case TE_ERR:
140                 fd_str = "ERR";
141                 break;
142         case TE_SECURE:
143                 fd_str = "SECURE";
144                 break;
145         case TE_CRITICAL:
146                 fd_str = "CRITICAL";
147                 break;
148         default:
149                 fd_str = "BAD FD";
150         }
151
152         return fd_str;
153 }
154
155 static uint32_t new_session_id(void)
156 {
157         return platform_get_rand32();
158 }
159
160 static session_t *te_get_session_from_id(uint32_t id)
161 {
162         session_t *session;
163
164         list_for_every_entry(&session_list, session, session_t, node) {
165                 if (session->session_id == id)
166                         return session;
167         }
168 exit:
169         return NULL;
170 }
171
172 static te_error_t te_add_persist_map(task_map_t *mptr, session_t *session)
173 {
174         persist_map_t *persist_map = NULL;
175
176         persist_map = calloc(1, sizeof(persist_map_t));
177         if (persist_map == NULL) {
178                 return OTE_ERROR_OUT_OF_MEMORY;
179         }
180
181         list_initialize(&persist_map->node);
182         persist_map->mptr = mptr;
183         persist_map->active = false;
184
185         enter_critical_section();
186         list_add_tail(&session->persist_maps, &persist_map->node);
187         exit_critical_section();
188
189         return OTE_SUCCESS;
190 }
191
192 static void te_release_persist_maps(session_t *session, task_t *task,
193                                 bool only_inactive)
194 {
195         persist_map_t *persist_map, *next;
196
197         list_for_every_entry_safe(&session->persist_maps,
198                                 persist_map, next, persist_map_t, node) {
199
200                 /* skip active mappings if desired */
201                 if (only_inactive && persist_map->active)
202                         continue;
203
204                 arch_task_unmap_memory(task, persist_map->mptr);
205                 list_delete(&persist_map->node);
206                 free(persist_map);
207         }
208 }
209
210 static void te_update_persist_maps(session_t *session, task_t *task)
211 {
212         persist_map_t *persist_map, *next;
213
214         /* activate any pending persistent mappings */
215         list_for_every_entry_safe(&session->persist_maps,
216                                 persist_map, next, persist_map_t, node) {
217                 if (!persist_map->active)
218                         persist_map->active = true;
219         }
220 }
221
222 static te_error_t te_prepare_memref_param(task_t *task, struct te_command *cmd,
223                                         te_oper_param_t *param)
224 {
225         task_map_t *mptr;
226         uint64_t vaddr;
227         uint32_t size, flags;
228         te_error_t result;
229
230         /* set read/write flags */
231         if ((param->type == TE_PARAM_TYPE_MEM_RW) ||
232                 (param->type == TE_PARAM_TYPE_PERSIST_MEM_RW)) {
233                 flags = (TM_UR | TM_UW);
234         } else {
235                 flags = TM_UR;
236         }
237
238         /* make sure we have room if it's a temporary memref */
239         if ((param->type == TE_PARAM_TYPE_MEM_RO) ||
240                 (param->type == TE_PARAM_TYPE_MEM_RW)) {
241                 if (cmd->maps == MAX_ARGS_PER_CMD) {
242                         dprintf(CRITICAL, "out of memref maps\n");
243                         return OTE_ERROR_OUT_OF_MEMORY;
244                 }
245         }
246
247         vaddr = param->u.Mem.base;
248         size  = param->u.Mem.len;
249
250         if (!cmd->requesting_task) {
251                 /* command (and memory) came from the NS world */
252                 flags |= TM_NS_MEM;
253         } else {
254                 task_t *ctask = cmd->requesting_task;
255                 task_map_t *cmptr;
256
257                 /*
258                  * In mapping memory from one task to another, the pages could
259                  * have come from either the NS world, or its own malloc-ed
260                  * buffer. A lookup in the current task is needed to set the
261                  * TM_NS_MEM flag accordingly in this task's mapping.
262                  */
263                 ASSERT(ctask);
264                 ASSERT(ctask != task);
265
266                 flags |= TM_SEC_VA;
267                 cmptr = task_find_mapping(ctask, vaddr, size);
268                 if (cmptr == NULL) {
269                         dprintf(CRITICAL, "address 0x%08x not found in current task\n",
270                                 (u_int)vaddr);
271                         return OTE_ERROR_BAD_PARAMETERS;
272                 }
273                 flags |= (cmptr->flags & TM_NS_MEM);
274         }
275
276         mptr = arch_task_map_memory(task, vaddr, size, flags);
277         if (mptr == NULL) {
278                 return OTE_ERROR_OUT_OF_MEMORY;
279         }
280
281         if ((param->type == TE_PARAM_TYPE_PERSIST_MEM_RO) ||
282                 (param->type == TE_PARAM_TYPE_PERSIST_MEM_RW)) {
283
284                 result = te_add_persist_map(mptr, cmd->session);
285                 if (result != OTE_SUCCESS) {
286                         arch_task_unmap_memory(task, mptr);
287                         return result;
288                 }
289         } else {
290                 cmd->mptr[cmd->maps++] = mptr;
291         }
292
293         /* create new address w/ old page offset */
294         vaddr &= PAGE_MASK;
295         vaddr |= mptr->vaddr;
296
297         /* rewrite param with this mapping */
298         param->u.Mem.base = vaddr;
299
300         return OTE_SUCCESS;
301 }
302
303 static te_error_t te_check_operation_params(task_t *task, struct te_command *cmd)
304 {
305         te_oper_param_t *params;
306         uint32_t i, param_type;
307
308         params = (te_oper_param_t *)(uintptr_t)cmd->msg.params;
309
310         /* check params */
311         for (i = 0; i < cmd->msg.params_size; i++) {
312                 te_error_t result;
313
314                 switch (params[i].type) {
315                 case TE_PARAM_TYPE_INT_RW:
316                 case TE_PARAM_TYPE_INT_RO:
317                         continue;
318                 case TE_PARAM_TYPE_MEM_RO:
319                 case TE_PARAM_TYPE_MEM_RW:
320                 case TE_PARAM_TYPE_PERSIST_MEM_RO:
321                 case TE_PARAM_TYPE_PERSIST_MEM_RW:
322                         break;
323                 default:
324                         dprintf(CRITICAL, "%s: unknown param type: 0x%x\n",
325                                 __func__, params[i].type);
326                         return OTE_ERROR_BAD_PARAMETERS;
327                 }
328
329                 result = te_prepare_memref_param(task, cmd, &params[i]);
330                 if (result != OTE_SUCCESS) {
331                         dprintf(CRITICAL, "%s: memref map failed: 0x%x\n",
332                                 __func__, result);
333                         return result;
334                 }
335         }
336         return OTE_SUCCESS;
337 }
338
339 static te_error_t te_copyin_ta_params(te_request_t *req, struct te_command *cmd)
340 {
341         te_oper_param_t *in_param;
342         te_oper_param_t *out_params;
343         uint32_t i;
344
345         if (req->params_size == 0)
346                 return OTE_SUCCESS;
347
348         out_params = (te_oper_param_t *)calloc(1, req->params_size * sizeof(*out_params));
349         if (out_params == NULL)
350                 return OTE_ERROR_OUT_OF_MEMORY;
351
352         dprintf(SPEW, "%s: new out_params %p in_params %p\n",
353                 __func__, out_params, (void *)(uintptr_t)req->params);
354
355         in_param = (te_oper_param_t *)(uintptr_t)req->params;
356         for (i = 0; i < req->params_size; i++) {
357                 if (!in_param) {
358                         dprintf(CRITICAL, "%s: NULL in_param at index %d\n",
359                                         __func__, i);
360                         free(out_params);
361                         return OTE_ERROR_BAD_PARAMETERS;
362                 }
363
364                 memcpy(&out_params[i], in_param, sizeof(*out_params));
365
366                 switch (out_params[i].type) {
367                 case TE_PARAM_TYPE_INT_RO:
368                         dprintf(SPEW, "%s: %d: INT_RO: val 0x%x\n",
369                                 __func__, i, out_params[i].u.Int.val);
370                         break;
371                 case TE_PARAM_TYPE_INT_RW:
372                         dprintf(SPEW, "%s: %d: INT_RW: val 0x%x\n",
373                                 __func__, i, out_params[i].u.Int.val);
374                         break;
375                 case TE_PARAM_TYPE_MEM_RO:
376                         dprintf(SPEW, "%s: %d: MEM_RO: len 0x%x\n",
377                                 __func__, i, out_params[i].u.Mem.len);
378                         break;
379                 case TE_PARAM_TYPE_MEM_RW:
380                         dprintf(SPEW, "%s: %d: MEM_RW: len 0x%x\n",
381                                 __func__, i, out_params[i].u.Mem.len);
382                         break;
383                 case TE_PARAM_TYPE_PERSIST_MEM_RO:
384                         dprintf(SPEW, "%s: %d: PERSIST_MEM_RO: len 0x%x\n",
385                                 __func__, i, out_params[i].u.Mem.len);
386                         break;
387                 case TE_PARAM_TYPE_PERSIST_MEM_RW:
388                         dprintf(SPEW, "%s: %d: PERSIST_MEM_RW: len 0x%x\n",
389                                 __func__, i, out_params[i].u.Mem.len);
390                         break;
391
392                 default:
393                         dprintf(INFO, "%s: unhandled param type 0x%x\n",
394                                 __func__, in_param->type);
395                         break;
396                 }
397
398                 in_param = (te_oper_param_t *)(uintptr_t)in_param->next;
399
400                 /* fix up next ptr */
401                 if (in_param == NULL) {
402                         out_params[i].next = NULL;
403                 } else {
404                         out_params[i].next = (uintptr_t)&out_params[i+1];
405                 }
406         }
407
408         cmd->msg.params = (uintptr_t)out_params;
409         cmd->msg.params_size = req->params_size;
410
411         return OTE_SUCCESS;
412 }
413
414 static void te_copyout_ta_params(struct te_command *cmd, te_request_t *req)
415 {
416         te_oper_param_t *in_params;
417         te_oper_param_t *out_param;
418         uint32_t i;
419
420         if (cmd->msg.params_size == 0)
421                 return;
422
423         in_params = (te_oper_param_t *)(uintptr_t)cmd->msg.params;
424         out_param = (te_oper_param_t *)(uintptr_t)req->params;
425
426         for (i = 0; i < req->params_size; i++) {
427                 switch (out_param->type) {
428                 case TE_PARAM_TYPE_INT_RO:
429                         dprintf(SPEW, "%s: %d: INT_RO: val 0x%x\n",
430                                 __func__, i, in_params[i].u.Int.val);
431                         break;
432                 case TE_PARAM_TYPE_INT_RW:
433                         dprintf(SPEW, "%s: %d: INT_RW: val 0x%x\n",
434                                 __func__, i, in_params[i].u.Int.val);
435                         out_param->u.Int.val = in_params[i].u.Int.val;
436                         break;
437                 case TE_PARAM_TYPE_MEM_RO:
438                         dprintf(SPEW, "%s: %d: MEM_RO: len 0x%x\n",
439                                 __func__, i, in_params[i].u.Mem.len);
440                         break;
441                 case TE_PARAM_TYPE_MEM_RW:
442                         dprintf(SPEW, "%s: %d: MEM_RW: len 0x%x\n",
443                                 __func__, i, in_params[i].u.Mem.len);
444                         out_param->u.Mem.len = in_params[i].u.Mem.len;
445                         break;
446                 case TE_PARAM_TYPE_PERSIST_MEM_RO:
447                         dprintf(SPEW, "%s: %d: PERSIST_MEM_RO: len 0x%x\n",
448                                 __func__, i, in_params[i].u.Mem.len);
449                         break;
450                 case TE_PARAM_TYPE_PERSIST_MEM_RW:
451                         dprintf(SPEW, "%s: %d: PERSIST_MEM_RW: len 0x%x\n",
452                                 __func__, i, in_params[i].u.Mem.len);
453                         out_param->u.Mem.len = in_params[i].u.Mem.len;
454                         break;
455                 default:
456                         dprintf(INFO, "%s: %d: unhandled param type 0x%x\n",
457                                 __func__, i, out_param->type);
458                         break;
459                 }
460                 out_param = (te_oper_param_t *)(uintptr_t)out_param->next;
461         }
462
463         free((void *)(uintptr_t)cmd->msg.params);
464
465         return;
466 }
467
468 static session_t *te_create_thread_session(task_t *task)
469 {
470         bool duplicate_id;
471         session_t *session;
472         uint32_t i = 0;
473
474         if (task == NULL) {
475                 return NULL;
476         }
477
478         /* allocate session */
479         session = calloc(1, sizeof(session_t));
480         if (session == NULL)
481                 return NULL;
482
483         list_initialize(&session->node);
484         list_initialize(&session->cmd_node);
485         list_initialize(&session->persist_maps);
486
487         do {
488                 session_t *temp;
489
490                 duplicate_id = false;
491                 session->session_id = new_session_id();
492                 list_for_every_entry(&session_list, temp, session_t, node) {
493                         if (session->session_id == temp->session_id) {
494                                 duplicate_id = true;
495                                 break;
496                         }
497                 }
498         } while (duplicate_id);
499
500         /* check if single or multi instance */
501         if (task->props.multi_instance) {
502                 char name[32];
503
504                 sprintf(name, "task_%d_instance", (i + 1));
505                 session->thread = thread_create(name, (thread_start_routine)(task->entry),
506                                                 0, LOW_PRIORITY, 4096);
507                 if (session->thread == NULL) {
508                         dprintf(CRITICAL, "allocate task instance thread failed\n");
509                         free(session);
510                         return NULL;
511                 }
512                 thread_resume(session->thread);
513         } else {
514                 /* for single, use current instance */
515                 session->thread = list_peek_head_type(&task->thread_node,
516                                                       thread_t, task_node);
517         }
518
519         return session;
520 }
521
522 te_error_t te_handle_open_session(te_request_t *req, bool task_issued)
523 {
524         struct te_command *cmd = NULL;
525         te_service_id_t uuid;
526         task_t *task;
527         session_t *session = NULL;
528         te_error_t result = OTE_SUCCESS;
529
530         memcpy(&uuid, req->dest_uuid, sizeof(uuid));
531
532         task = task_find_task_by_uuid(&uuid);
533         if (task == NULL) {
534                 dprintf(SPEW, "%s: task with uuid not found!\n", __func__);
535                 PRINT_UUID(__func__, &uuid);
536                 return OTE_ERROR_BAD_PARAMETERS;
537         }
538
539         if (check_restrict_access(task, task_issued)) {
540                 return OTE_ERROR_ACCESS_DENIED;
541         }
542
543         session = te_create_thread_session(task);
544         if (session == NULL) {
545                 return OTE_ERROR_BAD_PARAMETERS;
546         }
547
548         //PRINT_UUID(__func__, &uuid);
549
550         /* setup command structure for task */
551         cmd = (struct te_command *) calloc(1, sizeof(struct te_command));
552         if (cmd == NULL) {
553                 result = OTE_ERROR_OUT_OF_MEMORY;
554                 goto exit;
555         }
556
557         cmd->msg.type = OPEN_SESSION;
558         list_initialize(&cmd->node);
559
560         /*
561          * If the request is from a service (TA), then we need to
562          * copy the parameters into a new buffer and forward that
563          * buffer onto the target service (TA).
564          */
565         if (task_issued) {
566                 result = te_copyin_ta_params(req, cmd);
567                 if (result != OTE_SUCCESS) {
568                         goto exit;
569                 }
570         } else {
571                 cmd->msg.params = req->params;
572                 cmd->msg.params_size = req->params_size;
573         }
574         cmd->returning_cmd = 0;
575
576         /* save reference if issued by another task */
577         if (task_issued)
578                 cmd->requesting_task = current_thread->arch.task;
579
580         cmd->session = session;
581         task = session->thread->arch.task;
582
583         result = te_check_operation_params(task, cmd);
584         if (result != OTE_SUCCESS) {
585                 goto exit;
586         }
587
588         if (task->props.multi_instance || !task->te_instances) {
589                 /* first instance, issue create instance first */
590                 cmd->msg.type = CREATE_INSTANCE;
591         }
592
593         enter_critical_section();
594         list_add_tail(&session->cmd_node, &cmd->node);
595         list_add_tail(&session_list, &session->node);
596
597         /* kickoff thread */
598         thread_unblock_from_wait_queue(session->thread, false, NO_ERROR);
599         thread_yield();
600         exit_critical_section();
601
602         result = OTE_SUCCESS;
603 exit:
604         if (result != OTE_SUCCESS) {
605                 if (cmd) {
606                         if (cmd->msg.params)
607                                 free((void *)(uintptr_t)cmd->msg.params);
608                         free(cmd);
609                 }
610                 if (session)
611                         free(session);
612         }
613         return result;
614 }
615
616 te_error_t te_handle_close_session(te_request_t *req, bool task_issued)
617 {
618         struct te_command *cmd;
619         session_t *session;
620         task_t *task;
621
622         session = te_get_session_from_id(req->session_id);
623         if (session == NULL) {
624                 return OTE_ERROR_BAD_PARAMETERS;
625         }
626
627         task = session->thread->arch.task;
628         if (check_restrict_access(task, task_issued)) {
629                 dprintf(CRITICAL, "Restricted client type tried to close "
630                         "session for a task which they are not permitted!\n");
631                 return OTE_ERROR_ACCESS_DENIED;
632         }
633
634         cmd = calloc(1, sizeof(struct te_command));
635         if (cmd == NULL) {
636                 return OTE_ERROR_OUT_OF_MEMORY;
637         }
638
639         cmd->msg.type = CLOSE_SESSION;
640         cmd->msg.context = (uintptr_t)session->context;
641         cmd->session = session;
642         cmd->returning_cmd = 0;
643
644         /* add command to session */
645         enter_critical_section();
646         list_add_tail(&session->cmd_node, &cmd->node);
647
648         /* kickoff thread */
649         thread_unblock_from_wait_queue(session->thread, false, NO_ERROR);
650         thread_yield();
651         exit_critical_section();
652
653         return OTE_SUCCESS;
654 }
655
656 te_error_t te_handle_launch_op(te_request_t *req, bool task_issued)
657 {
658         struct te_command *cmd;
659         task_t *task;
660         session_t *session;
661         te_error_t result;
662
663         dprintf(SPEW, "%s: entry\n", __func__);
664         session = te_get_session_from_id(req->session_id);
665         if (session == NULL) {
666                 return OTE_ERROR_BAD_PARAMETERS;
667         }
668
669         task = session->thread->arch.task;
670         if (check_restrict_access(task, task_issued)) {
671                 dprintf(CRITICAL, "Restricted client type tried to perform "
672                         "an operation with a session/task for which they are "
673                         "not permitted!\n");
674                 return OTE_ERROR_ACCESS_DENIED;
675         }
676
677         cmd = calloc(1, sizeof(struct te_command));
678         if (cmd == NULL) {
679                 return OTE_ERROR_OUT_OF_MEMORY;
680         }
681
682         cmd->msg.type = LAUNCH_OPERATION;
683         cmd->msg.context = (uintptr_t)session->context;
684         cmd->session = session;
685
686         /*
687          * If the request is from a service (TA), then we need to
688          * copy the parameters into a new buffer and forward that
689          * buffer onto the target service (TA).
690          */
691         if (task_issued) {
692                 result = te_copyin_ta_params(req, cmd);
693                 if (result != OTE_SUCCESS) {
694                         goto exit;
695                 }
696         } else {
697                 cmd->msg.params = req->params;
698                 cmd->msg.params_size = req->params_size;
699         }
700
701         cmd->msg.command_id = req->command_id;
702         cmd->returning_cmd = 0;
703
704         /* save reference if issued by another task */
705         if (task_issued)
706                 cmd->requesting_task = current_thread->arch.task;
707
708         result = te_check_operation_params(task, cmd);
709         if (result != OTE_SUCCESS) {
710                 goto exit;
711         }
712
713         /* add command to session */
714         enter_critical_section();
715         list_add_tail(&session->cmd_node, &cmd->node);
716
717         /* kickoff thread */
718         thread_unblock_from_wait_queue(session->thread, false, NO_ERROR);
719         thread_yield();
720         exit_critical_section();
721
722         result = OTE_SUCCESS;
723
724 exit:
725         if (result != OTE_SUCCESS) {
726                 if (cmd->msg.params)
727                         free((void *)(uintptr_t)cmd->msg.params);
728                 if (cmd)
729                         free(cmd);
730         }
731         return result;
732 }
733
734 te_error_t te_handle_ta_event(enum ta_event_id event)
735 {
736         struct te_command cmd;
737
738         memset(&cmd, 0, sizeof(cmd));
739
740         cmd.msg.type = TA_EVENT;
741         cmd.msg.command_id = event;
742
743         /* Signal all tasks that have requested events.  */
744         return task_signal_ta_event(event, &cmd);
745 }
746
747 void te_intf_init(void)
748 {
749         /* initialize the session id list */
750         list_initialize(&session_list);
751
752         /* initialize the command list */
753         list_initialize(&completion_list);
754
755         event_init(&task_event, false, EVENT_FLAG_AUTOUNSIGNAL);
756 }
757
758 void te_get_completed_cmd(te_request_t *req, bool task_issued)
759 {
760         struct te_command *cmd;
761         session_t *session, *next;
762         task_t *task;
763
764         cmd = list_remove_head_type(&completion_list, struct te_command, node);
765
766         if (cmd == NULL) {
767                 /* command didn't complete (let NS world know) */
768                 req->result = OTE_ERROR_NO_ANSWER;
769                 req->result_origin = OTE_RESULT_ORIGIN_KERNEL;
770                 return;
771         }
772
773         /* get session */
774         list_for_every_entry_safe(&session_list, session, next, session_t, node) {
775                 if (cmd->session == session) {
776                         break;
777                 }
778         }
779
780         task = session->thread->arch.task;
781
782         dprintf(SPEW, "%s: cmd %d\n", __func__, cmd->msg.type);
783
784         switch (cmd->msg.type) {
785         case CREATE_INSTANCE:
786         case OPEN_SESSION:
787                 /* unhook and free session on failure */
788                 if (cmd->msg.result != OTE_SUCCESS) {
789                         ASSERT(session && next);
790
791                         /* release persistent mappings if any */
792                         te_release_persist_maps(session, task, false);
793
794                         list_delete(&session->node);
795                         free(session);
796                         req->session_id = 0x0;
797                 } else {
798                         /* return session id */
799                         nactive_sessions++;
800                         task->te_instances++;
801                         req->session_id = session->session_id;
802                         if (task_issued)
803                                 te_copyout_ta_params(cmd, req);
804
805                         /* mark persistent mappings as active */
806                         te_update_persist_maps(session, task);
807                 }
808                 break;
809         case DESTROY_INSTANCE:
810         case CLOSE_SESSION:
811                 ASSERT(session && next);
812
813                 /* release any persistent mappings */
814                 te_release_persist_maps(session, task, false);
815
816                 /* unhook and free session */
817                 list_delete(&session->node);
818                 free(session);
819                 nactive_sessions--;
820                 task->te_instances--;
821                 break;
822         case LAUNCH_OPERATION:
823                 if (cmd->msg.result != OTE_SUCCESS) {
824                         /* release inactive persistent mappings if any */
825                         te_release_persist_maps(session, task, true);
826                 } else {
827                         /* mark persistent mappings as active */
828                         te_update_persist_maps(session, task);
829
830                         if (task_issued)
831                                 te_copyout_ta_params(cmd, req);
832                 }
833                 break;
834         }
835
836         req->result = cmd->msg.result;
837         req->result_origin = OTE_RESULT_ORIGIN_TRUSTED_APP;
838
839         dprintf(SPEW, "%s: 0x%x 0x%x\n", __func__, req->result, req->result_origin);
840
841         free(cmd);
842 }
843
844 static struct te_command *te_thread_current_command()
845 {
846         struct te_command *cmd = NULL;
847         session_t *session;
848
849         /* return current command, if one is bound */
850         if (current_thread->arg)
851                 return (struct te_command *) current_thread->arg;
852
853         if (list_is_empty(&session_list))
854                 return NULL;
855
856         /* traverse session list for a command for this thread */
857         enter_critical_section();
858         list_for_every_entry(&session_list, session, session_t, node) {
859                 if (session->thread == current_thread) {
860                         cmd = list_remove_head_type(&session->cmd_node, struct te_command, node);
861                         if (cmd)
862                                 break;
863                 }
864         }
865         exit_critical_section();
866         return cmd;
867 }
868
869 static int te_handle_command_message(struct te_command *cmd, void *msg, bool read)
870 {
871         te_entry_point_message_t *ep;
872
873         if (read && !cmd) {
874                 /* no commands for this thread, wait */
875                 event_wait(&task_event);
876                 cmd = te_thread_current_command();
877         }
878
879         if (cmd->returning_cmd) {
880                 ep = (te_entry_point_message_t *) msg;
881                 cmd->returning_cmd = 0;
882                 /* copy params take two pass syscalls */
883                 ep = (te_entry_point_message_t *) msg;
884                 if (ep->params_size == cmd->msg.params_size && ep->params != NULL) {
885                         memcpy((void *)(uintptr_t)ep->params,
886                                 (void *)(uintptr_t)cmd->msg.params,
887                                 sizeof(te_oper_param_t) * ep->params_size);
888                 } else {
889                         return -EINVAL;
890                 }
891                 return sizeof(*ep);
892         }
893
894         if (read) {
895                 ASSERT(cmd);
896
897                 /* setup message */
898                 memset(msg, 0, sizeof(te_entry_point_message_t));
899
900                 ep = (te_entry_point_message_t *) msg;
901                 ep->type = cmd->msg.type;
902
903                 switch (ep->type) {
904                 case CREATE_INSTANCE:
905                 case DESTROY_INSTANCE:
906                         break;
907                 case OPEN_SESSION:
908                         ep->context = cmd->msg.context;
909                         ep->params_size = cmd->msg.params_size;
910                         if (ep->params_size)
911                                 cmd->returning_cmd = 1;
912                         break;
913                 case CLOSE_SESSION:
914                         ep->context = cmd->msg.context;
915                         break;
916                 case LAUNCH_OPERATION:
917                         ep->context = cmd->msg.context;
918                         ep->command_id = cmd->msg.command_id;
919                         ep->params_size = cmd->msg.params_size;
920                         if (ep->params_size)
921                                 cmd->returning_cmd = 1;
922                         break;
923                 case TA_EVENT:
924                         ep->command_id = cmd->msg.command_id;
925
926                         /* events do not write back a result.
927                          * clear current arg.  */
928                         current_thread->arg = NULL;
929                         return sizeof(*ep);
930                 default:
931                         /* unknown command */
932                         return -EINVAL;
933                 }
934
935                 current_thread->arg = cmd;
936                 return sizeof(*ep);
937         }
938
939         /* TBD handle writes for TA -> TA commands */
940         return -EINVAL;
941 }
942
943 static int te_handle_result_message(struct te_command *cmd, void *msg, bool read)
944 {
945         te_entry_point_message_t *ep;
946         task_t *task;
947
948         if (read || !cmd) {
949                 /* expect only writes and command pending */
950                 return -EINVAL;
951         }
952
953         ep = (te_entry_point_message_t *) msg;
954         if ((ep->result == OTE_SUCCESS) && (cmd->msg.type == CREATE_INSTANCE)) {
955                 /*
956                  * Special handling occurs on a successful CREATE_INSTANCE.
957                  *
958                  * This is always followed by an OPEN_SESSION command and only
959                  * the status of the OPEN_SESSION is returned to the caller.
960                  * Just change type (no need to unhook it), so it's found
961                  * when the TA queries for the next command.
962                  */
963                 cmd->msg.type = OPEN_SESSION;
964                 return sizeof(te_entry_point_message_t);
965         } else if (cmd->msg.type == CLOSE_SESSION) {
966                 /*
967                  * Same type of handling occurs on a DESTROY_INSTANCE, where
968                  * CLOSE_SESSION is what follows (no check of status as
969                  * DESTROY_INSTANCE doesn't return one).
970                  */
971                 task = cmd->session->thread->arch.task;
972
973                 if (task->props.multi_instance || (task->te_instances == 1)) {
974                         /* last instance, issue delete instance first */
975                         cmd->msg.type = DESTROY_INSTANCE;
976                         return sizeof(te_entry_point_message_t);
977                 }
978         }
979
980         /* copy back data to command */
981         switch (cmd->msg.type) {
982         case CREATE_INSTANCE:
983         case DESTROY_INSTANCE:
984         case CLOSE_SESSION:
985                 /* these don't return a result, just make it look clean */
986                 cmd->msg.result = OTE_SUCCESS;
987                 break;
988
989         case OPEN_SESSION:
990                 cmd->msg.result = ep->result;
991                 if (ep->params_size && ep->params) {
992                         memcpy((void *)(uintptr_t)cmd->msg.params,
993                                 (void *)(uintptr_t)ep->params,
994                                 sizeof(te_oper_param_t) * cmd->msg.params_size);
995                 }
996                 cmd->session->context = (void *)(uintptr_t)ep->context;
997
998                 /* release non-persistent mappings */
999                 task = cmd->session->thread->arch.task;
1000                 while (cmd->maps--) {
1001                         arch_task_unmap_memory(task, cmd->mptr[cmd->maps]);
1002                 }
1003                 break;
1004         case LAUNCH_OPERATION:
1005                 cmd->msg.result = ep->result;
1006                 cmd->msg.command_id = ep->command_id;
1007                 if (ep->params_size && ep->params) {
1008                         memcpy((void *)(uintptr_t)cmd->msg.params,
1009                                 (void *)(uintptr_t)ep->params,
1010                                 sizeof(te_oper_param_t) * ep->params_size);
1011                 }
1012
1013                 /* release non-persistent mappings */
1014                 task = cmd->session->thread->arch.task;
1015                 while (cmd->maps--) {
1016                         arch_task_unmap_memory(task, cmd->mptr[cmd->maps]);
1017                 }
1018                 break;
1019         }
1020
1021         /* unhook command and add to completion */
1022         current_thread->arg = NULL;
1023
1024         enter_critical_section();
1025         list_add_tail(&completion_list, &cmd->node);
1026         exit_critical_section();
1027
1028         return sizeof(te_entry_point_message_t);
1029 }
1030
1031 /*
1032  * This routine is called anytime the trusted app (TA) requests the next
1033  * command (reads the interface fd) or completes a command by writing the
1034  * result fd. A TA is also able to request a command of another TA by
1035  * writing to the interface fd.
1036  *
1037  * On completion, status is copied back to the current command and
1038  * the command is added to the completion list. When the idle thread is
1039  * scheduled, it picks up the status and returns it.
1040  */
1041 int te_handle_ta_message(uint32_t fd, void *msg, uint32_t size, bool read)
1042 {
1043         struct te_command *cmd;
1044         int retval;
1045         dprintf(SPEW, "%s: thread: 0x%p fd: %s action: %s\n",
1046                 __func__,
1047                 current_thread,
1048                 te_get_fd_str(fd),
1049                 ((read) ? "READ" : "WRITE"));
1050
1051         /* sanity checks */
1052         if (msg == NULL)
1053                 return -EFAULT;
1054
1055         if ((fd == TE_RESULT) || (fd == TE_INTERFACE)) {
1056                 if (size < sizeof(te_entry_point_message_t))
1057                         return -EINVAL;
1058         }
1059
1060         if ((fd != TE_RESULT) &&
1061                         (fd != TE_INTERFACE) &&
1062                         (fd != TE_INFO) &&
1063                         (fd != TE_ERR) &&
1064                         (fd != TE_SECURE) &&
1065                         (fd != TE_CRITICAL))
1066                 return -EBADF;
1067
1068         cmd = te_thread_current_command();
1069
1070         switch (fd) {
1071         case TE_INTERFACE:
1072                 /* get next command or issue to another TA */
1073                 retval = te_handle_command_message(cmd, msg, read);
1074                 break;
1075         case TE_RESULT:
1076                 /* pickup result of previous command */
1077                 retval = te_handle_result_message(cmd, msg, read);
1078                 break;
1079         case TE_CRITICAL:
1080         case TE_ERR:
1081         case TE_SECURE:
1082         case TE_INFO:
1083                 dprintf(CRITICAL, "%s", (char *)msg);
1084                 retval = size;
1085                 break;
1086         default:
1087                 return -EBADF;
1088         }
1089
1090         return retval;
1091 }
1092
1093 int te_get_current_ta_property(te_get_property_args_t *args)
1094 {
1095         task_t *taskp = current_thread->arch.task;
1096
1097         /* determine which client property they're after */
1098         ASSERT(args->data_type == OTE_PROP_DATA_TYPE_UUID);
1099         ASSERT(args->value_size == sizeof(te_service_id_t));
1100
1101         memcpy(&args->value.uuid,
1102                &taskp->props.uuid,
1103                sizeof(te_service_id_t));
1104
1105         args->result = OTE_SUCCESS;
1106         return 0;
1107 }
1108
1109 int te_get_current_client_property(te_get_property_args_t *args)
1110 {
1111         task_t *taskp;
1112         struct te_command *cmd;
1113
1114         /* determine which client property they're after */
1115         ASSERT(args->data_type == OTE_PROP_DATA_TYPE_IDENTITY);
1116         ASSERT(args->value_size == sizeof(te_identity_t));
1117
1118         /* we expect to have a current command bound */
1119         if (!current_thread->arg) {
1120                 args->result = OTE_ERROR_BAD_STATE;
1121                 return -EINVAL;
1122         }
1123
1124         cmd = (struct te_command *) current_thread->arg;
1125
1126         /* set login type and uuid */
1127         if (cmd->requesting_task) {
1128                 taskp = cmd->requesting_task;
1129                 memcpy(&args->value.identity.uuid, &taskp->props.uuid,
1130                         sizeof(te_service_id_t));
1131                 args->value.identity.login = TE_LOGIN_TA;
1132         } else {
1133                 /* no uuid available */
1134                 memset(&args->value.identity.uuid, 0, sizeof(te_service_id_t));
1135                 args->value.identity.login = TE_LOGIN_PUBLIC;
1136         }
1137
1138         args->result = OTE_SUCCESS;
1139         return 0;
1140 }
1141
1142 int te_get_implementation_property(te_get_property_args_t *args)
1143 {
1144         /* XXX to be done */
1145         args->result = OTE_ERROR_NOT_IMPLEMENTED;
1146         return -EINVAL;
1147 }
1148
1149 void te_session_cancel_thread(thread_t *t)
1150 {
1151         session_t *session = NULL;
1152         session_t *s_tmp = NULL;
1153
1154         enter_critical_section();
1155
1156         /* Delete any session referring to the thread being canceled. */
1157         list_for_every_entry_safe(&session_list, session, s_tmp, session_t, node) {
1158                 if (session->thread == t) {
1159                         task_t *task = NULL;
1160                         struct te_command *cmd = NULL;
1161                         struct te_command *cmd_tmp = NULL;
1162
1163                         list_delete(&session->node);
1164
1165                         task = session->thread->arch.task;
1166
1167                         list_for_every_entry_safe(&session->cmd_node, cmd, cmd_tmp,
1168                                                   te_command_t, node) {
1169                                 while (cmd->maps--) {
1170                                         arch_task_unmap_memory(task,
1171                                                         cmd->mptr[cmd->maps]);
1172                                 }
1173                                 list_delete(&cmd->node);
1174                                 free(cmd);
1175                                 cmd = NULL;
1176                         }
1177
1178                         te_release_persist_maps(session, task, false);
1179                         free(session);
1180                         session = NULL;
1181                 }
1182         }
1183         exit_critical_section();
1184 }