Merge branch 'linus' into sched/urgent, to resolve conflicts
[linux-2.6-block.git] / drivers / tee / tee_core.c
index 4d0ce606f0fcb368a473103f01d541b44d1fe772..6c4b200a45604827517ff1b840ba642ab2beb165 100644 (file)
@@ -54,6 +54,7 @@ static int tee_open(struct inode *inode, struct file *filp)
                goto err;
        }
 
+       kref_init(&ctx->refcount);
        ctx->teedev = teedev;
        INIT_LIST_HEAD(&ctx->list_shm);
        filp->private_data = ctx;
@@ -68,19 +69,40 @@ err:
        return rc;
 }
 
-static int tee_release(struct inode *inode, struct file *filp)
+void teedev_ctx_get(struct tee_context *ctx)
 {
-       struct tee_context *ctx = filp->private_data;
-       struct tee_device *teedev = ctx->teedev;
-       struct tee_shm *shm;
+       if (ctx->releasing)
+               return;
 
+       kref_get(&ctx->refcount);
+}
+
+static void teedev_ctx_release(struct kref *ref)
+{
+       struct tee_context *ctx = container_of(ref, struct tee_context,
+                                              refcount);
+       ctx->releasing = true;
        ctx->teedev->desc->ops->release(ctx);
-       mutex_lock(&ctx->teedev->mutex);
-       list_for_each_entry(shm, &ctx->list_shm, link)
-               shm->ctx = NULL;
-       mutex_unlock(&ctx->teedev->mutex);
        kfree(ctx);
-       tee_device_put(teedev);
+}
+
+void teedev_ctx_put(struct tee_context *ctx)
+{
+       if (ctx->releasing)
+               return;
+
+       kref_put(&ctx->refcount, teedev_ctx_release);
+}
+
+static void teedev_close_context(struct tee_context *ctx)
+{
+       tee_device_put(ctx->teedev);
+       teedev_ctx_put(ctx);
+}
+
+static int tee_release(struct inode *inode, struct file *filp)
+{
+       teedev_close_context(filp->private_data);
        return 0;
 }
 
@@ -114,8 +136,6 @@ static int tee_ioctl_shm_alloc(struct tee_context *ctx,
        if (data.flags)
                return -EINVAL;
 
-       data.id = -1;
-
        shm = tee_shm_alloc(ctx, data.size, TEE_SHM_MAPPED | TEE_SHM_DMA_BUF);
        if (IS_ERR(shm))
                return PTR_ERR(shm);
@@ -138,6 +158,43 @@ static int tee_ioctl_shm_alloc(struct tee_context *ctx,
        return ret;
 }
 
+static int
+tee_ioctl_shm_register(struct tee_context *ctx,
+                      struct tee_ioctl_shm_register_data __user *udata)
+{
+       long ret;
+       struct tee_ioctl_shm_register_data data;
+       struct tee_shm *shm;
+
+       if (copy_from_user(&data, udata, sizeof(data)))
+               return -EFAULT;
+
+       /* Currently no input flags are supported */
+       if (data.flags)
+               return -EINVAL;
+
+       shm = tee_shm_register(ctx, data.addr, data.length,
+                              TEE_SHM_DMA_BUF | TEE_SHM_USER_MAPPED);
+       if (IS_ERR(shm))
+               return PTR_ERR(shm);
+
+       data.id = shm->id;
+       data.flags = shm->flags;
+       data.length = shm->size;
+
+       if (copy_to_user(udata, &data, sizeof(data)))
+               ret = -EFAULT;
+       else
+               ret = tee_shm_get_fd(shm);
+       /*
+        * When user space closes the file descriptor the shared memory
+        * should be freed or if tee_shm_get_fd() failed then it will
+        * be freed immediately.
+        */
+       tee_shm_put(shm);
+       return ret;
+}
+
 static int params_from_user(struct tee_context *ctx, struct tee_param *params,
                            size_t num_params,
                            struct tee_ioctl_param __user *uparams)
@@ -578,6 +635,8 @@ static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                return tee_ioctl_version(ctx, uarg);
        case TEE_IOC_SHM_ALLOC:
                return tee_ioctl_shm_alloc(ctx, uarg);
+       case TEE_IOC_SHM_REGISTER:
+               return tee_ioctl_shm_register(ctx, uarg);
        case TEE_IOC_OPEN_SESSION:
                return tee_ioctl_open_session(ctx, uarg);
        case TEE_IOC_INVOKE: