diff options
| author | Rygebin <kaankulahli@gmail.com> | 2017-06-20 14:29:27 +0000 |
|---|---|---|
| committer | Rygebin <kaankulahli@gmail.com> | 2017-06-20 14:29:27 +0000 |
| commit | afa9ad70f02491fbe10df2203f8f2fa42f956228 (patch) | |
| tree | b6dce4ed04f62fd443721a94ac3e7f81427e0ad1 /drivers/misc | |
| parent | 582eb92a1e8bf6c0e743774c1fb550e630715433 (diff) | |
| parent | 08d1ec9238c605a9a5cf1229fd60961efcd21ff1 (diff) | |
Diffstat (limited to 'drivers/misc')
| -rw-r--r-- | drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c | 81 | ||||
| -rw-r--r-- | drivers/misc/qseecom.c | 666 |
2 files changed, 556 insertions, 191 deletions
diff --git a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c index ec3b5c2d8d2..166601e22db 100644 --- a/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c +++ b/drivers/misc/qcom/qdsp6v2/audio_hwacc_effects.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -17,7 +17,6 @@ #include "q6audio_common.h" #include "audio_utils_aio.h" #include <sound/msm-audio-effects-q6-v2.h> -#include <sound/msm-dts-eagle.h> #define MAX_CHANNELS_SUPPORTED 8 #define WAIT_TIMEDOUT_DURATION_SECS 1 @@ -29,6 +28,8 @@ struct q6audio_effects { struct audio_client *ac; struct msm_hwacc_effects_config config; + struct mutex lock; + atomic_t in_count; atomic_t out_count; @@ -51,31 +52,11 @@ static void audio_effects_init_pp(struct audio_client *ac) pr_err("%s: audio client null to init pp\n", __func__); return; } - switch (ac->topology) { - case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER: - - ret = q6asm_set_softvolume_v2(ac, &softvol, - SOFT_VOLUME_INSTANCE_1); - if (ret < 0) - pr_err("%s: Send SoftVolume1 Param failed ret=%d\n", - __func__, ret); - ret = q6asm_set_softvolume_v2(ac, &softvol, - SOFT_VOLUME_INSTANCE_2); - if (ret < 0) - pr_err("%s: Send SoftVolume2 Param failed ret=%d\n", - __func__, ret); - - msm_dts_eagle_init_master_module(ac); - - break; - default: - ret = q6asm_set_softvolume_v2(ac, &softvol, - SOFT_VOLUME_INSTANCE_1); - if (ret < 0) - pr_err("%s: Send SoftVolume Param failed ret=%d\n", - __func__, ret); - break; - } + ret = q6asm_set_softvolume_v2(ac, &softvol, + SOFT_VOLUME_INSTANCE_1); + if (ret < 0) + pr_err("%s: Send SoftVolume Param failed ret=%d\n", + __func__, ret); } static void audio_effects_deinit_pp(struct audio_client *ac) @@ -84,13 +65,6 @@ static void audio_effects_deinit_pp(struct audio_client *ac) pr_err("%s: audio client null to deinit pp\n", __func__); return; } - switch (ac->topology) { - case ASM_STREAM_POSTPROC_TOPO_ID_HPX_MASTER: - msm_dts_eagle_deinit_master_module(ac); - break; - default: - break; - } } static void audio_effects_event_handler(uint32_t opcode, uint32_t token, @@ -230,8 +204,11 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, uint32_t idx = 0; uint32_t size = 0; + mutex_lock(&effects->lock); + if (!effects->started) { rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } @@ -241,11 +218,13 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, if (!rc) { pr_err("%s: write wait_event_timeout\n", __func__); rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } if (!atomic_read(&effects->out_count)) { pr_err("%s: pcm stopped out_count 0\n", __func__); rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } @@ -254,6 +233,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, if (copy_from_user(bufptr, (void *)arg, effects->config.buf_cfg.output_len)) { rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } rc = q6asm_write(effects->ac, @@ -261,6 +241,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, 0, 0, NO_TIMESTAMP); if (rc < 0) { rc = -EFAULT; + mutex_unlock(&effects->lock); goto ioctl_fail; } atomic_dec(&effects->out_count); @@ -268,6 +249,7 @@ static int audio_effects_shared_ioctl(struct file *file, unsigned cmd, pr_err("%s: AUDIO_EFFECTS_WRITE: Buffer dropped\n", __func__); } + mutex_unlock(&effects->lock); break; } case AUDIO_EFFECTS_READ: { @@ -400,33 +382,6 @@ static long audio_effects_set_pp_param(struct q6audio_effects *effects, &(effects->audio_effects.topo_switch_vol), (long *)&values[1], SOFT_VOLUME_INSTANCE_2); break; - case DTS_EAGLE_MODULE_ENABLE: - pr_debug("%s: DTS_EAGLE_MODULE_ENABLE\n", __func__); - if (msm_audio_effects_is_effmodule_supp_in_top( - effects_module, effects->ac->topology)) { - /* - * HPX->OFF: first disable HPX and then - * enable SA+ - * HPX->ON: first disable SA+ and then - * enable HPX - */ - bool hpx_state = (bool)values[1]; - if (hpx_state) - msm_audio_effects_enable_extn(effects->ac, - &(effects->audio_effects), - false); - msm_dts_eagle_enable_asm(effects->ac, - hpx_state, - AUDPROC_MODULE_ID_DTS_HPX_PREMIX); - msm_dts_eagle_enable_asm(effects->ac, - hpx_state, - AUDPROC_MODULE_ID_DTS_HPX_POSTMIX); - if (!hpx_state) - msm_audio_effects_enable_extn(effects->ac, - &(effects->audio_effects), - true); - } - break; default: pr_err("%s: Invalid effects config module\n", __func__); rc = -EINVAL; @@ -464,6 +419,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd, break; } case AUDIO_EFFECTS_SET_BUF_LEN: { + mutex_lock(&effects->lock); if (copy_from_user(&effects->config.buf_cfg, (void *)arg, sizeof(effects->config.buf_cfg))) { pr_err("%s: copy from user for AUDIO_EFFECTS_SET_BUF_LEN failed\n", @@ -473,6 +429,7 @@ static long audio_effects_ioctl(struct file *file, unsigned int cmd, pr_debug("%s: write buf len: %d, read buf len: %d\n", __func__, effects->config.buf_cfg.output_len, effects->config.buf_cfg.input_len); + mutex_unlock(&effects->lock); break; } case AUDIO_EFFECTS_GET_BUF_AVAIL: { @@ -717,6 +674,7 @@ static int audio_effects_release(struct inode *inode, struct file *file) } q6asm_audio_client_free(effects->ac); + mutex_destroy(&effects->lock); kfree(effects); pr_debug("%s: close session success\n", __func__); @@ -747,6 +705,7 @@ static int audio_effects_open(struct inode *inode, struct file *file) init_waitqueue_head(&effects->read_wait); init_waitqueue_head(&effects->write_wait); + mutex_init(&effects->lock); effects->opened = 0; effects->started = 0; diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index b228952f554..79f5c7843fd 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -1,6 +1,6 @@ /*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver * - * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2017, 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 @@ -78,6 +78,9 @@ /* Encrypt/Decrypt Data Integrity Partition (DIP) for MDTP */ #define SCM_MDTP_CIPHER_DIP 0x01 +/* Maximum Allowed Size (128K) of Data Integrity Partition (DIP) for MDTP */ +#define MAX_DIP 0x20000 + #define RPMB_SERVICE 0x2000 #define SSD_SERVICE 0x3000 @@ -116,6 +119,35 @@ static DEFINE_MUTEX(qsee_bw_mutex); static DEFINE_MUTEX(app_access_lock); static DEFINE_MUTEX(clk_access_lock); +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) + +#define FEATURE_ID_WHITELIST 15 /*whitelist feature id*/ + +#define MAKE_WHITELIST_VERSION(major, minor, patch) \ + (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF)) + struct qseecom_registered_listener_list { struct list_head list; struct qseecom_register_listener_req svc; @@ -130,6 +162,8 @@ struct qseecom_registered_listener_list { bool listener_in_use; /* wq for thread blocked on this listener*/ wait_queue_head_t listener_block_app_wq; + struct sglist_info sglistinfo_ptr[MAX_ION_FD]; + uint32_t sglist_cnt; }; struct qseecom_registered_app_list { @@ -181,6 +215,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; @@ -254,6 +289,9 @@ struct qseecom_dev_handle { bool perf_enabled; bool fast_load_enabled; enum qseecom_bandwidth_request_mode mode; + struct sglist_info sglistinfo_ptr[MAX_ION_FD]; + uint32_t sglist_cnt; + bool use_legacy_cmd; }; struct qseecom_key_id_usage_desc { @@ -513,6 +551,34 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id, ret = scm_call2(smc_id, &desc); break; } + case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: { + struct qseecom_client_listener_data_irsp *req; + struct qseecom_client_listener_data_64bit_irsp *req_64; + + smc_id = + TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_ID; + desc.arginfo = + TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_PARAM_ID; + if (qseecom.qsee_version < QSEE_VERSION_40) { + req = + (struct qseecom_client_listener_data_irsp *) + req_buf; + desc.args[0] = req->listener_id; + desc.args[1] = req->status; + desc.args[2] = req->sglistinfo_ptr; + desc.args[3] = req->sglistinfo_len; + } else { + req_64 = + (struct qseecom_client_listener_data_64bit_irsp *) + req_buf; + desc.args[0] = req_64->listener_id; + desc.args[1] = req_64->status; + desc.args[2] = req_64->sglistinfo_ptr; + desc.args[3] = req_64->sglistinfo_len; + } + ret = scm_call2(smc_id, &desc); + break; + } case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: { struct qseecom_load_app_ireq *req; struct qseecom_load_app_64bit_ireq *req_64bit; @@ -568,6 +634,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 *) @@ -695,6 +793,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; @@ -719,6 +847,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; @@ -946,7 +1104,7 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, return -EBUSY; } - new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL); + new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL); if (!new_entry) { pr_err("kmalloc failed\n"); return -ENOMEM; @@ -1398,6 +1556,16 @@ static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data, return ret; } +static void __qseecom_clean_listener_sglistinfo( + struct qseecom_registered_listener_list *ptr_svc) +{ + if (ptr_svc->sglist_cnt) { + memset(ptr_svc->sglistinfo_ptr, 0, + SGLISTINFO_TABLE_SIZE); + ptr_svc->sglist_cnt = 0; + } +} + static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, struct qseecom_command_scm_resp *resp) { @@ -1406,9 +1574,14 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, uint32_t lstnr; unsigned long flags; struct qseecom_client_listener_data_irsp send_data_rsp; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; + uint32_t status; + void *cmd_buf = NULL; + size_t cmd_len; + struct sglist_info *table = NULL; while (resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; @@ -1420,6 +1593,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head, list) { if (ptr_svc->svc.listener_id == lstnr) { + ptr_svc->listener_in_use = true; ptr_svc->rcv_req_flag = 1; wake_up_interruptible(&ptr_svc->rcv_req_wq); break; @@ -1467,14 +1641,42 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; - send_data_rsp.status = QSEOS_RESULT_FAILURE; + status = QSEOS_RESULT_FAILURE; } else { - send_data_rsp.status = QSEOS_RESULT_SUCCESS; + status = QSEOS_RESULT_SUCCESS; } qseecom.send_resp_flag = 0; - send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND; - send_data_rsp.listener_id = lstnr; + ptr_svc->send_resp_flag = 0; + table = ptr_svc->sglistinfo_ptr; + if (qseecom.qsee_version < QSEE_VERSION_40) { + send_data_rsp.listener_id = lstnr; + send_data_rsp.status = status; + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + cmd_buf = (void *)&send_data_rsp; + cmd_len = sizeof(send_data_rsp); + } else { + send_data_rsp_64bit.listener_id = lstnr; + send_data_rsp_64bit.status = status; + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + cmd_buf = (void *)&send_data_rsp_64bit; + cmd_len = sizeof(send_data_rsp_64bit); + } + if (qseecom.whitelist_support == false) + *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; + else + *(uint32_t *)cmd_buf = + QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; if (ptr_svc) msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, @@ -1484,9 +1686,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data, __qseecom_enable_clk(CLK_QSEE); ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, - (const void *)&send_data_rsp, - sizeof(send_data_rsp), resp, - sizeof(*resp)); + cmd_buf, cmd_len, resp, sizeof(*resp)); + ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); if (ret) { pr_err("scm_call() failed with err: %d (app_id = %d)\n", ret, data->client.app_id); @@ -1519,9 +1721,14 @@ static int __qseecom_reentrancy_process_incomplete_cmd( uint32_t lstnr; unsigned long flags; struct qseecom_client_listener_data_irsp send_data_rsp; + struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit; struct qseecom_registered_listener_list *ptr_svc = NULL; sigset_t new_sigset; sigset_t old_sigset; + uint32_t status; + void *cmd_buf = NULL; + size_t cmd_len; + struct sglist_info *table = NULL; while (resp->result == QSEOS_RESULT_INCOMPLETE) { lstnr = resp->data; @@ -1585,13 +1792,38 @@ static int __qseecom_reentrancy_process_incomplete_cmd( pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d", data->client.app_id, lstnr, ret); rc = -ENODEV; - send_data_rsp.status = QSEOS_RESULT_FAILURE; + status = QSEOS_RESULT_FAILURE; } else { - send_data_rsp.status = QSEOS_RESULT_SUCCESS; + status = QSEOS_RESULT_SUCCESS; } - - send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND; - send_data_rsp.listener_id = lstnr; + table = ptr_svc->sglistinfo_ptr; + if (qseecom.qsee_version < QSEE_VERSION_40) { + send_data_rsp.listener_id = lstnr; + send_data_rsp.status = status; + send_data_rsp.sglistinfo_ptr = + (uint32_t)virt_to_phys(table); + send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + cmd_buf = (void *)&send_data_rsp; + cmd_len = sizeof(send_data_rsp); + } else { + send_data_rsp_64bit.listener_id = lstnr; + send_data_rsp_64bit.status = status; + send_data_rsp_64bit.sglistinfo_ptr = + virt_to_phys(table); + send_data_rsp_64bit.sglistinfo_len = + SGLISTINFO_TABLE_SIZE; + dmac_flush_range((void *)table, + (void *)table + SGLISTINFO_TABLE_SIZE); + cmd_buf = (void *)&send_data_rsp_64bit; + cmd_len = sizeof(send_data_rsp_64bit); + } + if (qseecom.whitelist_support == false) + *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND; + else + *(uint32_t *)cmd_buf = + QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST; if (ptr_svc) msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle, ptr_svc->sb_virt, ptr_svc->sb_length, @@ -1601,11 +1833,9 @@ static int __qseecom_reentrancy_process_incomplete_cmd( __qseecom_enable_clk(CLK_QSEE); ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, - (const void *)&send_data_rsp, - sizeof(send_data_rsp), resp, - sizeof(*resp)); - + cmd_buf, cmd_len, resp, sizeof(*resp)); ptr_svc->listener_in_use = false; + __qseecom_clean_listener_sglistinfo(ptr_svc); wake_up_interruptible(&ptr_svc->listener_block_app_wq); if (ret) { @@ -2134,11 +2364,6 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr, return -EINVAL; } - if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) { - pr_err("Invalid req/resp buffer, exiting\n"); - return -EINVAL; - } - /* Clients need to ensure req_buf is at base offset of shared buffer */ if ((uintptr_t)req_ptr->cmd_req_buf != data_ptr->client.user_virt_sb_base) { @@ -2146,15 +2371,11 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr, return -EINVAL; } - if (((uintptr_t)req_ptr->resp_buf < - data_ptr->client.user_virt_sb_base) || - ((uintptr_t)req_ptr->resp_buf >= - (data_ptr->client.user_virt_sb_base + - data_ptr->client.sb_length))){ - pr_err("response buffer address not within shared bufffer\n"); + if (data_ptr->client.sb_length < + sizeof(struct qseecom_rpmb_provision_key)) { + pr_err("shared buffer is too small to hold key type\n"); return -EINVAL; } - req_buf = data_ptr->client.sb_virt; send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id; @@ -2181,36 +2402,6 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr, return -EINVAL; } - if (((uintptr_t)req_ptr->cmd_req_buf < - data_ptr->client.user_virt_sb_base) || - ((uintptr_t)req_ptr->cmd_req_buf >= - (data_ptr->client.user_virt_sb_base + - data_ptr->client.sb_length))) { - pr_err("cmd buffer address not within shared bufffer\n"); - return -EINVAL; - } - - if (((uintptr_t)req_ptr->resp_buf < - data_ptr->client.user_virt_sb_base) || - ((uintptr_t)req_ptr->resp_buf >= - (data_ptr->client.user_virt_sb_base + - data_ptr->client.sb_length))){ - pr_err("response buffer address not within shared bufffer\n"); - return -EINVAL; - } - - if ((req_ptr->cmd_req_len == 0) || (req_ptr->resp_len == 0) || - req_ptr->cmd_req_len > data_ptr->client.sb_length || - req_ptr->resp_len > data_ptr->client.sb_length) { - pr_err("cmd buffer length or response buffer length not valid\n"); - return -EINVAL; - } - - if (req_ptr->cmd_req_len > UINT_MAX - req_ptr->resp_len) { - pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n"); - return -EINVAL; - } - reqd_len_sb_in = req_ptr->cmd_req_len + req_ptr->resp_len; if (reqd_len_sb_in > data_ptr->client.sb_length) { pr_err("Not enough memory to fit cmd_buf and resp_buf. "); @@ -2232,28 +2423,11 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr, return ret; } -static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, - void __user *argp) +static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data, + struct qseecom_send_svc_cmd_req *req) { - int ret = 0; - struct qseecom_client_send_service_ireq send_svc_ireq; - struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq; - struct qseecom_command_scm_resp resp; - struct qseecom_send_svc_cmd_req req; - void *send_req_ptr; - size_t req_buf_size; - - /*struct qseecom_command_scm_resp resp;*/ - - if (copy_from_user(&req, - (void __user *)argp, - sizeof(req))) { - pr_err("copy_from_user failed\n"); - return -EFAULT; - } - - if ((req.resp_buf == NULL) || (req.cmd_req_buf == NULL)) { - pr_err("cmd buffer or response buffer is null\n"); + if (!req || !req->resp_buf || !req->cmd_req_buf) { + pr_err("req or cmd buffer or response buffer is null\n"); return -EINVAL; } @@ -2277,6 +2451,86 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, return -EINVAL; } + if (((uintptr_t)req->cmd_req_buf < + data->client.user_virt_sb_base) || + ((uintptr_t)req->cmd_req_buf >= + (data->client.user_virt_sb_base + data->client.sb_length))) { + pr_err("cmd buffer address not within shared bufffer\n"); + return -EINVAL; + } + if (((uintptr_t)req->resp_buf < + data->client.user_virt_sb_base) || + ((uintptr_t)req->resp_buf >= + (data->client.user_virt_sb_base + data->client.sb_length))) { + pr_err("response buffer address not within shared bufffer\n"); + return -EINVAL; + } + if ((req->cmd_req_len == 0) || (req->resp_len == 0) || + (req->cmd_req_len > data->client.sb_length) || + (req->resp_len > data->client.sb_length)) { + pr_err("cmd buf length or response buf length not valid\n"); + return -EINVAL; + } + if (req->cmd_req_len > UINT_MAX - req->resp_len) { + pr_err("Integer overflow detected in req_len & rsp_len\n"); + return -EINVAL; + } + + if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) { + pr_debug("Not enough memory to fit cmd_buf.\n"); + pr_debug("resp_buf. Required: %u, Available: %zu\n", + (req->cmd_req_len + req->resp_len), + data->client.sb_length); + return -ENOMEM; + } + if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) { + pr_err("Integer overflow in req_len & cmd_req_buf\n"); + return -EINVAL; + } + if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) { + pr_err("Integer overflow in resp_len & resp_buf\n"); + return -EINVAL; + } + if (data->client.user_virt_sb_base > + (ULONG_MAX - data->client.sb_length)) { + pr_err("Integer overflow in user_virt_sb_base & sb_length\n"); + return -EINVAL; + } + if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) > + ((uintptr_t)data->client.user_virt_sb_base + + data->client.sb_length)) || + (((uintptr_t)req->resp_buf + req->resp_len) > + ((uintptr_t)data->client.user_virt_sb_base + + data->client.sb_length))) { + pr_err("cmd buf or resp buf is out of shared buffer region\n"); + return -EINVAL; + } + return 0; +} + +static int qseecom_send_service_cmd(struct qseecom_dev_handle *data, + void __user *argp) +{ + int ret = 0; + struct qseecom_client_send_service_ireq send_svc_ireq; + struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq; + struct qseecom_command_scm_resp resp; + struct qseecom_send_svc_cmd_req req; + void *send_req_ptr; + size_t req_buf_size; + + /*struct qseecom_command_scm_resp resp;*/ + + if (copy_from_user(&req, + (void __user *)argp, + sizeof(req))) { + pr_err("copy_from_user failed\n"); + return -EFAULT; + } + + if (__validate_send_service_cmd_inputs(data, &req)) + return -EINVAL; + data->type = QSEECOM_SECURE_SERVICE; switch (req.cmd_id) { @@ -2528,8 +2782,8 @@ 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; @@ -2537,6 +2791,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, int name_len = 0; 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 */ @@ -2561,7 +2816,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)); @@ -2569,11 +2823,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); @@ -2595,10 +2852,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 || data->use_legacy_cmd == true) + *(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, @@ -2699,6 +2966,8 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, struct qseecom_send_modfd_cmd_req *req = NULL; struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL; struct qseecom_registered_listener_list *this_lstnr = NULL; + uint32_t offset; + struct sg_table *sg_ptr; if ((data->type != QSEECOM_LISTENER_SERVICE) && (data->type != QSEECOM_CLIENT_APP)) @@ -2720,7 +2989,6 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup, } for (i = 0; i < MAX_ION_FD; i++) { - struct sg_table *sg_ptr = NULL; if ((data->type != QSEECOM_LISTENER_SERVICE) && (req->ifd_data[i].fd > 0)) { ihandle = ion_import_dma_buf(qseecom.ion_clnt, @@ -2852,14 +3120,37 @@ 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) { + offset = req->ifd_data[i].cmd_buf_offset; + data->sglistinfo_ptr[i].indexAndFlags = + SGLISTINFO_SET_INDEX_FLAG( + (sg_ptr->nents == 1), 0, offset); + data->sglistinfo_ptr[i].sizeOrCount = + (sg_ptr->nents == 1) ? + sg->length : sg_ptr->nents; + data->sglist_cnt = i + 1; + } else { + offset = (lstnr_resp->ifd_data[i].cmd_buf_offset + + (uintptr_t)lstnr_resp->resp_buf_ptr - + (uintptr_t)this_lstnr->sb_virt); + this_lstnr->sglistinfo_ptr[i].indexAndFlags = + SGLISTINFO_SET_INDEX_FLAG( + (sg_ptr->nents == 1), 0, offset); + this_lstnr->sglistinfo_ptr[i].sizeOrCount = + (sg_ptr->nents == 1) ? + sg->length : sg_ptr->nents; + this_lstnr->sglist_cnt = i + 1; + } + } /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); @@ -2883,6 +3174,8 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, struct qseecom_send_modfd_cmd_req *req = NULL; struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL; struct qseecom_registered_listener_list *this_lstnr = NULL; + uint32_t offset; + struct sg_table *sg_ptr; if ((data->type != QSEECOM_LISTENER_SERVICE) && (data->type != QSEECOM_CLIENT_APP)) @@ -2904,7 +3197,6 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, } for (i = 0; i < MAX_ION_FD; i++) { - struct sg_table *sg_ptr = NULL; if ((data->type != QSEECOM_LISTENER_SERVICE) && (req->ifd_data[i].fd > 0)) { ihandle = ion_import_dma_buf(qseecom.ion_clnt, @@ -2994,14 +3286,36 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup, sg = sg_next(sg); } } - 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) { + offset = req->ifd_data[i].cmd_buf_offset; + data->sglistinfo_ptr[i].indexAndFlags = + SGLISTINFO_SET_INDEX_FLAG( + (sg_ptr->nents == 1), 1, offset); + data->sglistinfo_ptr[i].sizeOrCount = + (sg_ptr->nents == 1) ? + sg->length : sg_ptr->nents; + data->sglist_cnt = i + 1; + } else { + offset = (lstnr_resp->ifd_data[i].cmd_buf_offset + + (uintptr_t)lstnr_resp->resp_buf_ptr - + (uintptr_t)this_lstnr->sb_virt); + this_lstnr->sglistinfo_ptr[i].indexAndFlags = + SGLISTINFO_SET_INDEX_FLAG( + (sg_ptr->nents == 1), 1, offset); + this_lstnr->sglistinfo_ptr[i].sizeOrCount = + (sg_ptr->nents == 1) ? + sg->length : sg_ptr->nents; + this_lstnr->sglist_cnt = i + 1; + } + } /* Deallocate the handle */ if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); @@ -3195,7 +3509,7 @@ static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry) return true; } -static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size, +static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size, uint32_t *app_arch) { int ret = -1; @@ -3233,14 +3547,21 @@ static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size, } pr_debug("QSEE %s app, arch %u\n", appname, *app_arch); release_firmware(fw_entry); + fw_entry = NULL; for (i = 0; i < num_images; i++) { memset(fw_name, 0, sizeof(fw_name)); snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i); ret = request_firmware(&fw_entry, fw_name, qseecom.pdev); if (ret) goto err; + if (*fw_size > U32_MAX - fw_entry->size) { + pr_err("QSEE %s app file size overflow\n", appname); + ret = -EINVAL; + goto err; + } *fw_size += fw_entry->size; release_firmware(fw_entry); + fw_entry = NULL; } return ret; @@ -3251,8 +3572,9 @@ err: return ret; } -static int __qseecom_get_fw_data(char *appname, u8 *img_data, - struct qseecom_load_app_ireq *load_req) +static int __qseecom_get_fw_data(const char *appname, u8 *img_data, + uint32_t fw_size, + struct qseecom_load_app_ireq *load_req) { int ret = -1; int i = 0, rc = 0; @@ -3272,6 +3594,12 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data, } load_req->img_len = fw_entry->size; + if (load_req->img_len > fw_size) { + pr_err("app %s size %zu is larger than buf size %u\n", + appname, fw_entry->size, fw_size); + ret = -EINVAL; + goto err; + } memcpy(img_data_ptr, fw_entry->data, fw_entry->size); img_data_ptr = img_data_ptr + fw_entry->size; load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/ @@ -3290,6 +3618,7 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data, goto err; } release_firmware(fw_entry); + fw_entry = NULL; for (i = 0; i < num_images; i++) { snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i); ret = request_firmware(&fw_entry, fw_name, qseecom.pdev); @@ -3297,10 +3626,17 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data, pr_err("Failed to locate blob %s\n", fw_name); goto err; } + if ((fw_entry->size > U32_MAX - load_req->img_len) || + (fw_entry->size + load_req->img_len > fw_size)) { + pr_err("Invalid file size for %s\n", fw_name); + ret = -EINVAL; + goto err; + } memcpy(img_data_ptr, fw_entry->data, fw_entry->size); img_data_ptr = img_data_ptr + fw_entry->size; load_req->img_len += fw_entry->size; release_firmware(fw_entry); + fw_entry = NULL; } return ret; err: @@ -3405,7 +3741,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname) if (ret) return ret; - ret = __qseecom_get_fw_data(appname, img_data, &load_req); + ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req); if (ret) { ret = -EIO; goto exit_free_img_data; @@ -3526,7 +3862,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data, if (ret) return -EIO; - ret = __qseecom_get_fw_data(cmnlib_name, img_data, &load_req); + ret = __qseecom_get_fw_data(cmnlib_name, img_data, fw_size, &load_req); if (ret) { ret = -EIO; goto exit_free_img_data; @@ -3894,8 +4230,11 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, } perf_enabled = true; } + if (!strcmp(data->client.app_name, "securemm")) + data->use_legacy_cmd = true; ret = __qseecom_send_cmd(data, &req); + data->use_legacy_cmd = false; if (qseecom.support_bus_scaling) __qseecom_add_bw_scale_down_timer( QSEECOM_SEND_CMD_CRYPTO_TIMEOUT); @@ -5295,7 +5634,8 @@ static int qseecom_mdtp_cipher_dip(void __user *argp) } if (req.in_buf == NULL || req.out_buf == NULL || - req.in_buf_size == 0 || req.out_buf_size == 0 || + req.in_buf_size == 0 || req.in_buf_size > MAX_DIP || + req.out_buf_size == 0 || req.out_buf_size > MAX_DIP || req.direction > 1) { pr_err("invalid parameters\n"); ret = -EINVAL; @@ -5575,14 +5915,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); @@ -5607,6 +5956,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) @@ -5631,8 +5981,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); @@ -5640,10 +5997,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); @@ -5663,17 +6023,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, @@ -5771,6 +6133,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)); @@ -5782,6 +6147,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); @@ -5802,45 +6169,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, @@ -5903,6 +6281,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; @@ -6082,6 +6469,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: { @@ -6455,6 +6843,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg) wake_up_all(&data->abort_wq); if (ret) pr_err("failed qseecom_send_mod_resp: %d\n", ret); + __qseecom_clean_data_sglistinfo(data); break; } case QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ: { @@ -6479,6 +6868,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: { @@ -6527,6 +6917,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: { @@ -6578,7 +6969,6 @@ static int qseecom_open(struct inode *inode, struct file *file) data->mode = INACTIVE; init_waitqueue_head(&data->abort_wq); atomic_set(&data->ioctl_count, 0); - return ret; } @@ -6773,6 +7163,17 @@ static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce) qclk->instance = CLK_INVALID; } +/* + * Check whitelist feature, and if TZ feature version is < 1.0.0, + * then whitelist feature is not supported. + */ +static int qseecom_check_whitelist_feature(void) +{ + int version = scm_get_feat_version(FEATURE_ID_WHITELIST); + + return version >= MAKE_WHITELIST_VERSION(1, 0, 0); +} + static int qseecom_probe(struct platform_device *pdev) { int rc; @@ -6804,6 +7205,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) { @@ -7096,6 +7498,10 @@ static int qseecom_probe(struct platform_device *pdev) qseecom.qsee_perf_client = msm_bus_scale_register_client( qseecom_platform_support); + qseecom.whitelist_support = qseecom_check_whitelist_feature(); + pr_warn("qseecom.whitelist_support = %d\n", + qseecom.whitelist_support); + if (!qseecom.qsee_perf_client) pr_err("Unable to register bus client\n"); return 0; |
