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