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