2 * Copyright (c) 2014, STMicroelectronics International N.V.
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.
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.
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>
22 #include "tee_core_priv.h"
26 * tee_context_dump - Dump in a buffer the informations (ctx, sess & shm)
27 * associated to a tee.
29 int tee_context_dump(struct tee *tee, char *buff, size_t len)
31 struct list_head *ptr_ctx, *ptr_sess, *ptr_shm;
32 struct tee_context *ctx;
33 struct tee_session *sess;
42 if (len < 80 || list_empty(&tee->list_ctx))
45 mutex_lock(&tee->lock);
47 list_for_each(ptr_ctx, &tee->list_ctx) {
48 ctx = list_entry(ptr_ctx, struct tee_context, entry);
50 pos += sprintf(buff + pos,
51 "[%02d] ctx=%p (refcount=%d) (usr=%d)",
53 (int)atomic_read(&ctx->refcount.
56 pos += sprintf(buff + pos, "name=\"%s\" (tgid=%d)\n",
59 if ((len - pos) < 80) {
64 if (list_empty(&ctx->list_sess))
68 list_for_each(ptr_sess, &ctx->list_sess) {
69 sess = list_entry(ptr_sess,
73 pos += sprintf(buff + pos,
74 "[%02d.%d] sess=%p sessid=%08x\n",
78 if ((len - pos) < 80) {
86 if (list_empty(&ctx->list_shm))
90 list_for_each(ptr_shm, &ctx->list_shm) {
91 shm = list_entry(ptr_shm, struct tee_shm, entry);
93 pos += sprintf(buff + pos,
94 "[%02d.%d] shm=%p paddr=%p kaddr=%p",
98 pos += sprintf(buff + pos,
102 if ((len - pos) < 80) {
114 mutex_unlock(&tee->lock);
119 * tee_context_create - Allocate and create a new context.
120 * Reference on the back-end is requested.
122 struct tee_context *tee_context_create(struct tee *tee)
125 struct tee_context *ctx;
127 dev_dbg(_DEV(tee), "%s: >\n", __func__);
129 ctx = devm_kzalloc(_DEV(tee), sizeof(struct tee_context), GFP_KERNEL);
131 dev_err(_DEV(tee), "%s: tee_context allocation failed\n",
133 return ERR_PTR(-ENOMEM);
136 kref_init(&ctx->refcount);
137 INIT_LIST_HEAD(&ctx->list_sess);
138 INIT_LIST_HEAD(&ctx->list_shm);
141 snprintf(ctx->name, sizeof(ctx->name), "%s", current->comm);
142 ctx->tgid = current->tgid;
146 devm_kfree(_DEV(tee), ctx);
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);
155 dev_dbg(_DEV(ctx->tee), "%s: < ctx=%p is created\n", __func__, ctx);
160 * _tee_context_do_release - Final function to release
161 * and free a context.
163 static void _tee_context_do_release(struct kref *kref)
165 struct tee_context *ctx;
168 ctx = container_of(kref, struct tee_context, refcount);
170 BUG_ON(!ctx || !ctx->tee);
174 dev_dbg(_DEV(tee), "%s: > ctx=%p\n", __func__, ctx);
176 tee_dec_stats(&tee->stats[TEE_STATS_CONTEXT_IDX]);
177 list_del(&ctx->entry);
179 devm_kfree(_DEV(tee), ctx);
182 dev_dbg(_DEV(tee), "%s: < ctx=%p is destroyed\n", __func__, ctx);
186 * tee_context_get - Increase the reference count of
189 void tee_context_get(struct tee_context *ctx)
191 BUG_ON(!ctx || !ctx->tee);
193 kref_get(&ctx->refcount);
195 dev_dbg(_DEV(ctx->tee), "%s: ctx=%p, kref=%d\n", __func__,
196 ctx, (int)atomic_read(&ctx->refcount.refcount));
199 static int is_in_list(struct tee *tee, struct list_head *entry)
203 if ((entry->next == LIST_POISON1) && (entry->prev == LIST_POISON2))
209 * tee_context_put - Decreases the reference count of
210 * the context. If 0, the final
211 * release function is called.
213 void tee_context_put(struct tee_context *ctx)
215 struct tee_context *_ctx = ctx;
218 BUG_ON(!ctx || !ctx->tee);
221 if (!is_in_list(tee, &ctx->entry))
224 kref_put(&ctx->refcount, _tee_context_do_release);
226 dev_dbg(_DEV(tee), "%s: ctx=%p, kref=%d\n", __func__,
227 _ctx, (int)atomic_read(&ctx->refcount.refcount));
231 * tee_context_destroy - Request to destroy a context.
233 void tee_context_destroy(struct tee_context *ctx)
237 if (!ctx || !ctx->tee)
242 dev_dbg(_DEV(tee), "%s: ctx=%p\n", __func__, ctx);
244 mutex_lock(&tee->lock);
245 tee_context_put(ctx);
246 mutex_unlock(&tee->lock);
249 int tee_context_copy_from_client(const struct tee_context *ctx,
250 void *dest, const void *src, size_t size)
254 if (dest && src && (size > 0)) {
256 res = copy_from_user(dest, src, size);
258 memcpy(dest, src, size);
263 struct tee_shm *tee_context_alloc_shm_tmp(struct tee_context *ctx,
264 size_t size, const void *src,
269 type &= (TEEC_MEM_INPUT | TEEC_MEM_OUTPUT);
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));
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",
293 struct tee_shm *tee_context_create_tmpref_buffer(struct tee_context *ctx,
295 const void *buffer, int type)
297 struct tee_shm *shm = NULL;
301 case TEEC_MEMREF_TEMP_OUTPUT:
302 flags = TEEC_MEM_OUTPUT;
304 case TEEC_MEMREF_TEMP_INPUT:
305 flags = TEEC_MEM_INPUT;
307 case TEEC_MEMREF_TEMP_INOUT:
308 flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
313 shm = tee_context_alloc_shm_tmp(ctx, size, buffer, flags);