Loading drivers/misc/qseecom.c +326 −40 Original line number Diff line number Diff line Loading @@ -205,6 +205,7 @@ struct qseecom_control { uint32_t qseos_version; uint32_t qsee_version; struct device *pdev; bool whitelist_support; bool commonlib_loaded; bool commonlib64_loaded; struct ion_handle *cmnlib_ion_handle; Loading Loading @@ -267,6 +268,30 @@ struct qseecom_listener_handle { static struct qseecom_control qseecom; struct sglist_info { uint32_t indexAndFlags; uint32_t sizeOrCount; }; /* * The 31th bit indicates only one or multiple physical address inside * the request buffer. If it is set, the index locates a single physical addr * inside the request buffer, and `sizeOrCount` is the size of the memory being * shared at that physical address. * Otherwise, the index locates an array of {start, len} pairs (a * "scatter/gather list"), and `sizeOrCount` gives the number of entries in * that array. * * The 30th bit indicates 64 or 32bit address; when it is set, physical addr * and scatter gather entry sizes are 64-bit values. Otherwise, 32-bit values. * * The bits [0:29] of `indexAndFlags` hold an offset into the request buffer. */ #define SGLISTINFO_SET_INDEX_FLAG(c, s, i) \ ((uint32_t)(((c & 1) << 31) | ((s & 1) << 30) | (i & 0x3fffffff))) #define SGLISTINFO_TABLE_SIZE (sizeof(struct sglist_info) * MAX_ION_FD) struct qseecom_dev_handle { enum qseecom_client_handle_type type; union { Loading @@ -280,6 +305,8 @@ struct qseecom_dev_handle { bool perf_enabled; bool fast_load_enabled; enum qseecom_bandwidth_request_mode mode; struct sglist_info *sglistinfo_ptr; uint32_t sglist_cnt; }; struct qseecom_key_id_usage_desc { Loading Loading @@ -612,6 +639,38 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, ret = scm_call2(smc_id, &desc); break; } case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: { struct qseecom_client_send_data_ireq *req; struct qseecom_client_send_data_64bit_ireq *req_64bit; smc_id = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID; desc.arginfo = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { req = (struct qseecom_client_send_data_ireq *) req_buf; desc.args[0] = req->app_id; desc.args[1] = req->req_ptr; desc.args[2] = req->req_len; desc.args[3] = req->rsp_ptr; desc.args[4] = req->rsp_len; desc.args[5] = req->sglistinfo_ptr; desc.args[6] = req->sglistinfo_len; } else { req_64bit = (struct qseecom_client_send_data_64bit_ireq *) req_buf; desc.args[0] = req_64bit->app_id; desc.args[1] = req_64bit->req_ptr; desc.args[2] = req_64bit->req_len; desc.args[3] = req_64bit->rsp_ptr; desc.args[4] = req_64bit->rsp_len; desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } ret = scm_call2(smc_id, &desc); break; } case QSEOS_RPMB_PROVISION_KEY_COMMAND: { struct qseecom_client_send_service_ireq *req; req = (struct qseecom_client_send_service_ireq *) Loading Loading @@ -754,6 +813,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, ret = scm_call2(smc_id, &desc); break; } case QSEOS_TEE_OPEN_SESSION_WHITELIST: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; smc_id = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID; desc.arginfo = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { req = (struct qseecom_qteec_ireq *)req_buf; desc.args[0] = req->app_id; desc.args[1] = req->req_ptr; desc.args[2] = req->req_len; desc.args[3] = req->resp_ptr; desc.args[4] = req->resp_len; desc.args[5] = req->sglistinfo_ptr; desc.args[6] = req->sglistinfo_len; } else { req_64bit = (struct qseecom_qteec_64bit_ireq *) req_buf; desc.args[0] = req_64bit->app_id; desc.args[1] = req_64bit->req_ptr; desc.args[2] = req_64bit->req_len; desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } ret = scm_call2(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; Loading @@ -778,6 +867,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, ret = scm_call2(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID; desc.arginfo = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { req = (struct qseecom_qteec_ireq *)req_buf; desc.args[0] = req->app_id; desc.args[1] = req->req_ptr; desc.args[2] = req->req_len; desc.args[3] = req->resp_ptr; desc.args[4] = req->resp_len; desc.args[5] = req->sglistinfo_ptr; desc.args[6] = req->sglistinfo_len; } else { req_64bit = (struct qseecom_qteec_64bit_ireq *) req_buf; desc.args[0] = req_64bit->app_id; desc.args[1] = req_64bit->req_ptr; desc.args[2] = req_64bit->req_len; desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } ret = scm_call2(smc_id, &desc); break; } case QSEOS_TEE_CLOSE_SESSION: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; Loading Loading @@ -2705,14 +2824,15 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, { int ret = 0; u32 reqd_len_sb_in = 0; struct qseecom_client_send_data_ireq send_data_req; struct qseecom_client_send_data_64bit_ireq send_data_req_64bit; struct qseecom_client_send_data_ireq send_data_req = {0}; struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0}; struct qseecom_command_scm_resp resp; unsigned long flags; struct qseecom_registered_app_list *ptr_app; bool found_app = false; void *cmd_buf = NULL; size_t cmd_len; struct sglist_info *table = data->sglistinfo_ptr; reqd_len_sb_in = req->cmd_req_len + req->resp_len; /* find app_id & img_name from list */ Loading @@ -2734,7 +2854,6 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, } if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND; send_data_req.app_id = data->client.app_id; send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( data, (uintptr_t)req->cmd_req_buf)); Loading @@ -2742,11 +2861,14 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, send_data_req.rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( data, (uintptr_t)req->resp_buf)); send_data_req.rsp_len = req->resp_len; send_data_req.sglistinfo_ptr = (uint32_t)virt_to_phys(table); send_data_req.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); cmd_buf = (void *)&send_data_req; cmd_len = sizeof(struct qseecom_client_send_data_ireq); } else { send_data_req_64bit.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND; send_data_req_64bit.app_id = data->client.app_id; send_data_req_64bit.req_ptr = __qseecom_uvirt_to_kphys(data, (uintptr_t)req->cmd_req_buf); Loading @@ -2768,10 +2890,20 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, send_data_req_64bit.rsp_len); return -EFAULT; } send_data_req_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table); send_data_req_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); cmd_buf = (void *)&send_data_req_64bit; cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq); } if (qseecom.whitelist_support == false) *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND; else *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST; msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, reqd_len_sb_in, Loading Loading @@ -3025,14 +3157,26 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, goto err; } } if (cleanup) if (cleanup) { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_INV_CACHES); else } else { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_CLEAN_INV_CACHES); if (data->type == QSEECOM_CLIENT_APP) { data->sglistinfo_ptr[i].indexAndFlags = SGLISTINFO_SET_INDEX_FLAG( (sg_ptr->nents == 1), 0, req->ifd_data[i].cmd_buf_offset); data->sglistinfo_ptr[i].sizeOrCount = (sg_ptr->nents == 1) ? sg->length : sg_ptr->nents; data->sglist_cnt = i + 1; } } /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); Loading Loading @@ -3231,14 +3375,25 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, } } cleanup: if (cleanup) if (cleanup) { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_INV_CACHES); else } else { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_CLEAN_INV_CACHES); if (data->type == QSEECOM_CLIENT_APP) { data->sglistinfo_ptr[i].indexAndFlags = SGLISTINFO_SET_INDEX_FLAG( (sg_ptr->nents == 1), 1, req->ifd_data[i].cmd_buf_offset); data->sglistinfo_ptr[i].sizeOrCount = (sg_ptr->nents == 1) ? sg->length : sg_ptr->nents; data->sglist_cnt = i + 1; } } /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); Loading Loading @@ -5897,14 +6052,23 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req, *update = (uint32_t)sg_dma_address(sg_ptr->sgl); } clean: if (cleanup) if (cleanup) { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, sg->length, ION_IOC_INV_CACHES); else } else { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, sg->length, ION_IOC_CLEAN_INV_CACHES); data->sglistinfo_ptr[i].indexAndFlags = SGLISTINFO_SET_INDEX_FLAG( (sg_ptr->nents == 1), 0, req->ifd_data[i].cmd_buf_offset); data->sglistinfo_ptr[i].sizeOrCount = (sg_ptr->nents == 1) ? sg->length : sg_ptr->nents; data->sglist_cnt = i + 1; } /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); Loading @@ -5929,6 +6093,7 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, uint32_t reqd_len_sb_in = 0; void *cmd_buf = NULL; size_t cmd_len; struct sglist_info *table = data->sglistinfo_ptr; ret = __qseecom_qteec_validate_msg(data, req); if (ret) Loading @@ -5951,8 +6116,15 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, return -ENOENT; } if ((cmd_id == QSEOS_TEE_OPEN_SESSION) || (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) { ret = __qseecom_update_qteec_req_buf( (struct qseecom_qteec_modfd_req *)req, data, false); if (ret) return ret; } if (qseecom.qsee_version < QSEE_VERSION_40) { ireq.qsee_cmd_id = cmd_id; ireq.app_id = data->client.app_id; ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req->req_ptr); Loading @@ -5960,10 +6132,13 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req->resp_ptr); ireq.resp_len = req->resp_len; ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table); ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); cmd_buf = (void *)&ireq; cmd_len = sizeof(struct qseecom_qteec_ireq); } else { ireq_64bit.qsee_cmd_id = cmd_id; ireq_64bit.app_id = data->client.app_id; ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req->req_ptr); Loading @@ -5983,17 +6158,19 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, ireq_64bit.resp_ptr, ireq_64bit.resp_len); return -EFAULT; } ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table); ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); cmd_buf = (void *)&ireq_64bit; cmd_len = sizeof(struct qseecom_qteec_64bit_ireq); } if (qseecom.whitelist_support == true && cmd_id == QSEOS_TEE_OPEN_SESSION) *(uint32_t *)cmd_buf = QSEOS_TEE_OPEN_SESSION_WHITELIST; else *(uint32_t *)cmd_buf = cmd_id; if ((cmd_id == QSEOS_TEE_OPEN_SESSION) || (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) { ret = __qseecom_update_qteec_req_buf( (struct qseecom_qteec_modfd_req *)req, data, false); if (ret) return ret; } reqd_len_sb_in = req->req_len + req->resp_len; msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, Loading Loading @@ -6091,6 +6268,9 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, uint32_t reqd_len_sb_in = 0; void *cmd_buf = NULL; size_t cmd_len; struct sglist_info *table = data->sglistinfo_ptr; void *req_ptr = NULL; void *resp_ptr = NULL; ret = copy_from_user(&req, argp, sizeof(struct qseecom_qteec_modfd_req)); Loading @@ -6102,6 +6282,8 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, (struct qseecom_qteec_req *)(&req)); if (ret) return ret; req_ptr = req.req_ptr; resp_ptr = req.resp_ptr; /* find app_id & img_name from list */ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); Loading @@ -6120,45 +6302,56 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, return -ENOENT; } /* validate offsets */ for (i = 0; i < MAX_ION_FD; i++) { if (req.ifd_data[i].fd) { if (req.ifd_data[i].cmd_buf_offset >= req.req_len) return -EINVAL; } } req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req.req_ptr); req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req.resp_ptr); ret = __qseecom_update_qteec_req_buf(&req, data, false); if (ret) return ret; if (qseecom.qsee_version < QSEE_VERSION_40) { ireq.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND; ireq.app_id = data->client.app_id; ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req.req_ptr); (uintptr_t)req_ptr); ireq.req_len = req.req_len; ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req.resp_ptr); (uintptr_t)resp_ptr); ireq.resp_len = req.resp_len; cmd_buf = (void *)&ireq; cmd_len = sizeof(struct qseecom_qteec_ireq); ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table); ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); } else { ireq_64bit.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND; ireq_64bit.app_id = data->client.app_id; ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req.req_ptr); (uintptr_t)req_ptr); ireq_64bit.req_len = req.req_len; ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req.resp_ptr); (uintptr_t)resp_ptr); ireq_64bit.resp_len = req.resp_len; cmd_buf = (void *)&ireq_64bit; cmd_len = sizeof(struct qseecom_qteec_64bit_ireq); ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table); ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); } reqd_len_sb_in = req.req_len + req.resp_len; if (qseecom.whitelist_support == true) *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND_WHITELIST; else *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND; /* validate offsets */ for (i = 0; i < MAX_ION_FD; i++) { if (req.ifd_data[i].fd) { if (req.ifd_data[i].cmd_buf_offset >= req.req_len) return -EINVAL; } } req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req.req_ptr); req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req.resp_ptr); ret = __qseecom_update_qteec_req_buf(&req, data, false); if (ret) return ret; msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, reqd_len_sb_in, Loading Loading @@ -6221,6 +6414,15 @@ static int qseecom_qteec_request_cancellation(struct qseecom_dev_handle *data, return ret; } static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data) { if (data->sglist_cnt) { memset(data->sglistinfo_ptr, 0, SGLISTINFO_TABLE_SIZE); data->sglist_cnt = 0; } } long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) { int ret = 0; Loading Loading @@ -6400,6 +6602,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed qseecom_send_cmd: %d\n", ret); __qseecom_clean_data_sglistinfo(data); break; } case QSEECOM_IOCTL_RECEIVE_REQ: { Loading Loading @@ -6797,6 +7000,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed open_session_cmd: %d\n", ret); __qseecom_clean_data_sglistinfo(data); break; } case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ: { Loading Loading @@ -6845,6 +7049,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed Invoke cmd: %d\n", ret); __qseecom_clean_data_sglistinfo(data); break; } case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ: { Loading Loading @@ -6921,6 +7126,9 @@ static int qseecom_open(struct inode *inode, struct file *file) init_waitqueue_head(&data->abort_wq); atomic_set(&data->ioctl_count, 0); data->sglistinfo_ptr = kzalloc(SGLISTINFO_TABLE_SIZE, GFP_KERNEL); if (!(data->sglistinfo_ptr)) return -ENOMEM; return ret; } Loading Loading @@ -6975,6 +7183,7 @@ static int qseecom_release(struct inode *inode, struct file *file) if (data->perf_enabled == true) qsee_disable_clock_vote(data, CLK_DFAB); } kfree(data->sglistinfo_ptr); kfree(data); return ret; Loading Loading @@ -7722,6 +7931,74 @@ out: return ret; } /* * Check if whitelist feature is supported by making a test scm_call * to send a whitelist command to an invalid app ID 0 */ static int qseecom_check_whitelist_feature(void) { struct qseecom_client_send_data_ireq send_data_req = {0}; struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0}; struct qseecom_command_scm_resp resp; uint32_t buf_size = 128; void *buf = NULL; void *cmd_buf = NULL; size_t cmd_len; int ret = 0; phys_addr_t pa; buf = kzalloc(buf_size, GFP_KERNEL); if (!buf) return -ENOMEM; pa = virt_to_phys(buf); if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST; send_data_req.app_id = 0; send_data_req.req_ptr = (uint32_t)pa; send_data_req.req_len = buf_size; send_data_req.rsp_ptr = (uint32_t)pa; send_data_req.rsp_len = buf_size; send_data_req.sglistinfo_ptr = (uint32_t)pa; send_data_req.sglistinfo_len = buf_size; cmd_buf = (void *)&send_data_req; cmd_len = sizeof(struct qseecom_client_send_data_ireq); } else { send_data_req_64bit.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST; send_data_req_64bit.app_id = 0; send_data_req_64bit.req_ptr = (uint64_t)pa; send_data_req_64bit.req_len = buf_size; send_data_req_64bit.rsp_ptr = (uint64_t)pa; send_data_req_64bit.rsp_len = buf_size; send_data_req_64bit.sglistinfo_ptr = (uint64_t)pa; send_data_req_64bit.sglistinfo_len = buf_size; cmd_buf = (void *)&send_data_req_64bit; cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq); } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); /* * If this cmd exists and whitelist is supported, scm_call return -2 (scm * driver remap it to -EINVAL) and resp.result 0xFFFFFFED(-19); Otherwise, * scm_call return -1 (remap to -EIO). */ if (ret == -EIO) { qseecom.whitelist_support = false; ret = 0; } else if (ret == -EINVAL && resp.result == QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD) { qseecom.whitelist_support = true; ret = 0; } else { pr_err("Failed to check whitelist: ret = %d, result = 0x%x\n", ret, resp.result); } kfree(buf); return ret; } static int qseecom_probe(struct platform_device *pdev) { int rc; Loading Loading @@ -7754,6 +8031,7 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.app_block_ref_cnt = 0; init_waitqueue_head(&qseecom.app_block_wq); qseecom.whitelist_support = true; rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV); if (rc < 0) { Loading Loading @@ -7969,6 +8247,14 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.qsee_perf_client = msm_bus_scale_register_client( qseecom_platform_support); rc = qseecom_check_whitelist_feature(); if (rc) { rc = -EINVAL; goto exit_destroy_ion_client; } pr_warn("qseecom.whitelist_support = %d\n", qseecom.whitelist_support); if (!qseecom.qsee_perf_client) pr_err("Unable to register bus client\n"); Loading include/soc/qcom/qseecomi.h +46 −1 Original line number Diff line number Diff line /* * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -18,6 +18,7 @@ #define QSEECOM_KEY_ID_SIZE 32 #define QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD -19 /*0xFFFFFFED*/ #define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63 #define QSEOS_RESULT_FAIL_KS_OP -64 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -65 Loading Loading @@ -64,6 +65,9 @@ enum qseecom_qceos_cmd_id { QSEOS_TEE_REQUEST_CANCELLATION, QSEOS_CONTINUE_BLOCKED_REQ_COMMAND, QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND = 0x1B, QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST = 0x1C, QSEOS_TEE_OPEN_SESSION_WHITELIST = 0x1D, QSEOS_TEE_INVOKE_COMMAND_WHITELIST = 0x1E, QSEOS_FSM_LTEOTA_REQ_CMD = 0x109, QSEOS_FSM_LTEOTA_REQ_RSP_CMD = 0x110, QSEOS_FSM_IKE_REQ_CMD = 0x203, Loading Loading @@ -181,6 +185,8 @@ __packed struct qseecom_client_send_data_ireq { uint32_t req_len; uint32_t rsp_ptr;/* First 4 bytes should be the return status */ uint32_t rsp_len; uint32_t sglistinfo_ptr; uint32_t sglistinfo_len; }; __packed struct qseecom_client_send_data_64bit_ireq { Loading @@ -190,6 +196,8 @@ __packed struct qseecom_client_send_data_64bit_ireq { uint32_t req_len; uint64_t rsp_ptr; uint32_t rsp_len; uint64_t sglistinfo_ptr; uint32_t sglistinfo_len; }; __packed struct qseecom_reg_log_buf_ireq { Loading Loading @@ -292,6 +300,8 @@ __packed struct qseecom_qteec_ireq { uint32_t req_len; uint32_t resp_ptr; uint32_t resp_len; uint32_t sglistinfo_ptr; uint32_t sglistinfo_len; }; __packed struct qseecom_qteec_64bit_ireq { Loading @@ -301,6 +311,8 @@ __packed struct qseecom_qteec_64bit_ireq { uint32_t req_len; uint64_t resp_ptr; uint32_t resp_len; uint64_t sglistinfo_ptr; uint32_t sglistinfo_len; }; __packed struct qseecom_client_send_fsm_key_req { Loading Loading @@ -658,4 +670,37 @@ __packed struct qseecom_continue_blocked_request_ireq { #define TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL) #define TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID \ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \ TZ_SVC_APP_ID_PLACEHOLDER, 0x06) #define TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_7( \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL) #define TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID \ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \ TZ_SVC_APP_ID_PLACEHOLDER, 0x07) #define TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_7( \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL) #define TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID \ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \ TZ_SVC_APP_ID_PLACEHOLDER, 0x09) #define TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_7( \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL) #endif /* __QSEECOMI_H_ */ Loading
drivers/misc/qseecom.c +326 −40 Original line number Diff line number Diff line Loading @@ -205,6 +205,7 @@ struct qseecom_control { uint32_t qseos_version; uint32_t qsee_version; struct device *pdev; bool whitelist_support; bool commonlib_loaded; bool commonlib64_loaded; struct ion_handle *cmnlib_ion_handle; Loading Loading @@ -267,6 +268,30 @@ struct qseecom_listener_handle { static struct qseecom_control qseecom; struct sglist_info { uint32_t indexAndFlags; uint32_t sizeOrCount; }; /* * The 31th bit indicates only one or multiple physical address inside * the request buffer. If it is set, the index locates a single physical addr * inside the request buffer, and `sizeOrCount` is the size of the memory being * shared at that physical address. * Otherwise, the index locates an array of {start, len} pairs (a * "scatter/gather list"), and `sizeOrCount` gives the number of entries in * that array. * * The 30th bit indicates 64 or 32bit address; when it is set, physical addr * and scatter gather entry sizes are 64-bit values. Otherwise, 32-bit values. * * The bits [0:29] of `indexAndFlags` hold an offset into the request buffer. */ #define SGLISTINFO_SET_INDEX_FLAG(c, s, i) \ ((uint32_t)(((c & 1) << 31) | ((s & 1) << 30) | (i & 0x3fffffff))) #define SGLISTINFO_TABLE_SIZE (sizeof(struct sglist_info) * MAX_ION_FD) struct qseecom_dev_handle { enum qseecom_client_handle_type type; union { Loading @@ -280,6 +305,8 @@ struct qseecom_dev_handle { bool perf_enabled; bool fast_load_enabled; enum qseecom_bandwidth_request_mode mode; struct sglist_info *sglistinfo_ptr; uint32_t sglist_cnt; }; struct qseecom_key_id_usage_desc { Loading Loading @@ -612,6 +639,38 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, ret = scm_call2(smc_id, &desc); break; } case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: { struct qseecom_client_send_data_ireq *req; struct qseecom_client_send_data_64bit_ireq *req_64bit; smc_id = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID; desc.arginfo = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { req = (struct qseecom_client_send_data_ireq *) req_buf; desc.args[0] = req->app_id; desc.args[1] = req->req_ptr; desc.args[2] = req->req_len; desc.args[3] = req->rsp_ptr; desc.args[4] = req->rsp_len; desc.args[5] = req->sglistinfo_ptr; desc.args[6] = req->sglistinfo_len; } else { req_64bit = (struct qseecom_client_send_data_64bit_ireq *) req_buf; desc.args[0] = req_64bit->app_id; desc.args[1] = req_64bit->req_ptr; desc.args[2] = req_64bit->req_len; desc.args[3] = req_64bit->rsp_ptr; desc.args[4] = req_64bit->rsp_len; desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } ret = scm_call2(smc_id, &desc); break; } case QSEOS_RPMB_PROVISION_KEY_COMMAND: { struct qseecom_client_send_service_ireq *req; req = (struct qseecom_client_send_service_ireq *) Loading Loading @@ -754,6 +813,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, ret = scm_call2(smc_id, &desc); break; } case QSEOS_TEE_OPEN_SESSION_WHITELIST: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; smc_id = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID; desc.arginfo = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { req = (struct qseecom_qteec_ireq *)req_buf; desc.args[0] = req->app_id; desc.args[1] = req->req_ptr; desc.args[2] = req->req_len; desc.args[3] = req->resp_ptr; desc.args[4] = req->resp_len; desc.args[5] = req->sglistinfo_ptr; desc.args[6] = req->sglistinfo_len; } else { req_64bit = (struct qseecom_qteec_64bit_ireq *) req_buf; desc.args[0] = req_64bit->app_id; desc.args[1] = req_64bit->req_ptr; desc.args[2] = req_64bit->req_len; desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } ret = scm_call2(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; Loading @@ -778,6 +867,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, ret = scm_call2(smc_id, &desc); break; } case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID; desc.arginfo = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID; if (qseecom.qsee_version < QSEE_VERSION_40) { req = (struct qseecom_qteec_ireq *)req_buf; desc.args[0] = req->app_id; desc.args[1] = req->req_ptr; desc.args[2] = req->req_len; desc.args[3] = req->resp_ptr; desc.args[4] = req->resp_len; desc.args[5] = req->sglistinfo_ptr; desc.args[6] = req->sglistinfo_len; } else { req_64bit = (struct qseecom_qteec_64bit_ireq *) req_buf; desc.args[0] = req_64bit->app_id; desc.args[1] = req_64bit->req_ptr; desc.args[2] = req_64bit->req_len; desc.args[3] = req_64bit->resp_ptr; desc.args[4] = req_64bit->resp_len; desc.args[5] = req_64bit->sglistinfo_ptr; desc.args[6] = req_64bit->sglistinfo_len; } ret = scm_call2(smc_id, &desc); break; } case QSEOS_TEE_CLOSE_SESSION: { struct qseecom_qteec_ireq *req; struct qseecom_qteec_64bit_ireq *req_64bit; Loading Loading @@ -2705,14 +2824,15 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, { int ret = 0; u32 reqd_len_sb_in = 0; struct qseecom_client_send_data_ireq send_data_req; struct qseecom_client_send_data_64bit_ireq send_data_req_64bit; struct qseecom_client_send_data_ireq send_data_req = {0}; struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0}; struct qseecom_command_scm_resp resp; unsigned long flags; struct qseecom_registered_app_list *ptr_app; bool found_app = false; void *cmd_buf = NULL; size_t cmd_len; struct sglist_info *table = data->sglistinfo_ptr; reqd_len_sb_in = req->cmd_req_len + req->resp_len; /* find app_id & img_name from list */ Loading @@ -2734,7 +2854,6 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, } if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND; send_data_req.app_id = data->client.app_id; send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( data, (uintptr_t)req->cmd_req_buf)); Loading @@ -2742,11 +2861,14 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, send_data_req.rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( data, (uintptr_t)req->resp_buf)); send_data_req.rsp_len = req->resp_len; send_data_req.sglistinfo_ptr = (uint32_t)virt_to_phys(table); send_data_req.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); cmd_buf = (void *)&send_data_req; cmd_len = sizeof(struct qseecom_client_send_data_ireq); } else { send_data_req_64bit.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND; send_data_req_64bit.app_id = data->client.app_id; send_data_req_64bit.req_ptr = __qseecom_uvirt_to_kphys(data, (uintptr_t)req->cmd_req_buf); Loading @@ -2768,10 +2890,20 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, send_data_req_64bit.rsp_len); return -EFAULT; } send_data_req_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table); send_data_req_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); cmd_buf = (void *)&send_data_req_64bit; cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq); } if (qseecom.whitelist_support == false) *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND; else *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST; msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, reqd_len_sb_in, Loading Loading @@ -3025,14 +3157,26 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, goto err; } } if (cleanup) if (cleanup) { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_INV_CACHES); else } else { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_CLEAN_INV_CACHES); if (data->type == QSEECOM_CLIENT_APP) { data->sglistinfo_ptr[i].indexAndFlags = SGLISTINFO_SET_INDEX_FLAG( (sg_ptr->nents == 1), 0, req->ifd_data[i].cmd_buf_offset); data->sglistinfo_ptr[i].sizeOrCount = (sg_ptr->nents == 1) ? sg->length : sg_ptr->nents; data->sglist_cnt = i + 1; } } /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); Loading Loading @@ -3231,14 +3375,25 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, } } cleanup: if (cleanup) if (cleanup) { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_INV_CACHES); else } else { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, len, ION_IOC_CLEAN_INV_CACHES); if (data->type == QSEECOM_CLIENT_APP) { data->sglistinfo_ptr[i].indexAndFlags = SGLISTINFO_SET_INDEX_FLAG( (sg_ptr->nents == 1), 1, req->ifd_data[i].cmd_buf_offset); data->sglistinfo_ptr[i].sizeOrCount = (sg_ptr->nents == 1) ? sg->length : sg_ptr->nents; data->sglist_cnt = i + 1; } } /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); Loading Loading @@ -5897,14 +6052,23 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req, *update = (uint32_t)sg_dma_address(sg_ptr->sgl); } clean: if (cleanup) if (cleanup) { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, sg->length, ION_IOC_INV_CACHES); else } else { msm_ion_do_cache_op(qseecom.ion_clnt, ihandle, NULL, sg->length, ION_IOC_CLEAN_INV_CACHES); data->sglistinfo_ptr[i].indexAndFlags = SGLISTINFO_SET_INDEX_FLAG( (sg_ptr->nents == 1), 0, req->ifd_data[i].cmd_buf_offset); data->sglistinfo_ptr[i].sizeOrCount = (sg_ptr->nents == 1) ? sg->length : sg_ptr->nents; data->sglist_cnt = i + 1; } /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); Loading @@ -5929,6 +6093,7 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, uint32_t reqd_len_sb_in = 0; void *cmd_buf = NULL; size_t cmd_len; struct sglist_info *table = data->sglistinfo_ptr; ret = __qseecom_qteec_validate_msg(data, req); if (ret) Loading @@ -5951,8 +6116,15 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, return -ENOENT; } if ((cmd_id == QSEOS_TEE_OPEN_SESSION) || (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) { ret = __qseecom_update_qteec_req_buf( (struct qseecom_qteec_modfd_req *)req, data, false); if (ret) return ret; } if (qseecom.qsee_version < QSEE_VERSION_40) { ireq.qsee_cmd_id = cmd_id; ireq.app_id = data->client.app_id; ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req->req_ptr); Loading @@ -5960,10 +6132,13 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req->resp_ptr); ireq.resp_len = req->resp_len; ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table); ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); cmd_buf = (void *)&ireq; cmd_len = sizeof(struct qseecom_qteec_ireq); } else { ireq_64bit.qsee_cmd_id = cmd_id; ireq_64bit.app_id = data->client.app_id; ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req->req_ptr); Loading @@ -5983,17 +6158,19 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, ireq_64bit.resp_ptr, ireq_64bit.resp_len); return -EFAULT; } ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table); ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); cmd_buf = (void *)&ireq_64bit; cmd_len = sizeof(struct qseecom_qteec_64bit_ireq); } if (qseecom.whitelist_support == true && cmd_id == QSEOS_TEE_OPEN_SESSION) *(uint32_t *)cmd_buf = QSEOS_TEE_OPEN_SESSION_WHITELIST; else *(uint32_t *)cmd_buf = cmd_id; if ((cmd_id == QSEOS_TEE_OPEN_SESSION) || (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) { ret = __qseecom_update_qteec_req_buf( (struct qseecom_qteec_modfd_req *)req, data, false); if (ret) return ret; } reqd_len_sb_in = req->req_len + req->resp_len; msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, Loading Loading @@ -6091,6 +6268,9 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, uint32_t reqd_len_sb_in = 0; void *cmd_buf = NULL; size_t cmd_len; struct sglist_info *table = data->sglistinfo_ptr; void *req_ptr = NULL; void *resp_ptr = NULL; ret = copy_from_user(&req, argp, sizeof(struct qseecom_qteec_modfd_req)); Loading @@ -6102,6 +6282,8 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, (struct qseecom_qteec_req *)(&req)); if (ret) return ret; req_ptr = req.req_ptr; resp_ptr = req.resp_ptr; /* find app_id & img_name from list */ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags); Loading @@ -6120,45 +6302,56 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, return -ENOENT; } /* validate offsets */ for (i = 0; i < MAX_ION_FD; i++) { if (req.ifd_data[i].fd) { if (req.ifd_data[i].cmd_buf_offset >= req.req_len) return -EINVAL; } } req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req.req_ptr); req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req.resp_ptr); ret = __qseecom_update_qteec_req_buf(&req, data, false); if (ret) return ret; if (qseecom.qsee_version < QSEE_VERSION_40) { ireq.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND; ireq.app_id = data->client.app_id; ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req.req_ptr); (uintptr_t)req_ptr); ireq.req_len = req.req_len; ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req.resp_ptr); (uintptr_t)resp_ptr); ireq.resp_len = req.resp_len; cmd_buf = (void *)&ireq; cmd_len = sizeof(struct qseecom_qteec_ireq); ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table); ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); } else { ireq_64bit.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND; ireq_64bit.app_id = data->client.app_id; ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req.req_ptr); (uintptr_t)req_ptr); ireq_64bit.req_len = req.req_len; ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data, (uintptr_t)req.resp_ptr); (uintptr_t)resp_ptr); ireq_64bit.resp_len = req.resp_len; cmd_buf = (void *)&ireq_64bit; cmd_len = sizeof(struct qseecom_qteec_64bit_ireq); ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table); ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE; dmac_flush_range((void *)table, (void *)table + SGLISTINFO_TABLE_SIZE); } reqd_len_sb_in = req.req_len + req.resp_len; if (qseecom.whitelist_support == true) *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND_WHITELIST; else *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND; /* validate offsets */ for (i = 0; i < MAX_ION_FD; i++) { if (req.ifd_data[i].fd) { if (req.ifd_data[i].cmd_buf_offset >= req.req_len) return -EINVAL; } } req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req.req_ptr); req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req.resp_ptr); ret = __qseecom_update_qteec_req_buf(&req, data, false); if (ret) return ret; msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle, data->client.sb_virt, reqd_len_sb_in, Loading Loading @@ -6221,6 +6414,15 @@ static int qseecom_qteec_request_cancellation(struct qseecom_dev_handle *data, return ret; } static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data) { if (data->sglist_cnt) { memset(data->sglistinfo_ptr, 0, SGLISTINFO_TABLE_SIZE); data->sglist_cnt = 0; } } long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) { int ret = 0; Loading Loading @@ -6400,6 +6602,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed qseecom_send_cmd: %d\n", ret); __qseecom_clean_data_sglistinfo(data); break; } case QSEECOM_IOCTL_RECEIVE_REQ: { Loading Loading @@ -6797,6 +7000,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed open_session_cmd: %d\n", ret); __qseecom_clean_data_sglistinfo(data); break; } case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ: { Loading Loading @@ -6845,6 +7049,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) mutex_unlock(&app_access_lock); if (ret) pr_err("failed Invoke cmd: %d\n", ret); __qseecom_clean_data_sglistinfo(data); break; } case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ: { Loading Loading @@ -6921,6 +7126,9 @@ static int qseecom_open(struct inode *inode, struct file *file) init_waitqueue_head(&data->abort_wq); atomic_set(&data->ioctl_count, 0); data->sglistinfo_ptr = kzalloc(SGLISTINFO_TABLE_SIZE, GFP_KERNEL); if (!(data->sglistinfo_ptr)) return -ENOMEM; return ret; } Loading Loading @@ -6975,6 +7183,7 @@ static int qseecom_release(struct inode *inode, struct file *file) if (data->perf_enabled == true) qsee_disable_clock_vote(data, CLK_DFAB); } kfree(data->sglistinfo_ptr); kfree(data); return ret; Loading Loading @@ -7722,6 +7931,74 @@ out: return ret; } /* * Check if whitelist feature is supported by making a test scm_call * to send a whitelist command to an invalid app ID 0 */ static int qseecom_check_whitelist_feature(void) { struct qseecom_client_send_data_ireq send_data_req = {0}; struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0}; struct qseecom_command_scm_resp resp; uint32_t buf_size = 128; void *buf = NULL; void *cmd_buf = NULL; size_t cmd_len; int ret = 0; phys_addr_t pa; buf = kzalloc(buf_size, GFP_KERNEL); if (!buf) return -ENOMEM; pa = virt_to_phys(buf); if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST; send_data_req.app_id = 0; send_data_req.req_ptr = (uint32_t)pa; send_data_req.req_len = buf_size; send_data_req.rsp_ptr = (uint32_t)pa; send_data_req.rsp_len = buf_size; send_data_req.sglistinfo_ptr = (uint32_t)pa; send_data_req.sglistinfo_len = buf_size; cmd_buf = (void *)&send_data_req; cmd_len = sizeof(struct qseecom_client_send_data_ireq); } else { send_data_req_64bit.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST; send_data_req_64bit.app_id = 0; send_data_req_64bit.req_ptr = (uint64_t)pa; send_data_req_64bit.req_len = buf_size; send_data_req_64bit.rsp_ptr = (uint64_t)pa; send_data_req_64bit.rsp_len = buf_size; send_data_req_64bit.sglistinfo_ptr = (uint64_t)pa; send_data_req_64bit.sglistinfo_len = buf_size; cmd_buf = (void *)&send_data_req_64bit; cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq); } ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len, &resp, sizeof(resp)); /* * If this cmd exists and whitelist is supported, scm_call return -2 (scm * driver remap it to -EINVAL) and resp.result 0xFFFFFFED(-19); Otherwise, * scm_call return -1 (remap to -EIO). */ if (ret == -EIO) { qseecom.whitelist_support = false; ret = 0; } else if (ret == -EINVAL && resp.result == QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD) { qseecom.whitelist_support = true; ret = 0; } else { pr_err("Failed to check whitelist: ret = %d, result = 0x%x\n", ret, resp.result); } kfree(buf); return ret; } static int qseecom_probe(struct platform_device *pdev) { int rc; Loading Loading @@ -7754,6 +8031,7 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.app_block_ref_cnt = 0; init_waitqueue_head(&qseecom.app_block_wq); qseecom.whitelist_support = true; rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV); if (rc < 0) { Loading Loading @@ -7969,6 +8247,14 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.qsee_perf_client = msm_bus_scale_register_client( qseecom_platform_support); rc = qseecom_check_whitelist_feature(); if (rc) { rc = -EINVAL; goto exit_destroy_ion_client; } pr_warn("qseecom.whitelist_support = %d\n", qseecom.whitelist_support); if (!qseecom.qsee_perf_client) pr_err("Unable to register bus client\n"); Loading
include/soc/qcom/qseecomi.h +46 −1 Original line number Diff line number Diff line /* * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading @@ -18,6 +18,7 @@ #define QSEECOM_KEY_ID_SIZE 32 #define QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD -19 /*0xFFFFFFED*/ #define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63 #define QSEOS_RESULT_FAIL_KS_OP -64 #define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -65 Loading Loading @@ -64,6 +65,9 @@ enum qseecom_qceos_cmd_id { QSEOS_TEE_REQUEST_CANCELLATION, QSEOS_CONTINUE_BLOCKED_REQ_COMMAND, QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND = 0x1B, QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST = 0x1C, QSEOS_TEE_OPEN_SESSION_WHITELIST = 0x1D, QSEOS_TEE_INVOKE_COMMAND_WHITELIST = 0x1E, QSEOS_FSM_LTEOTA_REQ_CMD = 0x109, QSEOS_FSM_LTEOTA_REQ_RSP_CMD = 0x110, QSEOS_FSM_IKE_REQ_CMD = 0x203, Loading Loading @@ -181,6 +185,8 @@ __packed struct qseecom_client_send_data_ireq { uint32_t req_len; uint32_t rsp_ptr;/* First 4 bytes should be the return status */ uint32_t rsp_len; uint32_t sglistinfo_ptr; uint32_t sglistinfo_len; }; __packed struct qseecom_client_send_data_64bit_ireq { Loading @@ -190,6 +196,8 @@ __packed struct qseecom_client_send_data_64bit_ireq { uint32_t req_len; uint64_t rsp_ptr; uint32_t rsp_len; uint64_t sglistinfo_ptr; uint32_t sglistinfo_len; }; __packed struct qseecom_reg_log_buf_ireq { Loading Loading @@ -292,6 +300,8 @@ __packed struct qseecom_qteec_ireq { uint32_t req_len; uint32_t resp_ptr; uint32_t resp_len; uint32_t sglistinfo_ptr; uint32_t sglistinfo_len; }; __packed struct qseecom_qteec_64bit_ireq { Loading @@ -301,6 +311,8 @@ __packed struct qseecom_qteec_64bit_ireq { uint32_t req_len; uint64_t resp_ptr; uint32_t resp_len; uint64_t sglistinfo_ptr; uint32_t sglistinfo_len; }; __packed struct qseecom_client_send_fsm_key_req { Loading Loading @@ -658,4 +670,37 @@ __packed struct qseecom_continue_blocked_request_ireq { #define TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_1(TZ_SYSCALL_PARAM_TYPE_VAL) #define TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID \ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \ TZ_SVC_APP_ID_PLACEHOLDER, 0x06) #define TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_7( \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL) #define TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID \ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \ TZ_SVC_APP_ID_PLACEHOLDER, 0x07) #define TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_7( \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL) #define TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID \ TZ_SYSCALL_CREATE_SMC_ID(TZ_OWNER_TZ_APPS, \ TZ_SVC_APP_ID_PLACEHOLDER, 0x09) #define TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID \ TZ_SYSCALL_CREATE_PARAM_ID_7( \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL, TZ_SYSCALL_PARAM_TYPE_BUF_RW, \ TZ_SYSCALL_PARAM_TYPE_VAL) #endif /* __QSEECOMI_H_ */