Skip to content

Commit 146bf4e

Browse files
etienne-lmsjenswi-linaro
authored andcommitted
tee: new ioctl to a register tee_shm from a dmabuf file descriptor
Add a userspace API to create a tee_shm object that refers to a dmabuf reference. Userspace registers the dmabuf file descriptor as in a tee_shm object. The registration is completed with a tee_shm returned file descriptor. Userspace is free to close the dmabuf file descriptor after it has been registered since all the resources are now held via the new tee_shm object. Closing the tee_shm file descriptor will eventually release all resources used by the tee_shm object when all references are released. The new IOCTL, TEE_IOC_SHM_REGISTER_FD, supports dmabuf references to physically contiguous memory buffers. Dmabuf references acquired from the TEE DMA-heap can be used as protected memory for Secure Video Path and such use cases. It depends on the TEE and the TEE driver if dmabuf references acquired by other means can be used. A new tee_shm flag is added to identify tee_shm objects built from a registered dmabuf, TEE_SHM_DMA_BUF. Signed-off-by: Etienne Carriere <etienne.carriere@foss.st.com> Signed-off-by: Olivier Masse <olivier.masse@nxp.com> Reviewed-by: Sumit Garg <sumit.garg@oss.qualcomm.com> Signed-off-by: Jens Wiklander <jens.wiklander@linaro.org>
1 parent fdf631a commit 146bf4e

6 files changed

Lines changed: 182 additions & 4 deletions

File tree

drivers/tee/tee_core.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,11 +354,49 @@ tee_ioctl_shm_register(struct tee_context *ctx,
354354
return ret;
355355
}
356356

357+
static int
358+
tee_ioctl_shm_register_fd(struct tee_context *ctx,
359+
struct tee_ioctl_shm_register_fd_data __user *udata)
360+
{
361+
struct tee_ioctl_shm_register_fd_data data;
362+
struct tee_shm *shm;
363+
long ret;
364+
365+
if (copy_from_user(&data, udata, sizeof(data)))
366+
return -EFAULT;
367+
368+
/* Currently no input flags are supported */
369+
if (data.flags)
370+
return -EINVAL;
371+
372+
shm = tee_shm_register_fd(ctx, data.fd);
373+
if (IS_ERR(shm))
374+
return -EINVAL;
375+
376+
data.id = shm->id;
377+
data.flags = shm->flags;
378+
data.size = shm->size;
379+
380+
if (copy_to_user(udata, &data, sizeof(data)))
381+
ret = -EFAULT;
382+
else
383+
ret = tee_shm_get_fd(shm);
384+
385+
/*
386+
* When user space closes the file descriptor the shared memory
387+
* should be freed or if tee_shm_get_fd() failed then it will
388+
* be freed immediately.
389+
*/
390+
tee_shm_put(shm);
391+
return ret;
392+
}
393+
357394
static int param_from_user_memref(struct tee_context *ctx,
358395
struct tee_param_memref *memref,
359396
struct tee_ioctl_param *ip)
360397
{
361398
struct tee_shm *shm;
399+
size_t offs = 0;
362400

363401
/*
364402
* If a NULL pointer is passed to a TA in the TEE,
@@ -389,14 +427,34 @@ static int param_from_user_memref(struct tee_context *ctx,
389427
tee_shm_put(shm);
390428
return -EINVAL;
391429
}
430+
431+
if (shm->flags & TEE_SHM_DMA_BUF) {
432+
struct tee_shm_dmabuf_ref *ref;
433+
434+
ref = container_of(shm, struct tee_shm_dmabuf_ref, shm);
435+
if (ref->parent_shm) {
436+
/*
437+
* The shm already has one reference to
438+
* ref->parent_shm so we are clear of 0.
439+
* We're getting another reference since
440+
* this shm will be used in the parameter
441+
* list instead of the shm we got with
442+
* tee_shm_get_from_id() above.
443+
*/
444+
refcount_inc(&ref->parent_shm->refcount);
445+
tee_shm_put(shm);
446+
shm = ref->parent_shm;
447+
offs = ref->offset;
448+
}
449+
}
392450
} else if (ctx->cap_memref_null) {
393451
/* Pass NULL pointer to OP-TEE */
394452
shm = NULL;
395453
} else {
396454
return -EINVAL;
397455
}
398456

399-
memref->shm_offs = ip->a;
457+
memref->shm_offs = ip->a + offs;
400458
memref->size = ip->b;
401459
memref->shm = shm;
402460

