From 7c9770b5c74751873a8c276f7105c2a5c450c4c7 Mon Sep 17 00:00:00 2001 From: Gaurav Kashyap Date: Thu, 3 Sep 2020 11:21:40 -0700 Subject: [PATCH 1/2] smcinvoke: add support of secure memory objects SMCInvoke provides communication trusted clients and applications. However, to send large buffers, it s reccommended to use memory objects. If memory objects are coming from heaps which have not been registered with SHMBridge, invoke operation would fail. Adding support to register bridges for memory objects if those are coming from secure heaps. Change-Id: Id13822f877b2ffb1886411705ffcbf1e3ef2a98a Signed-off-by: Gaurav Kashyap --- drivers/soc/qcom/smcinvoke.c | 101 ++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/smcinvoke.c b/drivers/soc/qcom/smcinvoke.c index 96359a335a05..d3d757ec67bc 100644 --- a/drivers/soc/qcom/smcinvoke.c +++ b/drivers/soc/qcom/smcinvoke.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -249,6 +250,8 @@ struct smcinvoke_mem_obj { uint64_t p_addr; size_t p_addr_len; struct list_head list; + bool bridge_created_by_others; + uint64_t shmbridge_handle; }; static void destroy_cb_server(struct kref *kref) @@ -357,6 +360,8 @@ static inline void free_mem_obj_locked(struct smcinvoke_mem_obj *mem_obj) { list_del(&mem_obj->list); dma_buf_put(mem_obj->dma_buf); + if (!mem_obj->bridge_created_by_others) + qtee_shmbridge_deregister(mem_obj->shmbridge_handle); kfree(mem_obj); } @@ -788,6 +793,82 @@ out: return ret; } +static int smcinvoke_create_bridge(struct smcinvoke_mem_obj *mem_obj) +{ + int ret = 0, i; + int tz_perm = PERM_READ|PERM_WRITE; + uint32_t *vmid_list; + uint32_t *perms_list; + uint32_t nelems = 0; + unsigned long dma_buf_flags = 0; + struct dma_buf *dmabuf = mem_obj->dma_buf; + phys_addr_t phys = mem_obj->p_addr; + size_t size = mem_obj->p_addr_len; + + if (!qtee_shmbridge_is_enabled()) + return 0; + + ret = dma_buf_get_flags(dmabuf, &dma_buf_flags); + if (ret) { + pr_err("failed to get dmabuf flag for mem_region_id %d\n", + mem_obj->mem_region_id); + return ret; + } + + if (dma_buf_flags & ION_FLAG_SECURE) + nelems = ion_get_flags_num_vm_elems(dma_buf_flags); + else + nelems = 1; + + vmid_list = kcalloc(nelems, sizeof(*vmid_list), GFP_KERNEL); + if (!vmid_list) { + ret = -ENOMEM; + goto exit; + } + + perms_list = kcalloc(nelems, sizeof(*perms_list), GFP_KERNEL); + if (!perms_list) { + ret = -ENOMEM; + goto exit_free_vmid_list; + } + + if (dma_buf_flags & ION_FLAG_SECURE) { + ret = ion_populate_vm_list(dma_buf_flags, vmid_list, nelems); + if (ret) + goto exit_free_vmid_list; + + for (i = 0; i < nelems; i++) + perms_list[i] = msm_secure_get_vmid_perms(vmid_list[i]); + } else { + vmid_list[0] = VMID_HLOS; + perms_list[0] = PERM_READ | PERM_WRITE; + } + + ret = qtee_shmbridge_register(phys, size, vmid_list, perms_list, nelems, + tz_perm, &mem_obj->shmbridge_handle); + + if (ret && ret != -EEXIST) { + pr_err("creation of shm bridge for mem_region_id %d failed ret %d\n", + mem_obj->mem_region_id, ret); + goto exit_free_perms_list; + } + + if (ret == -EEXIST) { + mem_obj->bridge_created_by_others = true; + ret = 0; + } + + pr_debug("created shm bridge handle %lld for mem_region_id %d\n", + mem_obj->shmbridge_handle, mem_obj->mem_region_id); + +exit_free_perms_list: + kfree(perms_list); +exit_free_vmid_list: + kfree(vmid_list); +exit: + return ret; +} + static int32_t smcinvoke_release_mem_obj_locked(void *buf, size_t buf_len) { struct smcinvoke_tzcb_req *msg = buf; @@ -845,8 +926,9 @@ static int32_t smcinvoke_map_mem_region(void *buf, size_t buf_len) sgt = dma_buf_map_attachment(buf_attach, DMA_BIDIRECTIONAL); if (IS_ERR(sgt)) { + pr_err("mapping dma buffers failed, ret: %d\n", + PTR_ERR(sgt)); ret = OBJECT_ERROR_KMEM; - pr_err("mapping dma buffers failed, ret: %d\n", ret); goto out; } mem_obj->sgt = sgt; @@ -864,6 +946,11 @@ static int32_t smcinvoke_map_mem_region(void *buf, size_t buf_len) pr_err("invalid physical address, ret: %d\n", ret); goto out; } + ret = smcinvoke_create_bridge(mem_obj); + if (ret) { + ret = OBJECT_ERROR_INVALID; + goto out; + } mem_obj->mem_map_obj_id = next_mem_map_obj_id_locked(); } else { kref_get(&mem_obj->mem_map_obj_ref_cnt); @@ -974,7 +1061,12 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) TZHANDLE_GET_SERVER(cb_req->hdr.tzhandle)); if (!srvr_info || srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT) { /* ret equals Object_ERROR_DEFUNCT, at this point go to out */ - pr_err("sever is either invalid or defunct\n"); + if (!srvr_info) + pr_err("server is invalid\n"); + else { + pr_err("server is defunct, state= %d tzhandle = %d\n", + srvr_info->state, cb_req->hdr.tzhandle); + } mutex_unlock(&g_smcinvoke_lock); goto out; } @@ -1928,6 +2020,11 @@ static int smcinvoke_probe(struct platform_device *pdev) goto exit_destroy_device; } smcinvoke_pdev = pdev; + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (rc) { + pr_err("dma_set_mask_and_coherent failed %d\n", rc); + goto exit_destroy_device; + } return 0; From 83174e305d9e7e60990bd90d55b31ad20b2c7e20 Mon Sep 17 00:00:00 2001 From: Gaurav Kashyap Date: Thu, 3 Sep 2020 11:22:22 -0700 Subject: [PATCH 2/2] qtee_shmbridge: register bridges for CMA heaps register shared memory bridges for CMA heaps Change-Id: I4b80e215ea013894af27385dccec884d63d76dca Signed-off-by: Jade Xu Signed-off-by: Gaurav Kashyap --- drivers/firmware/qtee_shmbridge.c | 38 ++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/drivers/firmware/qtee_shmbridge.c b/drivers/firmware/qtee_shmbridge.c index 72699c0e9f79..3b712b22cc9e 100644 --- a/drivers/firmware/qtee_shmbridge.c +++ b/drivers/firmware/qtee_shmbridge.c @@ -11,8 +11,11 @@ #include #include #include +#include +#include #include #include +#include #include #include #include @@ -78,6 +81,18 @@ struct bridge_list_entry { uint64_t handle; }; +struct cma_heap_bridge_info { + uint32_t heapid; + uint64_t handle; +}; + +enum CMA_HEAP_TYPE { + QSEECOM_HEAP = 0, + QSEECOM_TA_HEAP, + USER_CONTI_HEAP, + HEAP_TYPE_MAX +}; + static struct bridge_info default_bridge; static struct bridge_list bridge_list_head; static bool qtee_shmbridge_enabled; @@ -390,11 +405,12 @@ static int qtee_shmbridge_init(struct platform_device *pdev) mutex_init(&bridge_list_head.lock); INIT_LIST_HEAD(&bridge_list_head.head); + /* temporarily disable shm bridge mechanism */ ret = qtee_shmbridge_enable(true); if (ret) { /* keep the mem pool and return if failed to enable bridge */ ret = 0; - goto exit; + goto exit_shmbridge_enable; } /*register default bridge*/ @@ -412,7 +428,7 @@ static int qtee_shmbridge_init(struct platform_device *pdev) if (ret) { pr_err("Failed to register default bridge, size %zu\n", default_bridge.size); - goto exit; + goto exit_deregister_default_bridge; } pr_debug("qtee shmbridge registered default bridge with size %d bytes\n", @@ -420,6 +436,10 @@ static int qtee_shmbridge_init(struct platform_device *pdev) return 0; +exit_deregister_default_bridge: + qtee_shmbridge_deregister(default_bridge.handle); +exit_shmbridge_enable: + qtee_shmbridge_enable(false); exit_destroy_pool: gen_pool_destroy(default_bridge.genpool); exit_unmap: @@ -427,7 +447,8 @@ exit_unmap: DMA_TO_DEVICE); exit_freebuf: free_pages((long)default_bridge.vaddr, get_order(default_bridge.size)); -exit: + default_bridge.vaddr = NULL; +//exit: return ret; } @@ -439,6 +460,16 @@ static int qtee_shmbridge_probe(struct platform_device *pdev) return qtee_shmbridge_init(pdev); } +static int qtee_shmbridge_remove(struct platform_device *pdev) +{ + qtee_shmbridge_deregister(default_bridge.handle); + gen_pool_destroy(default_bridge.genpool); + dma_unmap_single(&pdev->dev, default_bridge.paddr, default_bridge.size, + DMA_TO_DEVICE); + free_pages((long)default_bridge.vaddr, get_order(default_bridge.size)); + return 0; +} + static const struct of_device_id qtee_shmbridge_of_match[] = { { .compatible = "qcom,tee-shared-memory-bridge"}, {} @@ -447,6 +478,7 @@ MODULE_DEVICE_TABLE(of, qtee_shmbridge_of_match); static struct platform_driver qtee_shmbridge_driver = { .probe = qtee_shmbridge_probe, + .remove = qtee_shmbridge_remove, .driver = { .name = "shared_memory_bridge", .of_match_table = qtee_shmbridge_of_match,