OP-TEE: update optee_linuxdriver to match updated optee_os & optee_client
[firefly-linux-kernel-4.4.55.git] / security / optee_linuxdriver / core / tee_context.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/sched.h>
20
21 #include "tee_shm.h"
22 #include "tee_core_priv.h"
23
24
25 /**
26  * tee_context_dump -   Dump in a buffer the informations (ctx, sess & shm)
27  *                      associated to a tee.
28  */
29 int tee_context_dump(struct tee *tee, char *buff, size_t len)
30 {
31         struct list_head *ptr_ctx, *ptr_sess, *ptr_shm;
32         struct tee_context *ctx;
33         struct tee_session *sess;
34         struct tee_shm *shm;
35         int i = 0;
36         int j = 0;
37
38         int pos = 0;
39
40         BUG_ON(!tee);
41
42         if (len < 80 || list_empty(&tee->list_ctx))
43                 return 0;
44
45         mutex_lock(&tee->lock);
46
47         list_for_each(ptr_ctx, &tee->list_ctx) {
48                 ctx = list_entry(ptr_ctx, struct tee_context, entry);
49
50                 pos += sprintf(buff + pos,
51                                 "[%02d] ctx=%p (refcount=%d) (usr=%d)",
52                                 i, ctx,
53                                 (int)atomic_read(&ctx->refcount.
54                                         refcount),
55                                 ctx->usr_client);
56                 pos += sprintf(buff + pos, "name=\"%s\" (tgid=%d)\n",
57                                 ctx->name,
58                                 ctx->tgid);
59                 if ((len - pos) < 80) {
60                         pos = 0;
61                         goto out;
62                 }
63
64                 if (list_empty(&ctx->list_sess))
65                         goto out;
66
67                 j = 0;
68                 list_for_each(ptr_sess, &ctx->list_sess) {
69                         sess = list_entry(ptr_sess,
70                                         struct tee_session,
71                                         entry);
72
73                         pos += sprintf(buff + pos,
74                                         "[%02d.%d] sess=%p sessid=%08x\n",
75                                         i, j, sess,
76                                         sess->sessid);
77
78                         if ((len - pos) < 80) {
79                                 pos = 0;
80                                 goto out;
81                         }
82
83                         j++;
84                 }
85
86                 if (list_empty(&ctx->list_shm))
87                         goto out;
88
89                 j = 0;
90                 list_for_each(ptr_shm, &ctx->list_shm) {
91                         shm = list_entry(ptr_shm, struct tee_shm, entry);
92
93                         pos += sprintf(buff + pos,
94                                         "[%02d.%d] shm=%p paddr=%p kaddr=%p",
95                                         i, j, shm,
96                                         &shm->paddr,
97                                         shm->kaddr);
98                         pos += sprintf(buff + pos,
99                                         " s=%zu(%zu)\n",
100                                         shm->size_req,
101                                         shm->size_alloc);
102                         if ((len - pos) < 80) {
103                                 pos = 0;
104                                 goto out;
105                         }
106
107                         j++;
108                 }
109
110                 i++;
111         }
112
113 out:
114         mutex_unlock(&tee->lock);
115         return pos;
116 }
117
118 /**
119  * tee_context_create - Allocate and create a new context.
120  *                      Reference on the back-end is requested.
121  */
122 struct tee_context *tee_context_create(struct tee *tee)
123 {
124         int ret;
125         struct tee_context *ctx;
126
127         dev_dbg(_DEV(tee), "%s: >\n", __func__);
128
129         ctx = devm_kzalloc(_DEV(tee), sizeof(struct tee_context), GFP_KERNEL);
130         if (!ctx) {
131                 dev_err(_DEV(tee), "%s: tee_context allocation failed\n",
132                         __func__);
133                 return ERR_PTR(-ENOMEM);
134         }
135
136         kref_init(&ctx->refcount);
137         INIT_LIST_HEAD(&ctx->list_sess);
138         INIT_LIST_HEAD(&ctx->list_shm);
139
140         ctx->tee = tee;
141         snprintf(ctx->name, sizeof(ctx->name), "%s", current->comm);
142         ctx->tgid = current->tgid;
143
144         ret = tee_get(tee);
145         if (ret) {
146                 devm_kfree(_DEV(tee), ctx);
147                 return ERR_PTR(ret);
148         }
149
150         mutex_lock(&tee->lock);
151         tee_inc_stats(&tee->stats[TEE_STATS_CONTEXT_IDX]);
152         list_add_tail(&ctx->entry, &tee->list_ctx);
153         mutex_unlock(&tee->lock);
154
155         dev_dbg(_DEV(ctx->tee), "%s: < ctx=%p is created\n", __func__, ctx);
156         return ctx;
157 }
158
159 /**
160  * _tee_context_do_release - Final function to release
161  *                           and free a context.
162  */
163 static void _tee_context_do_release(struct kref *kref)
164 {
165         struct tee_context *ctx;
166         struct tee *tee;
167
168         ctx = container_of(kref, struct tee_context, refcount);
169
170         BUG_ON(!ctx || !ctx->tee);
171
172         tee = ctx->tee;
173
174         dev_dbg(_DEV(tee), "%s: > ctx=%p\n", __func__, ctx);
175
176         tee_dec_stats(&tee->stats[TEE_STATS_CONTEXT_IDX]);
177         list_del(&ctx->entry);
178
179         devm_kfree(_DEV(tee), ctx);
180         tee_put(tee);
181
182         dev_dbg(_DEV(tee), "%s: < ctx=%p is destroyed\n", __func__, ctx);
183 }
184
185 /**
186  * tee_context_get - Increase the reference count of
187  *                   the context.
188  */
189 void tee_context_get(struct tee_context *ctx)
190 {
191         BUG_ON(!ctx || !ctx->tee);
192
193         kref_get(&ctx->refcount);
194
195         dev_dbg(_DEV(ctx->tee), "%s: ctx=%p, kref=%d\n", __func__,
196                 ctx, (int)atomic_read(&ctx->refcount.refcount));
197 }
198
199 static int is_in_list(struct tee *tee, struct list_head *entry)
200 {
201         int present = 1;
202
203         if ((entry->next == LIST_POISON1) && (entry->prev == LIST_POISON2))
204                 present = 0;
205         return present;
206 }
207
208 /**
209  * tee_context_put - Decreases the reference count of
210  *                   the context. If 0, the final
211  *                   release function is called.
212  */
213 void tee_context_put(struct tee_context *ctx)
214 {
215         struct tee_context *_ctx = ctx;
216         struct tee *tee;
217
218         BUG_ON(!ctx || !ctx->tee);
219         tee = ctx->tee;
220
221         if (!is_in_list(tee, &ctx->entry))
222                 return;
223
224         kref_put(&ctx->refcount, _tee_context_do_release);
225
226         dev_dbg(_DEV(tee), "%s: ctx=%p, kref=%d\n", __func__,
227                 _ctx, (int)atomic_read(&ctx->refcount.refcount));
228 }
229
230 /**
231  * tee_context_destroy - Request to destroy a context.
232  */
233 void tee_context_destroy(struct tee_context *ctx)
234 {
235         struct tee *tee;
236
237         if (!ctx || !ctx->tee)
238                 return;
239
240         tee = ctx->tee;
241
242         dev_dbg(_DEV(tee), "%s: ctx=%p\n", __func__, ctx);
243
244         mutex_lock(&tee->lock);
245         tee_context_put(ctx);
246         mutex_unlock(&tee->lock);
247 }
248
249 int tee_context_copy_from_client(const struct tee_context *ctx,
250                                  void *dest, const void *src, size_t size)
251 {
252         int res = 0;
253
254         if (dest && src && (size > 0)) {
255                 if (ctx->usr_client)
256                         res = copy_from_user(dest, src, size);
257                 else
258                         memcpy(dest, src, size);
259         }
260         return res;
261 }
262
263 struct tee_shm *tee_context_alloc_shm_tmp(struct tee_context *ctx,
264                                           size_t size, const void *src,
265                                           int type)
266 {
267         struct tee_shm *shm;
268
269         type &= (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT);
270
271         shm = tee_shm_alloc(ctx->tee, size,
272                         TEE_SHM_MAPPED | TEE_SHM_TEMP | type);
273         if (IS_ERR_OR_NULL(shm)) {
274                 dev_err(_DEV(ctx->tee), "%s: buffer allocation failed (%ld)\n",
275                         __func__, PTR_ERR(shm));
276                 return shm;
277         }
278
279         shm->ctx = ctx;
280
281         if (type & TEEC_MEM_INPUT) {
282                 if (tee_context_copy_from_client(ctx, shm->kaddr, src, size)) {
283                         dev_err(_DEV(ctx->tee),
284                                 "%s: tee_context_copy_from_client failed\n",
285                                 __func__);
286                         tee_shm_free(shm);
287                         shm = NULL;
288                 }
289         }
290         return shm;
291 }
292
293 struct tee_shm *tee_context_create_tmpref_buffer(struct tee_context *ctx,
294                                                  size_t size,
295                                                  const void *buffer, int type)
296 {
297         struct tee_shm *shm = NULL;
298         int flags;
299
300         switch (type) {
301         case TEEC_MEMREF_TEMP_OUTPUT:
302                 flags = TEEC_MEM_OUTPUT;
303                 break;
304         case TEEC_MEMREF_TEMP_INPUT:
305                 flags = TEEC_MEM_INPUT;
306                 break;
307         case TEEC_MEMREF_TEMP_INOUT:
308                 flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
309                 break;
310         default:
311                 BUG_ON(1);
312         };
313         shm = tee_context_alloc_shm_tmp(ctx, size, buffer, flags);
314         return shm;
315 }