@@ -842,6 +900,8 @@ static long tee_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
842900
return tee_ioctl_shm_alloc(ctx, uarg);
843901
case TEE_IOC_SHM_REGISTER:
844902
return tee_ioctl_shm_register(ctx, uarg);
903+
case TEE_IOC_SHM_REGISTER_FD:
904+
return tee_ioctl_shm_register_fd(ctx, uarg);
845905
case TEE_IOC_OPEN_SESSION:
846906
return tee_ioctl_open_session(ctx, uarg);
847907
case TEE_IOC_INVOKE:

drivers/tee/tee_private.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@
1313
#include <linux/mutex.h>
1414
#include <linux/types.h>
1515

16+
/* extra references appended to shm object for registered shared memory */
17+
struct tee_shm_dmabuf_ref {
18+
struct tee_shm shm;
19+
size_t offset;
20+
struct dma_buf *dmabuf;
21+
struct tee_shm *parent_shm;
22+
};
23+
1624
int tee_shm_get_fd(struct tee_shm *shm);
1725

1826
bool tee_device_get(struct tee_device *teedev);

drivers/tee/tee_shm.c

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
#include <linux/anon_inodes.h>
66
#include <linux/device.h>
7+
#include <linux/dma-buf.h>
78
#include <linux/idr.h>
89
#include <linux/io.h>
910
#include <linux/mm.h>
@@ -45,7 +46,15 @@ static void release_registered_pages(struct tee_shm *shm)
4546

4647
static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm)
4748
{
48-
if (shm->flags & TEE_SHM_POOL) {
49+
void *p = shm;
50+
51+
if (shm->flags & TEE_SHM_DMA_BUF) {
52+
struct tee_shm_dmabuf_ref *ref;
53+
54+
ref = container_of(shm, struct tee_shm_dmabuf_ref, shm);
55+
p = ref;
56+
dma_buf_put(ref->dmabuf);
57+
} else if (shm->flags & TEE_SHM_POOL) {
4958
teedev->pool->ops->free(teedev->pool, shm);
5059
} else if (shm->flags & TEE_SHM_DYNAMIC) {
5160
int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm);
@@ -59,7 +68,7 @@ static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm)
5968

6069
teedev_ctx_put(shm->ctx);
6170

62-
kfree(shm);
71+
kfree(p);
6372

6473
tee_device_put(teedev);
6574
}
@@ -169,7 +178,7 @@ struct tee_shm *tee_shm_alloc_user_buf(struct tee_context *ctx, size_t size)
169178
* tee_client_invoke_func(). The memory allocated is later freed with a
170179
* call to tee_shm_free().
171180
*
172-
* @returns a pointer to 'struct tee_shm'
181+
* @returns a pointer to 'struct tee_shm' on success, and ERR_PTR on failure
173182
*/
174183
struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size)
175184
{
@@ -179,6 +188,62 @@ struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size)
179188
}
180189
EXPORT_SYMBOL_GPL(tee_shm_alloc_kernel_buf);
181190

