OP-TEE: update optee_linuxdriver to match updated optee_os & optee_client
[firefly-linux-kernel-4.4.55.git] / security / optee_linuxdriver / core / tee_session.c
1 /*
2  * Copyright (c) 2014, STMicroelectronics International N.V.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License Version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  */
13 #include <linux/slab.h>
14 #include <linux/device.h>
15 #include <linux/types.h>
16 #include <linux/file.h>
17 #include <linux/atomic.h>
18 #include <linux/uaccess.h>
19 #include <linux/anon_inodes.h>
20
21 #include "tee_shm.h"
22 #include "tee_core_priv.h"
23
24 static int _init_tee_cmd(struct tee_session *sess, struct tee_cmd_io *cmd_io,
25                          struct tee_cmd *cmd);
26 static void _update_client_tee_cmd(struct tee_session *sess,
27                                    struct tee_cmd_io *cmd_io,
28                                    struct tee_cmd *cmd);
29 static void _release_tee_cmd(struct tee_session *sess, struct tee_cmd *cmd);
30
31 #define _DEV_TEE _DEV(sess->ctx->tee)
32
33 #define INMSG dev_dbg(_DEV_TEE, "%s: >\n", __func__)
34 #define OUTMSG(val) dev_dbg(_DEV_TEE, "%s: < %d\n", __func__, (int)val)
35
36 /******************************************************************************/
37
38 static inline bool flag_set(int val, int flags)
39 {
40         return (val & flags) == flags;
41 }
42
43 static inline bool is_mapped_temp(int flags)
44 {
45         return flag_set(flags, TEE_SHM_MAPPED | TEE_SHM_TEMP);
46 }
47
48
49 /******************************************************************************/
50
51 #define _UUID_STR_SIZE 35
52 static char *_uuid_to_str(const TEEC_UUID *uuid)
53 {
54         static char uuid_str[_UUID_STR_SIZE];
55
56         if (uuid) {
57                 sprintf(uuid_str,
58                         "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
59                         uuid->timeLow, uuid->timeMid, uuid->timeHiAndVersion,
60                         uuid->clockSeqAndNode[0], uuid->clockSeqAndNode[1],
61                         uuid->clockSeqAndNode[2], uuid->clockSeqAndNode[3],
62                         uuid->clockSeqAndNode[4], uuid->clockSeqAndNode[5],
63                         uuid->clockSeqAndNode[6], uuid->clockSeqAndNode[7]);
64         } else {
65                 sprintf(uuid_str, "NULL");
66         }
67
68         return uuid_str;
69 }
70
71 static int tee_copy_from_user(struct tee_context *ctx, void *to, void *from,
72                               size_t size)
73 {
74         if ((!to) || (!from) || (!size))
75                 return 0;
76         if (ctx->usr_client)
77                 return copy_from_user(to, from, size);
78         else {
79                 memcpy(to, from, size);
80                 return 0;
81         }
82 }
83
84 static int tee_copy_to_user(struct tee_context *ctx, void *to, void *from,
85                             size_t size)
86 {
87         if ((!to) || (!from) || (!size))
88                 return 0;
89         if (ctx->usr_client)
90                 return copy_to_user(to, from, size);
91         else {
92                 memcpy(to, from, size);
93                 return 0;
94         }
95 }
96
97 /* Defined as macro to let the put_user macro see the types */
98 #define tee_put_user(ctx, from, to)                             \
99         do {                                                    \
100                 if ((ctx)->usr_client)                          \
101                         put_user(from, to);                     \
102                 else                                            \
103                         *to = from;                             \
104         } while (0)
105
106 static inline int tee_session_is_opened(struct tee_session *sess)
107 {
108         if (sess && sess->sessid)
109                 return (sess->sessid != 0);
110         return 0;
111 }
112
113 static int tee_session_open_be(struct tee_session *sess,
114                                struct tee_cmd_io *cmd_io)
115 {
116         int ret = -EINVAL;
117         struct tee *tee;
118         struct tee_cmd cmd;
119
120         BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
121
122         tee = sess->ctx->tee;
123
124         dev_dbg(_DEV(tee), "%s: > open a new session", __func__);
125
126         sess->sessid = 0;
127         ret = _init_tee_cmd(sess, cmd_io, &cmd);
128         if (ret)
129                 goto out;
130
131         if (cmd.uuid) {
132                 dev_dbg(_DEV(tee), "%s: UUID=%s\n", __func__,
133                         _uuid_to_str((TEEC_UUID *) cmd.uuid->kaddr));
134         }
135
136         ret = tee->ops->open(sess, &cmd);
137         if (ret == 0)
138                 _update_client_tee_cmd(sess, cmd_io, &cmd);
139         else {
140                 /* propagate the reason of the error */
141                 cmd_io->origin = cmd.origin;
142                 cmd_io->err = cmd.err;
143         }
144
145 out:
146         _release_tee_cmd(sess, &cmd);
147         dev_dbg(_DEV(tee), "%s: < ret=%d, sessid=%08x", __func__, ret,
148                 sess->sessid);
149         return ret;
150 }
151
152 int tee_session_invoke_be(struct tee_session *sess, struct tee_cmd_io *cmd_io)
153 {
154         int ret = -EINVAL;
155         struct tee *tee;
156         struct tee_cmd cmd;
157
158         BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
159
160         tee = sess->ctx->tee;
161
162         dev_dbg(_DEV(tee), "%s: > sessid=%08x, cmd=0x%08x\n", __func__,
163                 sess->sessid, cmd_io->cmd);
164
165         ret = _init_tee_cmd(sess, cmd_io, &cmd);
166         if (ret)
167                 goto out;
168
169         ret = tee->ops->invoke(sess, &cmd);
170         if (!ret)
171                 _update_client_tee_cmd(sess, cmd_io, &cmd);
172         else {
173                 /* propagate the reason of the error */
174                 cmd_io->origin = cmd.origin;
175                 cmd_io->err = cmd.err;
176         }
177
178 out:
179         _release_tee_cmd(sess, &cmd);
180         dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
181         return ret;
182 }
183
184 static int tee_session_close_be(struct tee_session *sess)
185 {
186         int ret = -EINVAL;
187         struct tee *tee;
188
189         BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
190
191         tee = sess->ctx->tee;
192
193         dev_dbg(_DEV(tee), "%s: > sessid=%08x", __func__, sess->sessid);
194
195         ret = tee->ops->close(sess);
196         sess->sessid = 0;
197
198         dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
199         return ret;
200 }
201
202 static int tee_session_cancel_be(struct tee_session *sess,
203                                  struct tee_cmd_io *cmd_io)
204 {
205         int ret = -EINVAL;
206         struct tee *tee;
207         struct tee_cmd cmd;
208
209         BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
210
211         tee = sess->ctx->tee;
212
213         dev_dbg(_DEV(tee), "%s: > sessid=%08x, cmd=0x%08x\n", __func__,
214                 sess->sessid, cmd_io->cmd);
215
216         ret = _init_tee_cmd(sess, cmd_io, &cmd);
217         if (ret)
218                 goto out;
219
220         ret = tee->ops->cancel(sess, &cmd);
221
222 out:
223         _release_tee_cmd(sess, &cmd);
224         dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
225         return ret;
226 }
227
228 static int tee_do_invoke_command(struct tee_session *sess,
229                                  struct tee_cmd_io __user *u_cmd)
230 {
231         int ret = -EINVAL;
232         struct tee *tee;
233         struct tee_cmd_io k_cmd;
234         struct tee_context *ctx;
235
236         BUG_ON(!sess->ctx);
237         BUG_ON(!sess->ctx->tee);
238         ctx = sess->ctx;
239         tee = sess->ctx->tee;
240
241         dev_dbg(_DEV(tee), "%s: > sessid=%08x\n", __func__, sess->sessid);
242
243         BUG_ON(!sess->sessid);
244
245         if (tee_copy_from_user
246             (ctx, &k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) {
247                 dev_err(_DEV(tee), "%s: tee_copy_from_user failed\n", __func__);
248                 goto exit;
249         }
250
251         if ((k_cmd.op == NULL) || (k_cmd.uuid != NULL) ||
252             (k_cmd.data != NULL) || (k_cmd.data_size != 0)) {
253                 dev_err(_DEV(tee),
254                         "%s: op or/and data parameters are not valid\n",
255                         __func__);
256                 goto exit;
257         }
258
259         ret = tee_session_invoke_be(sess, &k_cmd);
260         if (ret)
261                 dev_err(_DEV(tee), "%s: tee_invoke_command failed\n", __func__);
262
263         tee_put_user(ctx, k_cmd.err, &u_cmd->err);
264         tee_put_user(ctx, k_cmd.origin, &u_cmd->origin);
265
266 exit:
267         dev_dbg(_DEV(tee), "%s: < ret=%d\n", __func__, ret);
268         return ret;
269 }
270
271 static int tee_do_cancel_cmd(struct tee_session *sess,
272                              struct tee_cmd_io __user *u_cmd)
273 {
274         int ret = -EINVAL;
275         struct tee *tee;
276         struct tee_cmd_io k_cmd;
277         struct tee_context *ctx;
278
279         BUG_ON(!sess->ctx);
280         BUG_ON(!sess->ctx->tee);
281         ctx = sess->ctx;
282         tee = sess->ctx->tee;
283
284         dev_dbg(sess->ctx->tee->dev, "%s: > sessid=%08x\n", __func__,
285                 sess->sessid);
286
287         BUG_ON(!sess->sessid);
288
289         if (tee_copy_from_user
290             (ctx, &k_cmd, (void *)u_cmd, sizeof(struct tee_cmd_io))) {
291                 dev_err(_DEV(tee), "%s: tee_copy_from_user failed\n", __func__);
292                 goto exit;
293         }
294
295         if ((k_cmd.op == NULL) || (k_cmd.uuid != NULL) ||
296             (k_cmd.data != NULL) || (k_cmd.data_size != 0)) {
297                 dev_err(_DEV(tee),
298                         "%s: op or/and data parameters are not valid\n",
299                         __func__);
300                 goto exit;
301         }
302
303         ret = tee_session_cancel_be(sess, &k_cmd);
304         if (ret)
305                 dev_err(_DEV(tee), "%s: tee_invoke_command failed\n", __func__);
306
307         tee_put_user(ctx, k_cmd.err, &u_cmd->err);
308         tee_put_user(ctx, k_cmd.origin, &u_cmd->origin);
309
310 exit:
311         dev_dbg(_DEV(tee), "%s: < ret=%d", __func__, ret);
312         return ret;
313 }
314
315 static long tee_session_ioctl(struct file *filp, unsigned int cmd,
316                               unsigned long arg)
317 {
318         struct tee *tee;
319         struct tee_session *sess = filp->private_data;
320         int ret;
321
322         BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
323
324         tee = sess->ctx->tee;
325
326         dev_dbg(_DEV(tee), "%s: > cmd nr=%d\n", __func__, _IOC_NR(cmd));
327
328         switch (cmd) {
329         case TEE_INVOKE_COMMAND_IOC:
330                 ret =
331                     tee_do_invoke_command(sess,
332                                           (struct tee_cmd_io __user *)arg);
333                 break;
334         case TEE_REQUEST_CANCELLATION_IOC:
335                 ret = tee_do_cancel_cmd(sess, (struct tee_cmd_io __user *)arg);
336                 break;
337         default:
338                 ret = -ENOSYS;
339                 break;
340         }
341
342         dev_dbg(_DEV(tee), "%s: < ret=%d\n", __func__, ret);
343
344         return ret;
345 }
346
347 static int tee_session_release(struct inode *inode, struct file *filp)
348 {
349         struct tee_session *sess = filp->private_data;
350         int ret = 0;
351         struct tee *tee;
352
353         BUG_ON(!sess || !sess->ctx || !sess->ctx->tee);
354         tee = sess->ctx->tee;
355
356         ret = tee_session_close_and_destroy(sess);
357         return ret;
358 }
359
360 const struct file_operations tee_session_fops = {
361         .owner = THIS_MODULE,
362 #ifdef CONFIG_COMPAT
363         .compat_ioctl = tee_session_ioctl,
364 #endif
365         .unlocked_ioctl = tee_session_ioctl,
366         .compat_ioctl = tee_session_ioctl,
367         .release = tee_session_release,
368 };
369
370 int tee_session_close_and_destroy(struct tee_session *sess)
371 {
372         int ret;
373         struct tee *tee;
374         struct tee_context *ctx;
375
376         if (!sess || !sess->ctx || !sess->ctx->tee)
377                 return -EINVAL;
378
379         ctx = sess->ctx;
380         tee = ctx->tee;
381
382         dev_dbg(_DEV(tee), "%s: > sess=%p\n", __func__, sess);
383
384         if (!tee_session_is_opened(sess))
385                 return -EINVAL;
386
387         ret = tee_session_close_be(sess);
388
389         mutex_lock(&tee->lock);
390         tee_dec_stats(&tee->stats[TEE_STATS_SESSION_IDX]);
391         list_del(&sess->entry);
392
393         devm_kfree(_DEV(tee), sess);
394         tee_context_put(ctx);
395         tee_put(tee);
396         mutex_unlock(&tee->lock);
397
398         dev_dbg(_DEV(tee), "%s: <\n", __func__);
399         return ret;
400 }
401
402 struct tee_session *tee_session_create_and_open(struct tee_context *ctx,
403                                                 struct tee_cmd_io *cmd_io)
404 {
405         int ret = 0;
406         struct tee_session *sess;
407         struct tee *tee;
408
409         BUG_ON(!ctx->tee);
410
411         tee = ctx->tee;
412
413         dev_dbg(_DEV(tee), "%s: >\n", __func__);
414         ret = tee_get(tee);
415         if (ret)
416                 return ERR_PTR(-EBUSY);
417
418         sess = devm_kzalloc(_DEV(tee), sizeof(struct tee_session), GFP_KERNEL);
419         if (!sess) {
420                 dev_err(_DEV(tee), "%s: tee_session allocation() failed\n",
421                         __func__);
422                 tee_put(tee);
423                 return ERR_PTR(-ENOMEM);
424         }
425
426         tee_context_get(ctx);
427         sess->ctx = ctx;
428
429         ret = tee_session_open_be(sess, cmd_io);
430         mutex_lock(&tee->lock);
431         if (ret || !sess->sessid || cmd_io->err) {
432                 dev_err(_DEV(tee), "%s: ERROR ret=%d (err=0x%08x, org=%d,  sessid=0x%08x)\n",
433                                 __func__, ret, cmd_io->err,
434                                 cmd_io->origin, sess->sessid);
435                 tee_put(tee);
436                 tee_context_put(ctx);
437                 devm_kfree(_DEV(tee), sess);
438                 mutex_unlock(&tee->lock);
439                 if (ret)
440                         return ERR_PTR(ret);
441                 else
442                         return NULL;
443         }
444
445         tee_inc_stats(&tee->stats[TEE_STATS_SESSION_IDX]);
446         list_add_tail(&sess->entry, &ctx->list_sess);
447         mutex_unlock(&tee->lock);
448
449         dev_dbg(_DEV(tee), "%s: < sess=%p\n", __func__, sess);
450         return sess;
451 }
452
453 int tee_session_create_fd(struct tee_context *ctx, struct tee_cmd_io *cmd_io)
454 {
455         int ret;
456         struct tee_session *sess;
457         struct tee *tee = ctx->tee;
458
459         BUG_ON(cmd_io->fd_sess > 0);
460
461         dev_dbg(_DEV(tee), "%s: >\n", __func__);
462
463         sess = tee_session_create_and_open(ctx, cmd_io);
464         if (IS_ERR_OR_NULL(sess)) {
465                 ret = PTR_ERR(sess);
466                 dev_dbg(_DEV(tee), "%s: ERROR can't create the session (ret=%d, err=0x%08x, org=%d)\n",
467                         __func__, ret, cmd_io->err, cmd_io->origin);
468                 cmd_io->fd_sess = -1;
469                 goto out;
470         }
471
472         /* Retrieve a fd */
473         cmd_io->fd_sess = -1;
474         ret =
475             anon_inode_getfd("tee_session", &tee_session_fops, sess, O_CLOEXEC);
476         if (ret < 0) {
477                 dev_err(_DEV(tee), "%s: ERROR can't get a fd (ret=%d)\n",
478                         __func__, ret);
479                 tee_session_close_and_destroy(sess);
480                 goto out;
481         }
482         cmd_io->fd_sess = ret;
483         ret = 0;
484
485 out:
486         dev_dbg(_DEV(tee), "%s: < ret=%d, sess=%p, fd=%d\n", __func__,
487                 ret, sess, cmd_io->fd_sess);
488         return ret;
489 }
490
491 static bool tee_session_is_supported_type(struct tee_session *sess, int type)
492 {
493         switch (type) {
494         case TEEC_NONE:
495         case TEEC_VALUE_INPUT:
496         case TEEC_VALUE_OUTPUT:
497         case TEEC_VALUE_INOUT:
498         case TEEC_MEMREF_TEMP_INPUT:
499         case TEEC_MEMREF_TEMP_OUTPUT:
500         case TEEC_MEMREF_TEMP_INOUT:
501         case TEEC_MEMREF_WHOLE:
502         case TEEC_MEMREF_PARTIAL_INPUT:
503         case TEEC_MEMREF_PARTIAL_OUTPUT:
504         case TEEC_MEMREF_PARTIAL_INOUT:
505                 return true;
506         default:
507                 dev_err(_DEV_TEE, "type is invalid (type %02x)\n", type);
508                 return false;
509         }
510 }
511
512 static int to_memref_type(int flags)
513 {
514         if (flag_set(flags, TEEC_MEM_INPUT | TEEC_MEM_OUTPUT))
515                 return TEEC_MEMREF_TEMP_INOUT;
516
517         if (flag_set(flags, TEEC_MEM_INPUT))
518                 return TEEC_MEMREF_TEMP_INPUT;
519
520         if (flag_set(flags, TEEC_MEM_OUTPUT))
521                 return TEEC_MEMREF_TEMP_OUTPUT;
522
523         pr_err("%s: bad flags=%x\n", __func__, flags);
524         return 0;
525 }
526
527 static int _init_tee_cmd(struct tee_session *sess, struct tee_cmd_io *cmd_io,
528                          struct tee_cmd *cmd)
529 {
530         int ret = -EINVAL;
531         int idx;
532         TEEC_Operation op;
533         struct tee_data *param = &cmd->param;
534         struct tee *tee;
535         struct tee_context *ctx;
536
537         BUG_ON(!sess->ctx);
538         BUG_ON(!sess->ctx->tee);
539         ctx = sess->ctx;
540         tee = sess->ctx->tee;
541
542         dev_dbg(_DEV(tee), "%s: > sessid=%08x\n", __func__, sess->sessid);
543
544         memset(cmd, 0, sizeof(struct tee_cmd));
545
546         cmd->cmd = cmd_io->cmd;
547         cmd->origin = TEEC_ORIGIN_TEE;
548         cmd->err = TEEC_ERROR_BAD_PARAMETERS;
549         cmd_io->origin = cmd->origin;
550         cmd_io->err = cmd->err;
551
552         if (tee_context_copy_from_client(ctx, &op, cmd_io->op, sizeof(op)))
553                 goto out;
554
555         cmd->param.type_original = op.paramTypes;
556
557         for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
558                 uint32_t offset = 0;
559                 uint32_t size = 0;
560                 int type = TEEC_PARAM_TYPE_GET(op.paramTypes, idx);
561
562                 switch (type) {
563                 case TEEC_NONE:
564                         break;
565
566                 case TEEC_VALUE_INPUT:
567                 case TEEC_VALUE_OUTPUT:
568                 case TEEC_VALUE_INOUT:
569                         param->params[idx].value = op.params[idx].value;
570                         dev_dbg(_DEV_TEE,
571                                 "%s: param[%d]:type=%d,a=%08x,b=%08x (VALUE)\n",
572                                 __func__, idx, type, param->params[idx].value.a,
573                                 param->params[idx].value.b);
574                         break;
575
576                 case TEEC_MEMREF_TEMP_INPUT:
577                 case TEEC_MEMREF_TEMP_OUTPUT:
578                 case TEEC_MEMREF_TEMP_INOUT:
579                         dev_dbg(_DEV_TEE,
580                                 "> param[%d]:type=%d,buffer=%p,s=%zu (TMPREF)\n",
581                                 idx, type, op.params[idx].tmpref.buffer,
582                                 op.params[idx].tmpref.size);
583
584                         param->params[idx].shm =
585                             tee_context_create_tmpref_buffer(ctx,
586                                              op.params[idx].tmpref.size,
587                                              op.params[idx].tmpref.buffer,
588                                              type);
589                         if (IS_ERR_OR_NULL(param->params[idx].shm))
590                                 goto out;
591
592                         dev_dbg(_DEV_TEE, "< %d %p:%zd\n", idx,
593                                         (void *)param->params[idx].shm->paddr,
594                                         param->params[idx].shm->size_alloc);
595                         break;
596
597                 case TEEC_MEMREF_PARTIAL_INPUT:
598                 case TEEC_MEMREF_PARTIAL_OUTPUT:
599                 case TEEC_MEMREF_PARTIAL_INOUT:
600                 case TEEC_MEMREF_WHOLE:
601                         if (tee_copy_from_user(ctx, &param->c_shm[idx],
602                                                 op.params[idx].memref.parent,
603                                                 sizeof(param->c_shm[idx]))) {
604                                 goto out;
605                         }
606
607                         if (type == TEEC_MEMREF_WHOLE) {
608                                 offset = 0;
609                                 size = param->c_shm[idx].size;
610                         } else { /* for PARTIAL, check the size */
611                                 offset = op.params[idx].memref.offset;
612                                 size = op.params[idx].memref.size;
613                                 if (param->c_shm[idx].size < size + offset) {
614                                         dev_err(_DEV(tee), "A PARTIAL parameter is bigger than the parent %zd < %d + %d\n",
615                                                 param->c_shm[idx].size, size,
616                                                 offset);
617                                         goto out;
618                                 }
619                         }
620
621                         dev_dbg(_DEV_TEE, "> param[%d]:type=%d,buffer=%p, offset=%d size=%d\n",
622                                         idx, type, param->c_shm[idx].buffer,
623                                         offset, size);
624
625                         type = to_memref_type(param->c_shm[idx].flags);
626                         if (type == 0)
627                                 goto out;
628
629                         param->params[idx].shm = tee_shm_get(ctx,
630                                         &param->c_shm[idx], size, offset);
631
632                         if (IS_ERR_OR_NULL(param->params[idx].shm)) {
633                                 param->params[idx].shm =
634                                     tee_context_create_tmpref_buffer(ctx, size,
635                                        param->c_shm[idx].buffer + offset, type);
636
637                                 if (IS_ERR_OR_NULL(param->params[idx].shm))
638                                         goto out;
639                         }
640
641                         dev_dbg(_DEV_TEE, "< %d %p:%zd\n", idx,
642                                 (void *)param->params[idx].shm->paddr,
643                                 param->params[idx].shm->size_req);
644                         break;
645
646                 default:
647                         BUG_ON(1);
648                 }
649
650                 param->type |= (type << (idx * 4));
651         }
652
653         if (cmd_io->uuid != NULL) {
654                 dev_dbg(_DEV_TEE, "%s: copy UUID value...\n", __func__);
655                 cmd->uuid = tee_context_alloc_shm_tmp(sess->ctx,
656                         sizeof(*cmd_io->uuid), cmd_io->uuid, TEEC_MEM_INPUT);
657                 if (IS_ERR_OR_NULL(cmd->uuid)) {
658                         ret = -EINVAL;
659                         goto out;
660                 }
661         }
662
663         ret = 0;
664
665 out:
666         if (ret)
667                 _release_tee_cmd(sess, cmd);
668
669         dev_dbg(_DEV_TEE, "%s: < ret=%d\n", __func__, ret);
670         return ret;
671 }
672
673 static void _update_client_tee_cmd(struct tee_session *sess,
674                                    struct tee_cmd_io *cmd_io,
675                                    struct tee_cmd *cmd)
676 {
677         int idx;
678         struct tee_context *ctx;
679
680         BUG_ON(!cmd_io);
681         BUG_ON(!cmd_io->op);
682         BUG_ON(!cmd_io->op->params);
683         BUG_ON(!cmd);
684         BUG_ON(!sess->ctx);
685         ctx = sess->ctx;
686
687         dev_dbg(_DEV_TEE, "%s: returned err=0x%08x (origin=%d)\n", __func__,
688                 cmd->err, cmd->origin);
689
690         cmd_io->origin = cmd->origin;
691         cmd_io->err = cmd->err;
692
693         if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
694                         TEEC_NONE, TEEC_NONE, TEEC_NONE))
695                 return;
696
697         for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
698                 int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
699                 int offset = 0;
700                 size_t size;
701                 size_t size_new;
702                 TEEC_SharedMemory *parent;
703
704                 dev_dbg(_DEV_TEE, "%s: id %d type %d\n", __func__, idx, type);
705                 BUG_ON(!tee_session_is_supported_type(sess, type));
706                 switch (type) {
707                 case TEEC_NONE:
708                 case TEEC_VALUE_INPUT:
709                 case TEEC_MEMREF_TEMP_INPUT:
710                 case TEEC_MEMREF_PARTIAL_INPUT:
711                         break;
712                 case TEEC_VALUE_OUTPUT:
713                 case TEEC_VALUE_INOUT:
714                         dev_dbg(_DEV_TEE, "%s: a=%08x, b=%08x\n",
715                                 __func__,
716                                 cmd->param.params[idx].value.a,
717                                 cmd->param.params[idx].value.b);
718                         if (tee_copy_to_user
719                             (ctx, &cmd_io->op->params[idx].value,
720                              &cmd->param.params[idx].value,
721                              sizeof(cmd_io->op->params[idx].value)))
722                                 dev_err(_DEV_TEE,
723                                         "%s:%d: can't update %d result to user\n",
724                                         __func__, __LINE__, idx);
725                         break;
726                 case TEEC_MEMREF_TEMP_OUTPUT:
727                 case TEEC_MEMREF_TEMP_INOUT:
728                         /* Returned updated size */
729                         size_new = cmd->param.params[idx].shm->size_req;
730                         if (size_new !=
731                                 cmd_io->op->params[idx].tmpref.size) {
732                                 dev_dbg(_DEV_TEE,
733                                         "Size has been updated by the TA %zd != %zd\n",
734                                         size_new,
735                                         cmd_io->op->params[idx].tmpref.size);
736                                 tee_put_user(ctx, size_new,
737                                      &cmd_io->op->params[idx].tmpref.size);
738                         }
739
740                         dev_dbg(_DEV_TEE, "%s: tmpref %p\n", __func__,
741                                 cmd->param.params[idx].shm->kaddr);
742
743                         /* ensure we do not exceed the shared buffer length */
744                         if (size_new > cmd_io->op->params[idx].tmpref.size)
745                                 dev_err(_DEV_TEE,
746                                         "  *** Wrong returned size from %d:%zd > %zd\n",
747                                         idx, size_new,
748                                         cmd_io->op->params[idx].tmpref.size);
749
750                         else if (tee_copy_to_user
751                                  (ctx,
752                                   cmd_io->op->params[idx].tmpref.buffer,
753                                   cmd->param.params[idx].shm->kaddr,
754                                   size_new))
755                                 dev_err(_DEV_TEE,
756                                         "%s:%d: can't update %d result to user\n",
757                                         __func__, __LINE__, idx);
758                         break;
759
760                 case TEEC_MEMREF_PARTIAL_OUTPUT:
761                 case TEEC_MEMREF_PARTIAL_INOUT:
762                 case TEEC_MEMREF_WHOLE:
763                         parent = &cmd->param.c_shm[idx];
764                         if (type == TEEC_MEMREF_WHOLE) {
765                                 offset = 0;
766                                 size = parent->size;
767                         } else {
768                                 offset = cmd_io->op->params[idx].memref.offset;
769                                 size = cmd_io->op->params[idx].memref.size;
770                         }
771
772                         /* Returned updated size */
773                         size_new = cmd->param.params[idx].shm->size_req;
774                         tee_put_user(ctx, size_new,
775                                         &cmd_io->op->params[idx].memref.size);
776
777                         /*
778                          * If we allocated a tmpref buffer,
779                          * copy back data to the user buffer
780                          */
781                         if (is_mapped_temp(cmd->param.params[idx].shm->flags)) {
782                                 if (parent->buffer &&
783                                         offset + size_new <= parent->size) {
784                                         if (tee_copy_to_user(ctx,
785                                            parent->buffer + offset,
786                                            cmd->param.params[idx].shm->kaddr,
787                                            size_new))
788                                                         dev_err(_DEV_TEE,
789                                                                 "%s: can't update %d data to user\n",
790                                                                 __func__, idx);
791                                 }
792                         }
793                         break;
794                 default:
795                         BUG_ON(1);
796                 }
797         }
798
799 }
800
801 static void _release_tee_cmd(struct tee_session *sess, struct tee_cmd *cmd)
802 {
803         int idx;
804         struct tee_context *ctx;
805
806         BUG_ON(!cmd);
807         BUG_ON(!sess);
808         BUG_ON(!sess->ctx);
809         BUG_ON(!sess->ctx->tee);
810
811         ctx = sess->ctx;
812
813         dev_dbg(_DEV_TEE, "%s: > free the temporary objects...\n", __func__);
814
815         tee_shm_free(cmd->uuid);
816
817         if (cmd->param.type_original == TEEC_PARAM_TYPES(TEEC_NONE,
818                         TEEC_NONE, TEEC_NONE, TEEC_NONE))
819                 goto out;
820
821         for (idx = 0; idx < TEEC_CONFIG_PAYLOAD_REF_COUNT; ++idx) {
822                 int type = TEEC_PARAM_TYPE_GET(cmd->param.type_original, idx);
823                 struct tee_shm *shm;
824                 switch (type) {
825                 case TEEC_NONE:
826                 case TEEC_VALUE_INPUT:
827                 case TEEC_VALUE_OUTPUT:
828                 case TEEC_VALUE_INOUT:
829                         break;
830                 case TEEC_MEMREF_TEMP_INPUT:
831                 case TEEC_MEMREF_TEMP_OUTPUT:
832                 case TEEC_MEMREF_TEMP_INOUT:
833                 case TEEC_MEMREF_WHOLE:
834                 case TEEC_MEMREF_PARTIAL_INPUT:
835                 case TEEC_MEMREF_PARTIAL_OUTPUT:
836                 case TEEC_MEMREF_PARTIAL_INOUT:
837                         if (IS_ERR_OR_NULL(cmd->param.params[idx].shm))
838                                 break;
839
840                         shm = cmd->param.params[idx].shm;
841
842                         if (is_mapped_temp(shm->flags))
843                                 tee_shm_free(shm);
844                         else
845                                 tee_shm_put(ctx, shm);
846                         break;
847                 default:
848                         BUG_ON(1);
849                 }
850         }
851
852 out:
853         memset(cmd, 0, sizeof(struct tee_cmd));
854         dev_dbg(_DEV_TEE, "%s: <\n", __func__);
855 }