summaryrefslogtreecommitdiff
path: root/drivers/tee/optee/ffa_abi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tee/optee/ffa_abi.c')
-rw-r--r--drivers/tee/optee/ffa_abi.c150
1 files changed, 146 insertions, 4 deletions
diff --git a/drivers/tee/optee/ffa_abi.c b/drivers/tee/optee/ffa_abi.c
index f9ef7d94cebd..bf8390789ecf 100644
--- a/drivers/tee/optee/ffa_abi.c
+++ b/drivers/tee/optee/ffa_abi.c
@@ -649,6 +649,124 @@ static int optee_ffa_do_call_with_arg(struct tee_context *ctx,
return optee_ffa_yielding_call(ctx, &data, rpc_arg, system_thread);
}
+static int do_call_lend_protmem(struct optee *optee, u64 cookie, u32 use_case)
+{
+ struct optee_shm_arg_entry *entry;
+ struct optee_msg_arg *msg_arg;
+ struct tee_shm *shm;
+ u_int offs;
+ int rc;
+
+ msg_arg = optee_get_msg_arg(optee->ctx, 1, &entry, &shm, &offs);
+ if (IS_ERR(msg_arg))
+ return PTR_ERR(msg_arg);
+
+ msg_arg->cmd = OPTEE_MSG_CMD_ASSIGN_PROTMEM;
+ msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT;
+ msg_arg->params[0].u.value.a = cookie;
+ msg_arg->params[0].u.value.b = use_case;
+
+ rc = optee->ops->do_call_with_arg(optee->ctx, shm, offs, false);
+ if (rc)
+ goto out;
+ if (msg_arg->ret != TEEC_SUCCESS) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+out:
+ optee_free_msg_arg(optee->ctx, entry, offs);
+ return rc;
+}
+
+static int optee_ffa_lend_protmem(struct optee *optee, struct tee_shm *protmem,
+ u32 *mem_attrs, unsigned int ma_count,
+ u32 use_case)
+{
+ struct ffa_device *ffa_dev = optee->ffa.ffa_dev;
+ const struct ffa_mem_ops *mem_ops = ffa_dev->ops->mem_ops;
+ const struct ffa_msg_ops *msg_ops = ffa_dev->ops->msg_ops;
+ struct ffa_send_direct_data data;
+ struct ffa_mem_region_attributes *mem_attr;
+ struct ffa_mem_ops_args args = {
+ .use_txbuf = true,
+ .tag = use_case,
+ };
+ struct page *page;
+ struct scatterlist sgl;
+ unsigned int n;
+ int rc;
+
+ mem_attr = kcalloc(ma_count, sizeof(*mem_attr), GFP_KERNEL);
+ for (n = 0; n < ma_count; n++) {
+ mem_attr[n].receiver = mem_attrs[n] & U16_MAX;
+ mem_attr[n].attrs = mem_attrs[n] >> 16;
+ }
+ args.attrs = mem_attr;
+ args.nattrs = ma_count;
+
+ page = phys_to_page(protmem->paddr);
+ sg_init_table(&sgl, 1);
+ sg_set_page(&sgl, page, protmem->size, 0);
+
+ args.sg = &sgl;
+ rc = mem_ops->memory_lend(&args);
+ kfree(mem_attr);
+ if (rc)
+ return rc;
+
+ rc = do_call_lend_protmem(optee, args.g_handle, use_case);
+ if (rc)
+ goto err_reclaim;
+
+ rc = optee_shm_add_ffa_handle(optee, protmem, args.g_handle);
+ if (rc)
+ goto err_unreg;
+
+ protmem->sec_world_id = args.g_handle;
+
+ return 0;
+
+err_unreg:
+ data = (struct ffa_send_direct_data){
+ .data0 = OPTEE_FFA_RELEASE_PROTMEM,
+ .data1 = (u32)args.g_handle,
+ .data2 = (u32)(args.g_handle >> 32),
+ };
+ msg_ops->sync_send_receive(ffa_dev, &data);
+err_reclaim:
+ mem_ops->memory_reclaim(args.g_handle, 0);
+ return rc;
+}
+
+static int optee_ffa_reclaim_protmem(struct optee *optee,
+ struct tee_shm *protmem)
+{
+ struct ffa_device *ffa_dev = optee->ffa.ffa_dev;
+ const struct ffa_msg_ops *msg_ops = ffa_dev->ops->msg_ops;
+ const struct ffa_mem_ops *mem_ops = ffa_dev->ops->mem_ops;
+ u64 global_handle = protmem->sec_world_id;
+ struct ffa_send_direct_data data = {
+ .data0 = OPTEE_FFA_RELEASE_PROTMEM,
+ .data1 = (u32)global_handle,
+ .data2 = (u32)(global_handle >> 32)
+ };
+ int rc;
+
+ optee_shm_rem_ffa_handle(optee, global_handle);
+ protmem->sec_world_id = 0;
+
+ rc = msg_ops->sync_send_receive(ffa_dev, &data);
+ if (rc)
+ pr_err("Release SHM id 0x%llx rc %d\n", global_handle, rc);
+
+ rc = mem_ops->memory_reclaim(global_handle, 0);
+ if (rc)
+ pr_err("mem_reclaim: 0x%llx %d", global_handle, rc);
+
+ return rc;
+}
+
/*
* 6. Driver initialization
*
@@ -657,7 +775,7 @@ static int optee_ffa_do_call_with_arg(struct tee_context *ctx,
* with a matching configuration.
*/
-static bool optee_ffa_api_is_compatbile(struct ffa_device *ffa_dev,
+static bool optee_ffa_api_is_compatible(struct ffa_device *ffa_dev,
const struct ffa_ops *ops)
{
const struct ffa_msg_ops *msg_ops = ops->msg_ops;
@@ -819,6 +937,8 @@ static const struct optee_ops optee_ffa_ops = {
.do_call_with_arg = optee_ffa_do_call_with_arg,
.to_msg_param = optee_ffa_to_msg_param,
.from_msg_param = optee_ffa_from_msg_param,
+ .lend_protmem = optee_ffa_lend_protmem,
+ .reclaim_protmem = optee_ffa_reclaim_protmem,
};
static void optee_ffa_remove(struct ffa_device *ffa_dev)
@@ -891,6 +1011,25 @@ err:
return rc;
}
+static int optee_ffa_protmem_pool_init(struct optee *optee, u32 sec_caps)
+{
+ enum tee_dma_heap_id id = TEE_DMA_HEAP_SECURE_VIDEO_PLAY;
+ struct tee_protmem_pool *pool;
+ int rc = 0;
+
+ if (sec_caps & OPTEE_FFA_SEC_CAP_PROTMEM) {
+ pool = optee_protmem_alloc_dyn_pool(optee, id);
+ if (IS_ERR(pool))
+ return PTR_ERR(pool);
+
+ rc = tee_device_register_dma_heap(optee->teedev, id, pool);
+ if (rc)
+ pool->ops->destroy_pool(pool);
+ }
+
+ return rc;
+}
+
static int optee_ffa_probe(struct ffa_device *ffa_dev)
{
const struct ffa_notifier_ops *notif_ops;
@@ -908,7 +1047,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
ffa_ops = ffa_dev->ops;
notif_ops = ffa_ops->notifier_ops;
- if (!optee_ffa_api_is_compatbile(ffa_dev, ffa_ops))
+ if (!optee_ffa_api_is_compatible(ffa_dev, ffa_ops))
return -EINVAL;
if (!optee_ffa_exchange_caps(ffa_dev, ffa_ops, &sec_caps,
@@ -941,7 +1080,7 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
optee);
if (IS_ERR(teedev)) {
rc = PTR_ERR(teedev);
- goto err_free_pool;
+ goto err_free_shm_pool;
}
optee->teedev = teedev;
@@ -988,6 +1127,9 @@ static int optee_ffa_probe(struct ffa_device *ffa_dev)
rc);
}
+ if (optee_ffa_protmem_pool_init(optee, sec_caps))
+ pr_info("Protected memory service not available\n");
+
rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES);
if (rc)
goto err_unregister_devices;
@@ -1018,7 +1160,7 @@ err_unreg_supp_teedev:
tee_device_unregister(optee->supp_teedev);
err_unreg_teedev:
tee_device_unregister(optee->teedev);
-err_free_pool:
+err_free_shm_pool:
tee_shm_pool_free(pool);
err_free_optee:
kfree(optee);