Merge tag 'v4.4-rc6'
[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         mutex_lock(&tee->lock);
177         tee_dec_stats(&tee->stats[TEE_STATS_CONTEXT_IDX]);
178         list_del(&ctx->entry);
179         mutex_unlock(&tee->lock);
180
181         devm_kfree(_DEV(tee), ctx);
182         tee_put(tee);
183
184         dev_dbg(_DEV(tee), "%s: < ctx=%p is destroyed\n", __func__, ctx);
185 }
186
187 /**
188  * tee_context_get - Increase the reference count of
189  *                   the context.
190  */
191 void tee_context_get(struct tee_context *ctx)
192 {
193         BUG_ON(!ctx || !ctx->tee);
194
195         kref_get(&ctx->refcount);
196
197         dev_dbg(_DEV(ctx->tee), "%s: ctx=%p, kref=%d\n", __func__,
198                 ctx, (int)atomic_read(&ctx->refcount.refcount));
199 }
200
201 static int is_in_list(struct tee *tee, struct list_head *entry)
202 {
203         int present = 1;
204
205         mutex_lock(&tee->lock);
206         if ((entry->next == LIST_POISON1) && (entry->prev == LIST_POISON2))
207                 present = 0;
208         mutex_unlock(&tee->lock);
209         return present;
210 }
211
212 /**
213  * tee_context_put - Decreases the reference count of
214  *                   the context. If 0, the final
215  *                   release function is called.
216  */
217 void tee_context_put(struct tee_context *ctx)
218 {
219         struct tee_context *_ctx = ctx;
220         struct tee *tee;
221
222         BUG_ON(!ctx || !ctx->tee);
223         tee = ctx->tee;
224
225         if (!is_in_list(tee, &ctx->entry))
226                 return;
227
228         kref_put(&ctx->refcount, _tee_context_do_release);
229
230         dev_dbg(_DEV(tee), "%s: ctx=%p, kref=%d\n", __func__,
231                 _ctx, (int)atomic_read(&ctx->refcount.refcount));
232 }
233
234 /**
235  * tee_context_destroy - Request to destroy a context.
236  */
237 void tee_context_destroy(struct tee_context *ctx)
238 {
239         struct tee *tee;
240
241         if (!ctx || !ctx->tee)
242                 return;
243
244         tee = ctx->tee;
245
246         dev_dbg(_DEV(tee), "%s: ctx=%p\n", __func__, ctx);
247
248         tee_context_put(ctx);
249 }
250
251 int tee_context_copy_from_client(const struct tee_context *ctx,
252                                  void *dest, const void *src, size_t size)
253 {
254         int res = 0;
255
256         if (dest && src && (size > 0)) {
257                 if (ctx->usr_client)
258                         res = copy_from_user(dest, src, size);
259                 else
260                         memcpy(dest, src, size);
261         }
262         return res;
263 }
264
265 struct tee_shm *tee_context_alloc_shm_tmp(struct tee_context *ctx,
266                                           size_t size, const void *src,
267                                           int type)
268 {
269         struct tee_shm *shm;
270
271         type &= (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT);
272
273         shm = tee_shm_alloc(ctx->tee, size,
274                         TEE_SHM_MAPPED | TEE_SHM_TEMP | type);
275         if (IS_ERR_OR_NULL(shm)) {
276                 dev_err(_DEV(ctx->tee), "%s: buffer allocation failed (%ld)\n",
277                         __func__, PTR_ERR(shm));
278                 return shm;
279         }
280
281         shm->ctx = ctx;
282
283         if (type & TEEC_MEM_INPUT) {
284                 if (tee_context_copy_from_client(ctx, shm->kaddr, src, size)) {
285                         dev_err(_DEV(ctx->tee),
286                                 "%s: tee_context_copy_from_client failed\n",
287                                 __func__);
288                         tee_shm_free(shm);
289                         shm = NULL;
290                 }
291         }
292         return shm;
293 }
294
295 struct tee_shm *tee_context_create_tmpref_buffer(struct tee_context *ctx,
296                                                  size_t size,
297                                                  const void *buffer, int type)
298 {
299         struct tee_shm *shm = NULL;
300         int flags;
301
302         switch (type) {
303         case TEEC_MEMREF_TEMP_OUTPUT:
304                 flags = TEEC_MEM_OUTPUT;
305                 break;
306         case TEEC_MEMREF_TEMP_INPUT:
307                 flags = TEEC_MEM_INPUT;
308                 break;
309         case TEEC_MEMREF_TEMP_INOUT:
310                 flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
311                 break;
312         default:
313                 BUG_ON(1);
314         };
315         shm = tee_context_alloc_shm_tmp(ctx, size, buffer, flags);
316         return shm;
317 }