summaryrefslogtreecommitdiffstats
path: root/drivers/tee/tee_shm_pool.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2017-12-21 17:23:52 +0100
committerArnd Bergmann <arnd@arndb.de>2017-12-21 17:23:52 +0100
commitbad19e0d0460564a067f901b6848c0cc0c403c52 (patch)
treea18b9f2796aee7ce366108e684c12b5fe9d95f89 /drivers/tee/tee_shm_pool.c
parentMerge tag 'gpmc-omap-for-v4.16-immutable' of https://github.com/rogerq/linux ... (diff)
parenttee: shm: inline tee_shm_get_id() (diff)
downloadlinux-bad19e0d0460564a067f901b6848c0cc0c403c52.tar.xz
linux-bad19e0d0460564a067f901b6848c0cc0c403c52.zip
Merge tag 'tee-drv-dynamic-shm-for-v4.16' of https://git.linaro.org/people/jens.wiklander/linux-tee into next/drivers
Pull "tee dynamic shm for v4.16" from Jens Wiklander: This pull request enables dynamic shared memory support in the TEE subsystem as a whole and in OP-TEE in particular. Global Platform TEE specification [1] allows client applications to register part of own memory as a shared buffer between application and TEE. This allows fast zero-copy communication between TEE and REE. But current implementation of TEE in Linux does not support this feature. Also, current implementation of OP-TEE transport uses fixed size pre-shared buffer for all communications with OP-TEE OS. This is okay in the most use cases. But this prevents use of OP-TEE in virtualized environments, because: a) We can't share the same buffer between different virtual machines b) Physically contiguous memory as seen by VM can be non-contiguous in reality (and as seen by OP-TEE OS) due to second stage of MMU translation. c) Size of this pre-shared buffer is limited. So, first part of this pull request adds generic register/unregister interface to tee subsystem. The second part adds necessary features into OP-TEE driver, so it can use not only static pre-shared buffer, but whole RAM to communicate with OP-TEE OS. This change is backwards compatible allowing older secure world or user space to work with newer kernels and vice versa. [1] https://www.globalplatform.org/specificationsdevice.asp * tag 'tee-drv-dynamic-shm-for-v4.16' of https://git.linaro.org/people/jens.wiklander/linux-tee: tee: shm: inline tee_shm_get_id() tee: use reference counting for tee_context tee: optee: enable dynamic SHM support tee: optee: add optee-specific shared pool implementation tee: optee: store OP-TEE capabilities in private data tee: optee: add registered buffers handling into RPC calls tee: optee: add registered shared parameters handling tee: optee: add shared buffer registration functions tee: optee: add page list manipulation functions tee: optee: Update protocol definitions tee: shm: add page accessor functions tee: shm: add accessors for buffer size and page offset tee: add register user memory tee: flexible shared memory pool creation
Diffstat (limited to 'drivers/tee/tee_shm_pool.c')
-rw-r--r--drivers/tee/tee_shm_pool.c165
1 files changed, 102 insertions, 63 deletions
diff --git a/drivers/tee/tee_shm_pool.c b/drivers/tee/tee_shm_pool.c
index fb4f8522a526..e6d4b9e4a864 100644
--- a/drivers/tee/tee_shm_pool.c
+++ b/drivers/tee/tee_shm_pool.c
@@ -44,49 +44,18 @@ static void pool_op_gen_free(struct tee_shm_pool_mgr *poolm,
shm->kaddr = NULL;
}
+static void pool_op_gen_destroy_poolmgr(struct tee_shm_pool_mgr *poolm)
+{
+ gen_pool_destroy(poolm->private_data);
+ kfree(poolm);
+}
+
static const struct tee_shm_pool_mgr_ops pool_ops_generic = {
.alloc = pool_op_gen_alloc,
.free = pool_op_gen_free,
+ .destroy_poolmgr = pool_op_gen_destroy_poolmgr,
};
-static void pool_res_mem_destroy(struct tee_shm_pool *pool)
-{
- gen_pool_destroy(pool->private_mgr.private_data);
- gen_pool_destroy(pool->dma_buf_mgr.private_data);
-}
-
-static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr,
- struct tee_shm_pool_mem_info *info,
- int min_alloc_order)
-{
- size_t page_mask = PAGE_SIZE - 1;
- struct gen_pool *genpool = NULL;
- int rc;
-
- /*
- * Start and end must be page aligned
- */
- if ((info->vaddr & page_mask) || (info->paddr & page_mask) ||
- (info->size & page_mask))
- return -EINVAL;
-
- genpool = gen_pool_create(min_alloc_order, -1);
- if (!genpool)
- return -ENOMEM;
-
- gen_pool_set_algo(genpool, gen_pool_best_fit, NULL);
- rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size,
- -1);
- if (rc) {
- gen_pool_destroy(genpool);
- return rc;
- }
-
- mgr->private_data = genpool;
- mgr->ops = &pool_ops_generic;
- return 0;
-}
-
/**
* tee_shm_pool_alloc_res_mem() - Create a shared memory pool from reserved
* memory range
@@ -104,42 +73,109 @@ struct tee_shm_pool *
tee_shm_pool_alloc_res_mem(struct tee_shm_pool_mem_info *priv_info,
struct tee_shm_pool_mem_info *dmabuf_info)
{
- struct tee_shm_pool *pool = NULL;
- int ret;
-
- pool = kzalloc(sizeof(*pool), GFP_KERNEL);
- if (!pool) {
- ret = -ENOMEM;
- goto err;
- }
+ struct tee_shm_pool_mgr *priv_mgr;
+ struct tee_shm_pool_mgr *dmabuf_mgr;
+ void *rc;
/*
* Create the pool for driver private shared memory
*/
- ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info,
- 3 /* 8 byte aligned */);
- if (ret)
- goto err;
+ rc = tee_shm_pool_mgr_alloc_res_mem(priv_info->vaddr, priv_info->paddr,
+ priv_info->size,
+ 3 /* 8 byte aligned */);
+ if (IS_ERR(rc))
+ return rc;
+ priv_mgr = rc;
/*
* Create the pool for dma_buf shared memory
*/
- ret = pool_res_mem_mgr_init(&pool->dma_buf_mgr, dmabuf_info,
- PAGE_SHIFT);
- if (ret)
+ rc = tee_shm_pool_mgr_alloc_res_mem(dmabuf_info->vaddr,
+ dmabuf_info->paddr,
+ dmabuf_info->size, PAGE_SHIFT);
+ if (IS_ERR(rc))
+ goto err_free_priv_mgr;
+ dmabuf_mgr = rc;
+
+ rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
+ if (IS_ERR(rc))
+ goto err_free_dmabuf_mgr;
+
+ return rc;
+
+err_free_dmabuf_mgr:
+ tee_shm_pool_mgr_destroy(dmabuf_mgr);
+err_free_priv_mgr:
+ tee_shm_pool_mgr_destroy(priv_mgr);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
+
+struct tee_shm_pool_mgr *tee_shm_pool_mgr_alloc_res_mem(unsigned long vaddr,
+ phys_addr_t paddr,
+ size_t size,
+ int min_alloc_order)
+{
+ const size_t page_mask = PAGE_SIZE - 1;
+ struct tee_shm_pool_mgr *mgr;
+ int rc;
+
+ /* Start and end must be page aligned */
+ if (vaddr & page_mask || paddr & page_mask || size & page_mask)
+ return ERR_PTR(-EINVAL);
+
+ mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
+ if (!mgr)
+ return ERR_PTR(-ENOMEM);
+
+ mgr->private_data = gen_pool_create(min_alloc_order, -1);
+ if (!mgr->private_data) {
+ rc = -ENOMEM;
goto err;
+ }
- pool->destroy = pool_res_mem_destroy;
- return pool;
+ gen_pool_set_algo(mgr->private_data, gen_pool_best_fit, NULL);
+ rc = gen_pool_add_virt(mgr->private_data, vaddr, paddr, size, -1);
+ if (rc) {
+ gen_pool_destroy(mgr->private_data);
+ goto err;
+ }
+
+ mgr->ops = &pool_ops_generic;
+
+ return mgr;
err:
- if (ret == -ENOMEM)
- pr_err("%s: can't allocate memory for res_mem shared memory pool\n", __func__);
- if (pool && pool->private_mgr.private_data)
- gen_pool_destroy(pool->private_mgr.private_data);
- kfree(pool);
- return ERR_PTR(ret);
+ kfree(mgr);
+
+ return ERR_PTR(rc);
}
-EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
+EXPORT_SYMBOL_GPL(tee_shm_pool_mgr_alloc_res_mem);
+
+static bool check_mgr_ops(struct tee_shm_pool_mgr *mgr)
+{
+ return mgr && mgr->ops && mgr->ops->alloc && mgr->ops->free &&
+ mgr->ops->destroy_poolmgr;
+}
+
+struct tee_shm_pool *tee_shm_pool_alloc(struct tee_shm_pool_mgr *priv_mgr,
+ struct tee_shm_pool_mgr *dmabuf_mgr)
+{
+ struct tee_shm_pool *pool;
+
+ if (!check_mgr_ops(priv_mgr) || !check_mgr_ops(dmabuf_mgr))
+ return ERR_PTR(-EINVAL);
+
+ pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+ if (!pool)
+ return ERR_PTR(-ENOMEM);
+
+ pool->private_mgr = priv_mgr;
+ pool->dma_buf_mgr = dmabuf_mgr;
+
+ return pool;
+}
+EXPORT_SYMBOL_GPL(tee_shm_pool_alloc);
/**
* tee_shm_pool_free() - Free a shared memory pool
@@ -150,7 +186,10 @@ EXPORT_SYMBOL_GPL(tee_shm_pool_alloc_res_mem);
*/
void tee_shm_pool_free(struct tee_shm_pool *pool)
{
- pool->destroy(pool);
+ if (pool->private_mgr)
+ tee_shm_pool_mgr_destroy(pool->private_mgr);
+ if (pool->dma_buf_mgr)
+ tee_shm_pool_mgr_destroy(pool->dma_buf_mgr);
kfree(pool);
}
EXPORT_SYMBOL_GPL(tee_shm_pool_free);