191+
struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd)
192+
{
193+
struct tee_shm_dmabuf_ref *ref;
194+
int rc;
195+
196+
if (!tee_device_get(ctx->teedev))
197+
return ERR_PTR(-EINVAL);
198+
199+
teedev_ctx_get(ctx);
200+
201+
ref = kzalloc(sizeof(*ref), GFP_KERNEL);
202+
if (!ref) {
203+
rc = -ENOMEM;
204+
goto err_put_tee;
205+
}
206+
207+
refcount_set(&ref->shm.refcount, 1);
208+
ref->shm.ctx = ctx;
209+
ref->shm.id = -1;
210+
ref->shm.flags = TEE_SHM_DMA_BUF;
211+
212+
ref->dmabuf = dma_buf_get(fd);
213+
if (IS_ERR(ref->dmabuf)) {
214+
rc = PTR_ERR(ref->dmabuf);
215+
goto err_kfree_ref;
216+
}
217+
218+
rc = tee_heap_update_from_dma_buf(ctx->teedev, ref->dmabuf,
219+
&ref->offset, &ref->shm,
220+
&ref->parent_shm);
221+
if (rc)
222+
goto err_put_dmabuf;
223+
224+
mutex_lock(&ref->shm.ctx->teedev->mutex);
225+
ref->shm.id = idr_alloc(&ref->shm.ctx->teedev->idr, &ref->shm,
226+
1, 0, GFP_KERNEL);
227+
mutex_unlock(&ref->shm.ctx->teedev->mutex);
228+
if (ref->shm.id < 0) {
229+
rc = ref->shm.id;
230+
goto err_put_dmabuf;
231+
}
232+
233+
return &ref->shm;
234+
235+
err_put_dmabuf:
236+
dma_buf_put(ref->dmabuf);
237+
err_kfree_ref:
238+
kfree(ref);
239+
err_put_tee:
240+
teedev_ctx_put(ctx);
241+
tee_device_put(ctx->teedev);
242+
243+
return ERR_PTR(rc);
244+
}
245+
EXPORT_SYMBOL_GPL(tee_shm_register_fd);
246+
182247
/**
183248
* tee_shm_alloc_priv_buf() - Allocate shared memory for a privately shared
184249
* kernel buffer
@@ -442,6 +507,9 @@ static int tee_shm_fop_mmap(struct file *filp, struct vm_area_struct *vma)
442507
/* Refuse sharing shared memory provided by application */
443508
if (shm->flags & TEE_SHM_USER_MAPPED)
444509
return -EINVAL;
510+
/* Refuse sharing registered DMA_bufs with the application */
511+
if (shm->flags & TEE_SHM_DMA_BUF)
512+
return -EINVAL;
445513

446514
/* check for overflowing the buffer's size */
447515
if (vma->vm_pgoff + vma_pages(vma) > shm->size >> PAGE_SHIFT)

include/linux/tee_core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define TEE_SHM_USER_MAPPED BIT(1) /* Memory mapped in user space */
2929
#define TEE_SHM_POOL BIT(2) /* Memory allocated from pool */
3030
#define TEE_SHM_PRIV BIT(3) /* Memory private to TEE driver */
31+
#define TEE_SHM_DMA_BUF BIT(4) /* Memory with dma-buf handle */
3132

3233
#define TEE_DEVICE_FLAG_REGISTERED 0x1
3334
#define TEE_MAX_DEV_NAME_LEN 32

include/linux/tee_drv.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,16 @@ struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size);
116116
struct tee_shm *tee_shm_register_kernel_buf(struct tee_context *ctx,
117117
void *addr, size_t length);
118118

119+
/**
120+
* tee_shm_register_fd() - Register shared memory from file descriptor
121+
*
122+
* @ctx: Context that allocates the shared memory
123+
* @fd: Shared memory file descriptor reference
124+
*
125+
* @returns a pointer to 'struct tee_shm' on success, and ERR_PTR on failure
126+
*/
127+
struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd);
128+
119129
/**
120130
* tee_shm_free() - Free shared memory
121131
* @shm: Handle to shared memory to free

include/uapi/linux/tee.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,37 @@ struct tee_ioctl_shm_register_data {
378378
__s32 id;
379379
};
380380

381+
/**
382+
* struct tee_ioctl_shm_register_fd_data - Shared memory registering argument
383+
* @fd: [in] File descriptor identifying dmabuf reference
384+
* @size: [out] Size of referenced memory
385+
* @flags: [in] Flags to/from allocation.
386+
* @id: [out] Identifier of the shared memory
387+
*
388+
* The flags field should currently be zero as input. Updated by the call
389+
* with actual flags as defined by TEE_IOCTL_SHM_* above.
390+
* This structure is used as argument for TEE_IOC_SHM_REGISTER_FD below.
391+
*/
392+
struct tee_ioctl_shm_register_fd_data {
393+
__s64 fd;
394+
__u64 size;
395+
__u32 flags;
396+
__s32 id;
397+
};
398+
399+
/**
400+
* TEE_IOC_SHM_REGISTER_FD - register a shared memory from a file descriptor
401+
*
402+
* Returns a file descriptor on success or < 0 on failure
403+
*
404+
* The returned file descriptor refers to the shared memory object in the
405+
* kernel. The supplied file deccriptor can be closed if it's not needed
406+
* for other purposes. The shared memory is freed when the descriptor is
407+
* closed.
408+
*/
409+
#define TEE_IOC_SHM_REGISTER_FD _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 8, \
410+
struct tee_ioctl_shm_register_fd_data)
411+
381412
/**
382413
* TEE_IOC_SHM_REGISTER - Register shared memory argument
383414
*

0 commit comments

Comments
 (0)