summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohamed Sunfeer <msunfeer@codeaurora.org>2019-10-25 23:53:01 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2019-11-11 20:22:53 -0800
commit195b2497d11037a2cd921b9c8aa54907ac343d11 (patch)
treef259b19d09fa4b55f0cc490398b50bdaa0e0cd19
parent9fbd3acbf7d7c4d295f1f9fae508c097ba1dcc9c (diff)
qseecom: Fix compilation errors
While porting the changes from 4.9 kernel version to 4.4 version, there are few function prototype got changed which leads to compilation error, this patch fixes those errors by using the appropriate functions and added some definitions. Change-Id: I525e84f25912377cad72f72b6d451702f9afd2c6 Signed-off-by: Mohamed Sunfeer <msunfeer@codeaurora.org>
-rw-r--r--drivers/misc/qseecom.c1607
-rw-r--r--include/soc/qcom/qseecomi.h151
-rw-r--r--include/uapi/linux/qseecom.h5
3 files changed, 1108 insertions, 655 deletions
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index d50144e0fed9..21ad3dc3abaa 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,4 +1,5 @@
-/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
+/*
+ * QTI Secure Execution Environment Communicator (QSEECOM) driver
*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*
@@ -43,13 +44,13 @@
#include <linux/msm-bus-board.h>
#include <soc/qcom/qseecomi.h>
#include <asm/cacheflush.h>
-#include "qseecom_legacy.h"
#include "qseecom_kernel.h"
#include <crypto/ice.h>
#include <linux/delay.h>
#include <linux/compat.h>
#include "compat_qseecom.h"
+#include <linux/kthread.h>
#define QSEECOM_DEV "qseecom"
#define QSEOS_VERSION_14 0x14
@@ -65,7 +66,7 @@
#define QSEE_CE_CLK_100MHZ 100000000
#define CE_CLK_DIV 1000000
-#define QSEECOM_MAX_SG_ENTRY 512
+#define QSEECOM_MAX_SG_ENTRY 4096
#define QSEECOM_SG_ENTRY_MSG_BUF_SZ_64BIT \
(QSEECOM_MAX_SG_ENTRY * SG_ENTRY_SZ_64BIT)
@@ -100,6 +101,10 @@
#define QSEECOM_STATE_READY 2
#define QSEECOM_ICE_FDE_KEY_SIZE_MASK 2
+#define QSEECOM_SCM_EBUSY_WAIT_MS 30
+#define QSEECOM_SCM_EBUSY_MAX_RETRY 67
+#define QSEECOM_SCM_SECURE_WORLD_BUSY_COUNT 33
+
/*
* default ce info unit to 0 for
* services which
@@ -109,6 +114,9 @@
#define DEFAULT_CE_INFO_UNIT 0
#define DEFAULT_NUM_CE_INFO_UNIT 1
+#define FDE_FLAG_POS 4
+#define ENABLE_KEY_WRAP_IN_KS (1 << FDE_FLAG_POS)
+
enum qseecom_clk_definitions {
CLK_DFAB = 0,
CLK_SFPB,
@@ -137,12 +145,25 @@ enum qseecom_ce_hw_instance {
CLK_INVALID,
};
+enum qseecom_listener_unregister_kthread_state {
+ LSNR_UNREG_KT_SLEEP = 0,
+ LSNR_UNREG_KT_WAKEUP,
+};
+
+enum qseecom_unload_app_kthread_state {
+ UNLOAD_APP_KT_SLEEP = 0,
+ UNLOAD_APP_KT_WAKEUP,
+};
+
static struct class *driver_class;
static dev_t qseecom_device_no;
static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(clk_access_lock);
+static DEFINE_MUTEX(listener_access_lock);
+static DEFINE_MUTEX(unload_app_pending_list_lock);
+
struct sglist_info {
uint32_t indexAndFlags;
@@ -182,13 +203,21 @@ struct qseecom_registered_listener_list {
size_t sb_length;
struct ion_handle *ihandle; /* Retrieve phy addr */
wait_queue_head_t rcv_req_wq;
+ /* rcv_req_flag: 0: ready and empty; 1: received req */
int rcv_req_flag;
int send_resp_flag;
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 sglist_info sglistinfo_ptr[MAX_ION_FD];
+ uint32_t sglist_cnt;
+ int abort;
+ bool unregister_pending;
+};
+
+struct qseecom_unregister_pending_list {
+ struct list_head list;
+ struct qseecom_dev_handle *data;
};
struct qseecom_registered_app_list {
@@ -198,6 +227,7 @@ struct qseecom_registered_app_list {
char app_name[MAX_APP_NAME_SIZE];
u32 app_arch;
bool app_blocked;
+ u32 check_block;
u32 blocked_on_listener_id;
};
@@ -235,7 +265,6 @@ struct qseecom_clk {
struct qseecom_control {
struct ion_client *ion_clnt; /* Ion client */
struct list_head registered_listener_list_head;
- spinlock_t registered_listener_list_lock;
struct list_head registered_app_list_head;
spinlock_t registered_app_list_lock;
@@ -275,12 +304,29 @@ struct qseecom_control {
unsigned int ce_opp_freq_hz;
bool appsbl_qseecom_support;
uint32_t qsee_reentrancy_support;
+ bool enable_key_wrap_in_ks;
uint32_t app_block_ref_cnt;
wait_queue_head_t app_block_wq;
atomic_t qseecom_state;
int is_apps_region_protected;
bool smcinvoke_support;
+
+ struct list_head unregister_lsnr_pending_list_head;
+ wait_queue_head_t register_lsnr_pending_wq;
+ struct task_struct *unregister_lsnr_kthread_task;
+ wait_queue_head_t unregister_lsnr_kthread_wq;
+ atomic_t unregister_lsnr_kthread_state;
+
+ struct list_head unload_app_pending_list_head;
+ struct task_struct *unload_app_kthread_task;
+ wait_queue_head_t unload_app_kthread_wq;
+ atomic_t unload_app_kthread_state;
+};
+
+struct qseecom_unload_app_pending_list {
+ struct list_head list;
+ struct qseecom_dev_handle *data;
};
struct qseecom_sec_buf_fd_info {
@@ -305,10 +351,14 @@ struct qseecom_client_handle {
char app_name[MAX_APP_NAME_SIZE];
u32 app_arch;
struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD];
+ bool from_smcinvoke;
+ bool unload_pending;
};
struct qseecom_listener_handle {
u32 id;
+ bool unregister_pending;
+ bool release_called;
};
static struct qseecom_control qseecom;
@@ -380,6 +430,8 @@ static int qseecom_free_ce_info(struct qseecom_dev_handle *data,
void __user *argp);
static int qseecom_query_ce_info(struct qseecom_dev_handle *data,
void __user *argp);
+static int __qseecom_unload_app(struct qseecom_dev_handle *data,
+ uint32_t app_id);
static int get_qseecom_keymaster_status(char *str)
{
@@ -388,6 +440,25 @@ static int get_qseecom_keymaster_status(char *str)
}
__setup("androidboot.keymaster=", get_qseecom_keymaster_status);
+static int __qseecom_scm_call2_locked(uint32_t smc_id, struct scm_desc *desc)
+{
+ int ret = 0;
+ int retry_count = 0;
+
+ do {
+ ret = scm_call2_noretry(smc_id, desc);
+ if (ret == -EBUSY) {
+ mutex_unlock(&app_access_lock);
+ msleep(QSEECOM_SCM_EBUSY_WAIT_MS);
+ mutex_lock(&app_access_lock);
+ }
+ if (retry_count == QSEECOM_SCM_SECURE_WORLD_BUSY_COUNT)
+ pr_warn("secure world has been busy for 1 second!\n");
+ } while (ret == -EBUSY &&
+ (retry_count++ < QSEECOM_SCM_EBUSY_MAX_RETRY));
+ return ret;
+}
+
static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
const void *req_buf, void *resp_buf)
{
@@ -415,7 +486,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
svc_id, tz_cmd_id);
return -EINVAL;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case SCM_SVC_ES: {
@@ -426,10 +497,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_save_partition_hash_req *)
req_buf;
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("error allocating data\n");
+
+ if (!tzbuf)
return -ENOMEM;
- }
memset(tzbuf, 0, tzbuflen);
memcpy(tzbuf, p_hash_req->digest,
SHA256_DIGEST_LENGTH);
@@ -439,7 +509,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = p_hash_req->partition_id;
desc.args[1] = virt_to_phys(tzbuf);
desc.args[2] = SHA256_DIGEST_LENGTH;
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
@@ -457,6 +527,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
case QSEOS_APP_START_COMMAND: {
struct qseecom_load_app_ireq *req;
struct qseecom_load_app_64bit_ireq *req_64bit;
+
smc_id = TZ_OS_APP_START_ID;
desc.arginfo = TZ_OS_APP_START_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -473,11 +544,12 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[2] = req_64bit->phy_addr;
}
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_APP_SHUTDOWN_COMMAND: {
struct qseecom_unload_app_ireq *req;
+
req = (struct qseecom_unload_app_ireq *)req_buf;
smc_id = TZ_OS_APP_SHUTDOWN_ID;
desc.arginfo = TZ_OS_APP_SHUTDOWN_ID_PARAM_ID;
@@ -489,11 +561,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
struct qseecom_check_app_ireq *req;
u32 tzbuflen = PAGE_ALIGN(sizeof(req->app_name));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("Allocate %d bytes buffer failed\n",
- tzbuflen);
+
+ if (!tzbuf)
return -ENOMEM;
- }
req = (struct qseecom_check_app_ireq *)req_buf;
pr_debug("Lookup app_name = %s\n", req->app_name);
strlcpy(tzbuf, req->app_name, sizeof(req->app_name));
@@ -503,13 +573,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = strlen(req->app_name);
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
case QSEOS_APP_REGION_NOTIFICATION: {
struct qsee_apps_region_info_ireq *req;
struct qsee_apps_region_info_64bit_ireq *req_64bit;
+
smc_id = TZ_OS_APP_REGION_NOTIFICATION_ID;
desc.arginfo =
TZ_OS_APP_REGION_NOTIFICATION_ID_PARAM_ID;
@@ -526,12 +597,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[1] = req_64bit->size;
}
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_LOAD_SERV_IMAGE_COMMAND: {
struct qseecom_load_lib_image_ireq *req;
struct qseecom_load_lib_image_64bit_ireq *req_64bit;
+
smc_id = TZ_OS_LOAD_SERVICES_IMAGE_ID;
desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -549,19 +621,20 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[2] = req_64bit->phy_addr;
}
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_UNLOAD_SERV_IMAGE_COMMAND: {
smc_id = TZ_OS_UNLOAD_SERVICES_IMAGE_ID;
desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_REGISTER_LISTENER: {
struct qseecom_register_listener_ireq *req;
struct qseecom_register_listener_64bit_ireq *req_64bit;
+
desc.arginfo =
TZ_OS_REGISTER_LISTENER_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -580,30 +653,29 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
}
qseecom.smcinvoke_support = true;
smc_id = TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
- if (ret) {
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
+ if (ret == -EIO) {
+ /* smcinvoke is not supported */
qseecom.smcinvoke_support = false;
smc_id = TZ_OS_REGISTER_LISTENER_ID;
- __qseecom_reentrancy_check_if_no_app_blocked(
- smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
}
break;
}
case QSEOS_DEREGISTER_LISTENER: {
struct qseecom_unregister_listener_ireq *req;
+
req = (struct qseecom_unregister_listener_ireq *)
req_buf;
smc_id = TZ_OS_DEREGISTER_LISTENER_ID;
desc.arginfo = TZ_OS_DEREGISTER_LISTENER_ID_PARAM_ID;
desc.args[0] = req->listener_id;
- __qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_LISTENER_DATA_RSP_COMMAND: {
struct qseecom_client_listener_data_irsp *req;
+
req = (struct qseecom_client_listener_data_irsp *)
req_buf;
smc_id = TZ_OS_LISTENER_RESPONSE_HANDLER_ID;
@@ -611,7 +683,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
TZ_OS_LISTENER_RESPONSE_HANDLER_ID_PARAM_ID;
desc.args[0] = req->listener_id;
desc.args[1] = req->status;
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: {
@@ -639,12 +711,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[2] = req_64->sglistinfo_ptr;
desc.args[3] = req_64->sglistinfo_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: {
struct qseecom_load_app_ireq *req;
struct qseecom_load_app_64bit_ireq *req_64bit;
+
smc_id = TZ_OS_LOAD_EXTERNAL_IMAGE_ID;
desc.arginfo = TZ_OS_LOAD_SERVICES_IMAGE_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -660,20 +733,21 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[2] = req_64bit->phy_addr;
}
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_UNLOAD_EXTERNAL_ELF_COMMAND: {
smc_id = TZ_OS_UNLOAD_EXTERNAL_IMAGE_ID;
desc.arginfo = TZ_OS_UNLOAD_SERVICES_IMAGE_ID_PARAM_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_CLIENT_SEND_DATA_COMMAND: {
struct qseecom_client_send_data_ireq *req;
struct qseecom_client_send_data_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_QSAPP_SEND_DATA_ID;
desc.arginfo = TZ_APP_QSAPP_SEND_DATA_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -694,7 +768,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->rsp_ptr;
desc.args[4] = req_64bit->rsp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: {
@@ -726,32 +800,33 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[5] = req_64bit->sglistinfo_ptr;
desc.args[6] = req_64bit->sglistinfo_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_RPMB_PROVISION_KEY_COMMAND: {
struct qseecom_client_send_service_ireq *req;
+
req = (struct qseecom_client_send_service_ireq *)
req_buf;
smc_id = TZ_OS_RPMB_PROVISION_KEY_ID;
desc.arginfo = TZ_OS_RPMB_PROVISION_KEY_ID_PARAM_ID;
desc.args[0] = req->key_type;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_RPMB_ERASE_COMMAND: {
smc_id = TZ_OS_RPMB_ERASE_ID;
desc.arginfo = TZ_OS_RPMB_ERASE_ID_PARAM_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_RPMB_CHECK_PROV_STATUS_COMMAND: {
smc_id = TZ_OS_RPMB_CHECK_PROV_STATUS_ID;
desc.arginfo = TZ_OS_RPMB_CHECK_PROV_STATUS_ID_PARAM_ID;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_GENERATE_KEY: {
@@ -759,6 +834,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_key_generate_ireq) -
sizeof(uint32_t));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
+
if (!tzbuf)
return -ENOMEM;
memset(tzbuf, 0, tzbuflen);
@@ -771,7 +847,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = tzbuflen;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
@@ -780,11 +856,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_key_delete_ireq) -
sizeof(uint32_t));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("Allocate %d bytes buffer failed\n",
- tzbuflen);
+
+ if (!tzbuf)
return -ENOMEM;
- }
memset(tzbuf, 0, tzbuflen);
memcpy(tzbuf, req_buf + sizeof(uint32_t),
(sizeof(struct qseecom_key_delete_ireq) -
@@ -795,7 +869,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = tzbuflen;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
@@ -804,11 +878,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_key_select_ireq) -
sizeof(uint32_t));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("Allocate %d bytes buffer failed\n",
- tzbuflen);
+
+ if (!tzbuf)
return -ENOMEM;
- }
memset(tzbuf, 0, tzbuflen);
memcpy(tzbuf, req_buf + sizeof(uint32_t),
(sizeof(struct qseecom_key_select_ireq) -
@@ -819,7 +891,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = tzbuflen;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
@@ -828,11 +900,9 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
(struct qseecom_key_userinfo_update_ireq) -
sizeof(uint32_t));
char *tzbuf = kzalloc(tzbuflen, GFP_KERNEL);
- if (!tzbuf) {
- pr_err("Allocate %d bytes buffer failed\n",
- tzbuflen);
+
+ if (!tzbuf)
return -ENOMEM;
- }
memset(tzbuf, 0, tzbuflen);
memcpy(tzbuf, req_buf + sizeof(uint32_t), (sizeof
(struct qseecom_key_userinfo_update_ireq) -
@@ -843,13 +913,14 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[0] = virt_to_phys(tzbuf);
desc.args[1] = tzbuflen;
__qseecom_reentrancy_check_if_no_app_blocked(smc_id);
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
kzfree(tzbuf);
break;
}
case QSEOS_TEE_OPEN_SESSION: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_GPAPP_OPEN_SESSION_ID;
desc.arginfo = TZ_APP_GPAPP_OPEN_SESSION_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -868,7 +939,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->resp_ptr;
desc.args[4] = req_64bit->resp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_OPEN_SESSION_WHITELIST: {
@@ -898,12 +969,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[5] = req_64bit->sglistinfo_ptr;
desc.args[6] = req_64bit->sglistinfo_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_INVOKE_COMMAND: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_ID;
desc.arginfo = TZ_APP_GPAPP_INVOKE_COMMAND_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -922,7 +994,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->resp_ptr;
desc.args[4] = req_64bit->resp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: {
@@ -952,12 +1024,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[5] = req_64bit->sglistinfo_ptr;
desc.args[6] = req_64bit->sglistinfo_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_CLOSE_SESSION: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_GPAPP_CLOSE_SESSION_ID;
desc.arginfo = TZ_APP_GPAPP_CLOSE_SESSION_ID_PARAM_ID;
if (qseecom.qsee_version < QSEE_VERSION_40) {
@@ -976,12 +1049,13 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->resp_ptr;
desc.args[4] = req_64bit->resp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_TEE_REQUEST_CANCELLATION: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
+
smc_id = TZ_APP_GPAPP_REQUEST_CANCELLATION_ID;
desc.arginfo =
TZ_APP_GPAPP_REQUEST_CANCELLATION_ID_PARAM_ID;
@@ -1001,7 +1075,7 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.args[3] = req_64bit->resp_ptr;
desc.args[4] = req_64bit->resp_len;
}
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
case QSEOS_CONTINUE_BLOCKED_REQ_COMMAND: {
@@ -1016,11 +1090,11 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
desc.arginfo =
TZ_OS_CONTINUE_BLOCKED_REQUEST_ID_PARAM_ID;
desc.args[0] = req->app_or_session_id;
- ret = scm_call2(smc_id, &desc);
+ ret = __qseecom_scm_call2_locked(smc_id, &desc);
break;
}
default: {
- pr_err("qseos_cmd_id 0x%d is not supported by armv8 scm_call2.\n",
+ pr_err("qseos_cmd_id %d is not supported by armv8 scm_call2.\n",
qseos_cmd_id);
ret = -EINVAL;
break;
@@ -1056,42 +1130,18 @@ static int qseecom_scm_call(u32 svc_id, u32 tz_cmd_id, const void *cmd_buf,
return qseecom_scm_call2(svc_id, tz_cmd_id, cmd_buf, resp_buf);
}
-static int __qseecom_is_svc_unique(struct qseecom_dev_handle *data,
- struct qseecom_register_listener_req *svc)
-{
- struct qseecom_registered_listener_list *ptr;
- int unique = 1;
- unsigned long flags;
-
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(ptr, &qseecom.registered_listener_list_head, list) {
- if (ptr->svc.listener_id == svc->listener_id) {
- pr_err("Service id: %u is already registered\n",
- ptr->svc.listener_id);
- unique = 0;
- break;
- }
- }
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
- return unique;
-}
-
static struct qseecom_registered_listener_list *__qseecom_find_svc(
int32_t listener_id)
{
struct qseecom_registered_listener_list *entry = NULL;
- unsigned long flags;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(entry, &qseecom.registered_listener_list_head, list)
- {
+ list_for_each_entry(entry,
+ &qseecom.registered_listener_list_head, list) {
if (entry->svc.listener_id == listener_id)
break;
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
-
if ((entry != NULL) && (entry->svc.listener_id != listener_id)) {
- pr_err("Service id: %u is not found\n", listener_id);
+ pr_debug("Service id: %u is not found\n", listener_id);
return NULL;
}
@@ -1151,8 +1201,14 @@ static int __qseecom_set_sb_memory(struct qseecom_registered_listener_list *svc,
resp.result = QSEOS_RESULT_INCOMPLETE;
+ mutex_unlock(&listener_access_lock);
+ mutex_lock(&app_access_lock);
+ __qseecom_reentrancy_check_if_no_app_blocked(
+ TZ_OS_REGISTER_LISTENER_SMCINVOKE_ID);
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
&resp, sizeof(resp));
+ mutex_unlock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
if (ret) {
pr_err("qseecom_scm_call failed with err: %d\n", ret);
return -EINVAL;
@@ -1170,9 +1226,9 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
void __user *argp)
{
int ret = 0;
- unsigned long flags;
struct qseecom_register_listener_req rcvd_lstnr;
struct qseecom_registered_listener_list *new_entry;
+ struct qseecom_registered_listener_list *ptr_svc;
ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr));
if (ret) {
@@ -1183,18 +1239,33 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
rcvd_lstnr.sb_size))
return -EFAULT;
- data->listener.id = 0;
- if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
- pr_err("Service is not unique and is already registered\n");
- data->released = true;
- return -EBUSY;
+ ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id);
+ if (ptr_svc) {
+ if (ptr_svc->unregister_pending == false) {
+ pr_err("Service %d is not unique\n",
+ rcvd_lstnr.listener_id);
+ data->released = true;
+ return -EBUSY;
+ }
+ /*wait until listener is unregistered*/
+ pr_debug("register %d has to wait\n",
+ rcvd_lstnr.listener_id);
+ mutex_unlock(&listener_access_lock);
+ ret = wait_event_interruptible(
+ qseecom.register_lsnr_pending_wq,
+ list_empty(
+ &qseecom.unregister_lsnr_pending_list_head));
+ if (ret) {
+ pr_err("interrupted register_pending_wq %d\n",
+ rcvd_lstnr.listener_id);
+ mutex_lock(&listener_access_lock);
+ return -ERESTARTSYS;
+ }
+ mutex_lock(&listener_access_lock);
}
-
new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
- if (!new_entry) {
- pr_err("kmalloc failed\n");
+ if (!new_entry)
return -ENOMEM;
- }
memcpy(&new_entry->svc, &rcvd_lstnr, sizeof(rcvd_lstnr));
new_entry->rcv_req_flag = 0;
@@ -1202,30 +1273,28 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
new_entry->sb_length = rcvd_lstnr.sb_size;
new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base;
if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) {
- pr_err("qseecom_set_sb_memoryfailed\n");
+ pr_err("qseecom_set_sb_memory failed for listener %d, size %d\n",
+ rcvd_lstnr.listener_id, rcvd_lstnr.sb_size);
kzfree(new_entry);
return -ENOMEM;
}
- data->listener.id = rcvd_lstnr.listener_id;
init_waitqueue_head(&new_entry->rcv_req_wq);
init_waitqueue_head(&new_entry->listener_block_app_wq);
new_entry->send_resp_flag = 0;
new_entry->listener_in_use = false;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
list_add_tail(&new_entry->list, &qseecom.registered_listener_list_head);
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
+ data->listener.id = rcvd_lstnr.listener_id;
+ pr_debug("Service %d is registered\n", rcvd_lstnr.listener_id);
return ret;
}
-static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+static int __qseecom_unregister_listener(struct qseecom_dev_handle *data,
+ struct qseecom_registered_listener_list *ptr_svc)
{
int ret = 0;
- unsigned long flags;
- uint32_t unmap_mem = 0;
struct qseecom_register_listener_ireq req;
- struct qseecom_registered_listener_list *ptr_svc = NULL;
struct qseecom_command_scm_resp resp;
struct ion_handle *ihandle = NULL; /* Retrieve phy addr */
@@ -1233,68 +1302,157 @@ static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
req.listener_id = data->listener.id;
resp.result = QSEOS_RESULT_INCOMPLETE;
+ mutex_unlock(&listener_access_lock);
+ mutex_lock(&app_access_lock);
+ __qseecom_reentrancy_check_if_no_app_blocked(
+ TZ_OS_DEREGISTER_LISTENER_ID);
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
sizeof(req), &resp, sizeof(resp));
+ mutex_unlock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
if (ret) {
pr_err("scm_call() failed with err: %d (lstnr id=%d)\n",
ret, data->listener.id);
- return ret;
+ if (ret == -EBUSY)
+ return ret;
+ goto exit;
}
if (resp.result != QSEOS_RESULT_SUCCESS) {
pr_err("Failed resp.result=%d,(lstnr id=%d)\n",
resp.result, data->listener.id);
- return -EPERM;
- }
-
- data->abort = 1;
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(ptr_svc, &qseecom.registered_listener_list_head,
- list) {
- if (ptr_svc->svc.listener_id == data->listener.id) {
- wake_up_all(&ptr_svc->rcv_req_wq);
- break;
- }
+ ret = -EPERM;
+ goto exit;
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
while (atomic_read(&data->ioctl_count) > 1) {
- if (wait_event_freezable(data->abort_wq,
+ if (wait_event_interruptible(data->abort_wq,
atomic_read(&data->ioctl_count) <= 1)) {
pr_err("Interrupted from abort\n");
ret = -ERESTARTSYS;
- return ret;
}
}
- spin_lock_irqsave(&qseecom.registered_listener_list_lock, flags);
- list_for_each_entry(ptr_svc,
- &qseecom.registered_listener_list_head,
- list)
- {
- if (ptr_svc->svc.listener_id == data->listener.id) {
- if (ptr_svc->sb_virt) {
- unmap_mem = 1;
- ihandle = ptr_svc->ihandle;
- }
- list_del(&ptr_svc->list);
- kzfree(ptr_svc);
- break;
- }
- }
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock, flags);
-
- /* Unmap the memory */
- if (unmap_mem) {
+exit:
+ if (ptr_svc->sb_virt) {
+ ihandle = ptr_svc->ihandle;
if (!IS_ERR_OR_NULL(ihandle)) {
ion_unmap_kernel(qseecom.ion_clnt, ihandle);
ion_free(qseecom.ion_clnt, ihandle);
- }
+ }
}
+ list_del(&ptr_svc->list);
+ kzfree(ptr_svc);
+
data->released = true;
+ pr_debug("Service %d is unregistered\n", data->listener.id);
return ret;
}
+static int qseecom_unregister_listener(struct qseecom_dev_handle *data)
+{
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct qseecom_unregister_pending_list *entry = NULL;
+
+ if (data->released) {
+ pr_err("Don't unregister lsnr %d\n", data->listener.id);
+ return -EINVAL;
+ }
+
+ ptr_svc = __qseecom_find_svc(data->listener.id);
+ if (!ptr_svc) {
+ pr_err("Unregiser invalid listener ID %d\n", data->listener.id);
+ return -ENODATA;
+ }
+ /* stop CA thread waiting for listener response */
+ ptr_svc->abort = 1;
+ wake_up_interruptible_all(&qseecom.send_resp_wq);
+
+ /* stop listener thread waiting for listener request */
+ data->abort = 1;
+ wake_up_all(&ptr_svc->rcv_req_wq);
+
+ /* return directly if pending*/
+ if (ptr_svc->unregister_pending)
+ return 0;
+
+ /*add unregistration into pending list*/
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ entry->data = data;
+ list_add_tail(&entry->list,
+ &qseecom.unregister_lsnr_pending_list_head);
+ ptr_svc->unregister_pending = true;
+ pr_debug("unregister %d pending\n", data->listener.id);
+ return 0;
+}
+
+static void __qseecom_processing_pending_lsnr_unregister(void)
+{
+ struct qseecom_unregister_pending_list *entry = NULL;
+ struct qseecom_registered_listener_list *ptr_svc = NULL;
+ struct list_head *pos;
+ int ret = 0;
+
+ mutex_lock(&listener_access_lock);
+ while (!list_empty(&qseecom.unregister_lsnr_pending_list_head)) {
+ pos = qseecom.unregister_lsnr_pending_list_head.next;
+ entry = list_entry(pos,
+ struct qseecom_unregister_pending_list, list);
+ if (entry && entry->data) {
+ pr_debug("process pending unregister %d\n",
+ entry->data->listener.id);
+ /* don't process if qseecom_release is not called*/
+ if (!entry->data->listener.release_called)
+ break;
+ ptr_svc = __qseecom_find_svc(
+ entry->data->listener.id);
+ if (ptr_svc) {
+ ret = __qseecom_unregister_listener(
+ entry->data, ptr_svc);
+ if (ret == -EBUSY) {
+ pr_debug("unregister %d pending again\n",
+ entry->data->listener.id);
+ mutex_unlock(&listener_access_lock);
+ return;
+ }
+ } else
+ pr_err("invalid listener %d\n",
+ entry->data->listener.id);
+ kzfree(entry->data);
+ }
+ list_del(pos);
+ kzfree(entry);
+ }
+ mutex_unlock(&listener_access_lock);
+ wake_up_interruptible(&qseecom.register_lsnr_pending_wq);
+}
+
+static void __wakeup_unregister_listener_kthread(void)
+{
+ atomic_set(&qseecom.unregister_lsnr_kthread_state,
+ LSNR_UNREG_KT_WAKEUP);
+ wake_up_interruptible(&qseecom.unregister_lsnr_kthread_wq);
+}
+
+static int __qseecom_unregister_listener_kthread_func(void *data)
+{
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(
+ qseecom.unregister_lsnr_kthread_wq,
+ atomic_read(&qseecom.unregister_lsnr_kthread_state)
+ == LSNR_UNREG_KT_WAKEUP);
+ pr_debug("kthread to unregister listener is called %d\n",
+ atomic_read(&qseecom.unregister_lsnr_kthread_state));
+ __qseecom_processing_pending_lsnr_unregister();
+ atomic_set(&qseecom.unregister_lsnr_kthread_state,
+ LSNR_UNREG_KT_SLEEP);
+ }
+ pr_warn("kthread to unregister listener stopped\n");
+ return 0;
+}
+
static int __qseecom_set_msm_bus_request(uint32_t mode)
{
int ret = 0;
@@ -1343,39 +1501,35 @@ static void qseecom_bw_inactive_req_work(struct work_struct *work)
qseecom.timer_running = false;
mutex_unlock(&qsee_bw_mutex);
mutex_unlock(&app_access_lock);
- return;
}
static void qseecom_scale_bus_bandwidth_timer_callback(unsigned long data)
{
schedule_work(&qseecom.bw_inactive_req_ws);
- return;
}
static int __qseecom_decrease_clk_ref_count(enum qseecom_ce_hw_instance ce)
{
struct qseecom_clk *qclk;
int ret = 0;
+
mutex_lock(&clk_access_lock);
if (ce == CLK_QSEE)
qclk = &qseecom.qsee;
else
qclk = &qseecom.ce_drv;
- if (qclk->clk_access_cnt > 2) {
+ if (qclk->clk_access_cnt > 0) {
+ qclk->clk_access_cnt--;
+ } else {
pr_err("Invalid clock ref count %d\n", qclk->clk_access_cnt);
ret = -EINVAL;
- goto err_dec_ref_cnt;
}
- if (qclk->clk_access_cnt == 2)
- qclk->clk_access_cnt--;
-err_dec_ref_cnt:
mutex_unlock(&clk_access_lock);
return ret;
}
-
static int qseecom_scale_bus_bandwidth_timer(uint32_t mode)
{
int32_t ret = 0;
@@ -1445,6 +1599,7 @@ static int __qseecom_register_bus_bandwidth_needs(
static int qseecom_perf_enable(struct qseecom_dev_handle *data)
{
int ret = 0;
+
ret = qsee_vote_for_clock(data, CLK_DFAB);
if (ret) {
pr_err("Failed to vote for DFAB clock with err %d\n", ret);
@@ -1481,9 +1636,9 @@ static int qseecom_scale_bus_bandwidth(struct qseecom_dev_handle *data,
}
/*
- * Register bus bandwidth needs if bus scaling feature is enabled;
- * otherwise, qseecom enable/disable clocks for the client directly.
- */
+ * Register bus bandwidth needs if bus scaling feature is enabled;
+ * otherwise, qseecom enable/disable clocks for the client directly.
+ */
if (qseecom.support_bus_scaling) {
mutex_lock(&qsee_bw_mutex);
ret = __qseecom_register_bus_bandwidth_needs(data, req_mode);
@@ -1526,12 +1681,12 @@ static void __qseecom_disable_clk_scale_down(struct qseecom_dev_handle *data)
else
__qseecom_add_bw_scale_down_timer(
QSEECOM_LOAD_APP_CRYPTO_TIMEOUT);
- return;
}
static int __qseecom_enable_clk_scale_up(struct qseecom_dev_handle *data)
{
int ret = 0;
+
if (qseecom.support_bus_scaling) {
ret = qseecom_scale_bus_bandwidth_timer(MEDIUM);
if (ret)
@@ -1583,7 +1738,7 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
}
if (len < req.sb_len) {
- pr_err("Requested length (0x%x) is > allocated (0x%zu)\n",
+ pr_err("Requested length (0x%x) is > allocated (%zu)\n",
req.sb_len, len);
return -EINVAL;
}
@@ -1600,11 +1755,13 @@ static int qseecom_set_client_mem_param(struct qseecom_dev_handle *data,
return 0;
}
-static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data)
+static int __qseecom_listener_has_sent_rsp(struct qseecom_dev_handle *data,
+ struct qseecom_registered_listener_list *ptr_svc)
{
int ret;
+
ret = (qseecom.send_resp_flag != 0);
- return ret || data->abort;
+ return ret || data->abort || ptr_svc->abort;
}
static int __qseecom_reentrancy_listener_has_sent_rsp(
@@ -1614,56 +1771,7 @@ static int __qseecom_reentrancy_listener_has_sent_rsp(
int ret;
ret = (ptr_svc->send_resp_flag != 0);
- return ret || data->abort;
-}
-
-static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data,
- struct qseecom_command_scm_resp *resp,
- struct qseecom_client_listener_data_irsp *send_data_rsp,
- struct qseecom_registered_listener_list *ptr_svc,
- uint32_t lstnr) {
- int ret = 0;
-
- send_data_rsp->status = QSEOS_RESULT_FAILURE;
- qseecom.send_resp_flag = 0;
- send_data_rsp->qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
- send_data_rsp->listener_id = lstnr;
- if (ptr_svc)
- pr_warn("listener_id:%x, lstnr: %x\n",
- ptr_svc->svc.listener_id, lstnr);
- if (ptr_svc && ptr_svc->ihandle) {
- ret = msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
- ptr_svc->sb_virt, ptr_svc->sb_length,
- ION_IOC_CLEAN_INV_CACHES);
- if (ret) {
- pr_err("cache operation failed %d\n", ret);
- return ret;
- }
- }
-
- if (lstnr == RPMB_SERVICE) {
- ret = __qseecom_enable_clk(CLK_QSEE);
- if (ret)
- return ret;
- }
- ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, send_data_rsp,
- sizeof(send_data_rsp), resp, sizeof(*resp));
- if (ret) {
- pr_err("scm_call() failed with err: %d (app_id = %d)\n",
- ret, data->client.app_id);
- if (lstnr == RPMB_SERVICE)
- __qseecom_disable_clk(CLK_QSEE);
- return ret;
- }
- if ((resp->result != QSEOS_RESULT_SUCCESS) &&
- (resp->result != QSEOS_RESULT_INCOMPLETE)) {
- pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
- resp->result, data->client.app_id, lstnr);
- ret = -EINVAL;
- }
- if (lstnr == RPMB_SERVICE)
- __qseecom_disable_clk(CLK_QSEE);
- return ret;
+ return ret || data->abort || ptr_svc->abort;
}
static void __qseecom_clean_listener_sglistinfo(
@@ -1682,9 +1790,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
int ret = 0;
int rc = 0;
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_client_listener_data_irsp send_data_rsp = {0};
+ struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
+ = {0};
struct qseecom_registered_listener_list *ptr_svc = NULL;
sigset_t new_sigset;
sigset_t old_sigset;
@@ -1693,13 +1801,13 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
size_t cmd_len;
struct sglist_info *table = NULL;
+ qseecom.app_block_ref_cnt++;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
/*
* Wake up blocking lsitener service with the lstnr id
*/
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
+ mutex_lock(&listener_access_lock);
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
@@ -1709,29 +1817,38 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
break;
}
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
if (ptr_svc == NULL) {
pr_err("Listener Svc %d does not exist\n", lstnr);
- __qseecom_qseos_fail_return_resp_tz(data, resp,
- &send_data_rsp, ptr_svc, lstnr);
- return -EINVAL;
+ rc = -EINVAL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
if (!ptr_svc->ihandle) {
pr_err("Client handle is not initialized\n");
- __qseecom_qseos_fail_return_resp_tz(data, resp,
- &send_data_rsp, ptr_svc, lstnr);
- return -EINVAL;
+ rc = -EINVAL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
if (ptr_svc->svc.listener_id != lstnr) {
- pr_warn("Service requested does not exist\n");
- __qseecom_qseos_fail_return_resp_tz(data, resp,
- &send_data_rsp, NULL, lstnr);
- return -ERESTARTSYS;
+ pr_err("Service %d does not exist\n",
+ lstnr);
+ rc = -ERESTARTSYS;
+ ptr_svc = NULL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
+ }
+
+ if (ptr_svc->abort == 1) {
+ pr_debug("Service %d abort %d\n",
+ lstnr, ptr_svc->abort);
+ rc = -ENODEV;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
+
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
/* initialize the new signal mask with all signals*/
@@ -1739,6 +1856,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
/* block all signals */
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
+ mutex_unlock(&listener_access_lock);
do {
/*
* When reentrancy is not supported, check global
@@ -1746,22 +1864,23 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
* send_resp_flag.
*/
if (!qseecom.qsee_reentrancy_support &&
- !wait_event_freezable(qseecom.send_resp_wq,
- __qseecom_listener_has_sent_rsp(data))) {
- break;
+ !wait_event_interruptible(qseecom.send_resp_wq,
+ __qseecom_listener_has_sent_rsp(
+ data, ptr_svc))) {
+ break;
}
if (qseecom.qsee_reentrancy_support &&
- !wait_event_freezable(qseecom.send_resp_wq,
+ !wait_event_interruptible(qseecom.send_resp_wq,
__qseecom_reentrancy_listener_has_sent_rsp(
data, ptr_svc))) {
- break;
+ break;
}
} while (1);
-
+ mutex_lock(&listener_access_lock);
/* restore signal mask */
sigprocmask(SIG_SETMASK, &old_sigset, NULL);
- if (data->abort) {
+ if (data->abort || ptr_svc->abort) {
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
rc = -ENODEV;
@@ -1769,76 +1888,91 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
} else {
status = QSEOS_RESULT_SUCCESS;
}
-
+err_resp:
qseecom.send_resp_flag = 0;
- ptr_svc->send_resp_flag = 0;
- table = ptr_svc->sglistinfo_ptr;
+ if (ptr_svc) {
+ 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);
+ if (table) {
+ 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);
+ if (table) {
+ 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)
+ if (qseecom.whitelist_support == false || table == NULL)
*(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
else
*(uint32_t *)cmd_buf =
QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
- if (ptr_svc) {
+ if (ptr_svc && ptr_svc->ihandle) {
ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
ION_IOC_CLEAN_INV_CACHES);
if (ret) {
pr_err("cache operation failed %d\n", ret);
- return ret;
+ goto exit;
}
}
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE)) {
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
- return ret;
+ goto exit;
}
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
cmd_buf, cmd_len, resp, sizeof(*resp));
- ptr_svc->listener_in_use = false;
- __qseecom_clean_listener_sglistinfo(ptr_svc);
+ if (ptr_svc) {
+ 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);
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
__qseecom_disable_clk(CLK_QSEE);
- return ret;
+ goto exit;
}
+ pr_debug("resp status %d, res= %d, app_id = %d, lstr = %d\n",
+ status, resp->result, data->client.app_id, lstnr);
if ((resp->result != QSEOS_RESULT_SUCCESS) &&
(resp->result != QSEOS_RESULT_INCOMPLETE)) {
pr_err("fail:resp res= %d,app_id = %d,lstr = %d\n",
resp->result, data->client.app_id, lstnr);
ret = -EINVAL;
+ goto exit;
}
+exit:
+ mutex_unlock(&listener_access_lock);
if ((lstnr == RPMB_SERVICE) || (lstnr == SSD_SERVICE))
__qseecom_disable_clk(CLK_QSEE);
}
+ qseecom.app_block_ref_cnt--;
+ wake_up_interruptible_all(&qseecom.app_block_wq);
if (rc)
return rc;
@@ -1859,6 +1993,7 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
sigset_t old_sigset;
unsigned long flags;
bool found_app = false;
+ struct qseecom_registered_app_list dummy_app_entry = { {NULL} };
if (!resp || !data) {
pr_err("invalid resp or data pointer\n");
@@ -1868,33 +2003,42 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
/* find app_id & img_name from list */
if (!ptr_app) {
- spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
- list_for_each_entry(ptr_app, &qseecom.registered_app_list_head,
- list) {
- if ((ptr_app->app_id == data->client.app_id) &&
- (!strcmp(ptr_app->app_name,
+ if (data->client.from_smcinvoke) {
+ pr_debug("This request is from smcinvoke\n");
+ ptr_app = &dummy_app_entry;
+ ptr_app->app_id = data->client.app_id;
+ } else {
+ spin_lock_irqsave(&qseecom.registered_app_list_lock,
+ flags);
+ list_for_each_entry(ptr_app,
+ &qseecom.registered_app_list_head, list) {
+ if ((ptr_app->app_id == data->client.app_id) &&
+ (!strcmp(ptr_app->app_name,
data->client.app_name))) {
- found_app = true;
- break;
+ found_app = true;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(
+ &qseecom.registered_app_list_lock, flags);
+ if (!found_app) {
+ pr_err("app_id %d (%s) is not found\n",
+ data->client.app_id,
+ (char *)data->client.app_name);
+ ret = -ENOENT;
+ goto exit;
}
- }
- spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
- flags);
- if (!found_app) {
- pr_err("app_id %d (%s) is not found\n",
- data->client.app_id,
- (char *)data->client.app_name);
- ret = -ENOENT;
- goto exit;
}
}
do {
session_id = resp->resp_type;
+ mutex_lock(&listener_access_lock);
list_ptr = __qseecom_find_svc(resp->data);
if (!list_ptr) {
pr_err("Invalid listener ID %d\n", resp->data);
ret = -ENODATA;
+ mutex_unlock(&listener_access_lock);
goto exit;
}
ptr_app->blocked_on_listener_id = resp->data;
@@ -1910,11 +2054,13 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
do {
qseecom.app_block_ref_cnt++;
ptr_app->app_blocked = true;
+ mutex_unlock(&listener_access_lock);
mutex_unlock(&app_access_lock);
- wait_event_freezable(
+ wait_event_interruptible(
list_ptr->listener_block_app_wq,
!list_ptr->listener_in_use);
mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
ptr_app->app_blocked = false;
qseecom.app_block_ref_cnt--;
} while (list_ptr->listener_in_use);
@@ -1947,9 +2093,11 @@ static int __qseecom_process_reentrancy_blocked_on_listener(
if (ret) {
pr_err("unblock app %d or session %d fail\n",
data->client.app_id, session_id);
+ mutex_unlock(&listener_access_lock);
goto exit;
}
}
+ mutex_unlock(&listener_access_lock);
resp->result = continue_resp.result;
resp->resp_type = continue_resp.resp_type;
resp->data = continue_resp.data;
@@ -1971,9 +2119,9 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
int ret = 0;
int rc = 0;
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_client_listener_data_irsp send_data_rsp = {0};
+ struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit
+ = {0};
struct qseecom_registered_listener_list *ptr_svc = NULL;
sigset_t new_sigset;
sigset_t old_sigset;
@@ -1982,13 +2130,12 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
size_t cmd_len;
struct sglist_info *table = NULL;
- while (ret == 0 && rc == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
+ while (ret == 0 && resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
/*
* Wake up blocking lsitener service with the lstnr id
*/
- spin_lock_irqsave(&qseecom.registered_listener_list_lock,
- flags);
+ mutex_lock(&listener_access_lock);
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
@@ -1998,23 +2145,38 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
break;
}
}
- spin_unlock_irqrestore(&qseecom.registered_listener_list_lock,
- flags);
if (ptr_svc == NULL) {
pr_err("Listener Svc %d does not exist\n", lstnr);
- return -EINVAL;
+ rc = -EINVAL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
if (!ptr_svc->ihandle) {
pr_err("Client handle is not initialized\n");
- return -EINVAL;
+ rc = -EINVAL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
if (ptr_svc->svc.listener_id != lstnr) {
- pr_warn("Service requested does not exist\n");
- return -ERESTARTSYS;
+ pr_err("Service %d does not exist\n",
+ lstnr);
+ rc = -ERESTARTSYS;
+ ptr_svc = NULL;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
+ }
+
+ if (ptr_svc->abort == 1) {
+ pr_debug("Service %d abort %d\n",
+ lstnr, ptr_svc->abort);
+ rc = -ENODEV;
+ status = QSEOS_RESULT_FAILURE;
+ goto err_resp;
}
+
pr_debug("waking up rcv_req_wq and waiting for send_resp_wq\n");
/* initialize the new signal mask with all signals*/
@@ -2024,22 +2186,24 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
/* unlock mutex btw waking listener and sleep-wait */
+ mutex_unlock(&listener_access_lock);
mutex_unlock(&app_access_lock);
do {
- if (!wait_event_freezable(qseecom.send_resp_wq,
+ if (!wait_event_interruptible(qseecom.send_resp_wq,
__qseecom_reentrancy_listener_has_sent_rsp(
data, ptr_svc))) {
- break;
+ break;
}
} while (1);
/* lock mutex again after resp sent */
mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
ptr_svc->send_resp_flag = 0;
qseecom.send_resp_flag = 0;
/* restore signal mask */
sigprocmask(SIG_SETMASK, &old_sigset, NULL);
- if (data->abort) {
+ if (data->abort || ptr_svc->abort) {
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
rc = -ENODEV;
@@ -2047,55 +2211,64 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
} else {
status = QSEOS_RESULT_SUCCESS;
}
- table = ptr_svc->sglistinfo_ptr;
+err_resp:
+ if (ptr_svc)
+ 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);
+ if (table) {
+ 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);
+ if (table) {
+ 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)
+ if (qseecom.whitelist_support == false || table == NULL)
*(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
else
*(uint32_t *)cmd_buf =
QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
- if (ptr_svc) {
+ if (ptr_svc && ptr_svc->ihandle) {
ret = msm_ion_do_cache_op(qseecom.ion_clnt,
ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
ION_IOC_CLEAN_INV_CACHES);
if (ret) {
pr_err("cache operation failed %d\n", ret);
- return ret;
+ goto exit;
}
}
if (lstnr == RPMB_SERVICE) {
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
- return ret;
+ goto exit;
}
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
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 (ptr_svc) {
+ ptr_svc->listener_in_use = false;
+ __qseecom_clean_listener_sglistinfo(ptr_svc);
+ wake_up_interruptible(&ptr_svc->listener_block_app_wq);
+ }
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
@@ -2113,8 +2286,10 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
ret = -EINVAL;
goto exit;
}
+ mutex_unlock(&listener_access_lock);
ret = __qseecom_process_reentrancy_blocked_on_listener(
resp, NULL, data);
+ mutex_lock(&listener_access_lock);
if (ret) {
pr_err("failed to process App(%d) %s blocked on listener %d\n",
data->client.app_id,
@@ -2131,6 +2306,7 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
goto exit;
}
exit:
+ mutex_unlock(&listener_access_lock);
if (lstnr == RPMB_SERVICE)
__qseecom_disable_clk(CLK_QSEE);
@@ -2149,23 +2325,15 @@ exit:
*/
static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id)
{
- sigset_t new_sigset, old_sigset;
-
if (qseecom.qsee_reentrancy_support > QSEE_REENTRANCY_PHASE_0 &&
qseecom.qsee_reentrancy_support < QSEE_REENTRANCY_PHASE_3 &&
IS_OWNER_TRUSTED_OS(TZ_SYSCALL_OWNER_ID(smc_id))) {
/* thread sleep until this app unblocked */
while (qseecom.app_block_ref_cnt > 0) {
- sigfillset(&new_sigset);
- sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
mutex_unlock(&app_access_lock);
- do {
- if (!wait_event_freezable(qseecom.app_block_wq,
- (qseecom.app_block_ref_cnt == 0)))
- break;
- } while (1);
+ wait_event_interruptible(qseecom.app_block_wq,
+ (!qseecom.app_block_ref_cnt));
mutex_lock(&app_access_lock);
- sigprocmask(SIG_SETMASK, &old_sigset, NULL);
}
}
}
@@ -2178,22 +2346,17 @@ static void __qseecom_reentrancy_check_if_no_app_blocked(uint32_t smc_id)
static void __qseecom_reentrancy_check_if_this_app_blocked(
struct qseecom_registered_app_list *ptr_app)
{
- sigset_t new_sigset, old_sigset;
if (qseecom.qsee_reentrancy_support) {
+ ptr_app->check_block++;
while (ptr_app->app_blocked || qseecom.app_block_ref_cnt > 1) {
/* thread sleep until this app unblocked */
- sigfillset(&new_sigset);
- sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
mutex_unlock(&app_access_lock);
- do {
- if (!wait_event_freezable(qseecom.app_block_wq,
- (!ptr_app->app_blocked &&
- qseecom.app_block_ref_cnt <= 1)))
- break;
- } while (1);
+ wait_event_interruptible(qseecom.app_block_wq,
+ (!ptr_app->app_blocked &&
+ qseecom.app_block_ref_cnt <= 1));
mutex_lock(&app_access_lock);
- sigprocmask(SIG_SETMASK, &old_sigset, NULL);
}
+ ptr_app->check_block--;
}
}
@@ -2420,8 +2583,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
- pr_err("process_incomplete_cmd failed err: %d\n",
- ret);
+ /* TZ has created app_id, need to unload it */
+ pr_err("incomp_cmd err %d, %d, unload %d %s\n",
+ ret, resp.result, resp.data,
+ load_img_req.img_name);
+ __qseecom_unload_app(data, resp.data);
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
ret = -EFAULT;
@@ -2442,7 +2608,6 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
- pr_err("kmalloc failed\n");
ret = -ENOMEM;
goto loadapp_err;
}
@@ -2450,11 +2615,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
entry->ref_cnt = 1;
entry->app_arch = load_img_req.app_arch;
/*
- * keymaster app may be first loaded as "keymaste" by qseecomd,
- * and then used as "keymaster" on some targets. To avoid app
- * name checking error, register "keymaster" into app_list and
- * thread private data.
- */
+ * keymaster app may be first loaded as "keymaste" by qseecomd,
+ * and then used as "keymaster" on some targets. To avoid app
+ * name checking error, register "keymaster" into app_list and
+ * thread private data.
+ */
if (!strcmp(load_img_req.img_name, "keymaste"))
strlcpy(entry->app_name, "keymaster",
MAX_APP_NAME_SIZE);
@@ -2463,6 +2628,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
MAX_APP_NAME_SIZE);
entry->app_blocked = false;
entry->blocked_on_listener_id = 0;
+ entry->check_block = 0;
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
@@ -2473,7 +2639,7 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags);
- pr_warn("App with id %d (%s) now loaded\n", app_id,
+ pr_warn("App with id %u (%s) now loaded\n", app_id,
(char *)(load_img_req.img_name));
}
data->client.app_id = app_id;
@@ -2511,11 +2677,12 @@ enable_clk_err:
static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
{
int ret = 1; /* Set unload app */
+
wake_up_all(&qseecom.send_resp_wq);
if (qseecom.qsee_reentrancy_support)
mutex_unlock(&app_access_lock);
while (atomic_read(&data->ioctl_count) > 1) {
- if (wait_event_freezable(data->abort_wq,
+ if (wait_event_interruptible(data->abort_wq,
atomic_read(&data->ioctl_count) <= 1)) {
pr_err("Interrupted from abort\n");
ret = -ERESTARTSYS;
@@ -2530,6 +2697,7 @@ static int __qseecom_cleanup_app(struct qseecom_dev_handle *data)
static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
{
int ret = 0;
+
if (!IS_ERR_OR_NULL(data->client.ihandle)) {
ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
ion_free(qseecom.ion_clnt, data->client.ihandle);
@@ -2539,17 +2707,61 @@ static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data)
return ret;
}
+static int __qseecom_unload_app(struct qseecom_dev_handle *data,
+ uint32_t app_id)
+{
+ struct qseecom_unload_app_ireq req;
+ struct qseecom_command_scm_resp resp;
+ int ret = 0;
+
+ /* Populate the structure for sending scm call to load image */
+ req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
+ req.app_id = app_id;
+
+ /* SCM_CALL to unload the app */
+ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
+ sizeof(struct qseecom_unload_app_ireq),
+ &resp, sizeof(resp));
+ if (ret) {
+ pr_err("scm_call to unload app (id = %d) failed\n", app_id);
+ return -EFAULT;
+ }
+ switch (resp.result) {
+ case QSEOS_RESULT_SUCCESS:
+ pr_warn("App (%d) is unloaded\n", app_id);
+ break;
+ case QSEOS_RESULT_INCOMPLETE:
+ ret = __qseecom_process_incomplete_cmd(data, &resp);
+ if (ret)
+ pr_err("unload app %d fail proc incom cmd: %d,%d,%d\n",
+ app_id, ret, resp.result, resp.data);
+ else
+ pr_warn("App (%d) is unloaded\n", app_id);
+ break;
+ case QSEOS_RESULT_FAILURE:
+ pr_err("app (%d) unload_failed!!\n", app_id);
+ ret = -EFAULT;
+ break;
+ default:
+ pr_err("unload app %d get unknown resp.result %d\n",
+ app_id, resp.result);
+ ret = -EFAULT;
+ break;
+ }
+ return ret;
+}
+
static int qseecom_unload_app(struct qseecom_dev_handle *data,
bool app_crash)
{
unsigned long flags;
unsigned long flags1;
int ret = 0;
- struct qseecom_command_scm_resp resp;
struct qseecom_registered_app_list *ptr_app = NULL;
bool unload = false;
bool found_app = false;
bool found_dead_app = false;
+ bool doublecheck = false;
if (!data) {
pr_err("Invalid/uninitialized device handle\n");
@@ -2572,15 +2784,15 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
if (!strcmp((void *)ptr_app->app_name,
(void *)data->client.app_name)) {
found_app = true;
- if (ptr_app->app_blocked)
+ if (ptr_app->app_blocked ||
+ ptr_app->check_block)
app_crash = false;
if (app_crash || ptr_app->ref_cnt == 1)
unload = true;
break;
- } else {
- found_dead_app = true;
- break;
}
+ found_dead_app = true;
+ break;
}
}
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
@@ -2599,42 +2811,30 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
(char *)data->client.app_name);
if (unload) {
- struct qseecom_unload_app_ireq req;
- /* Populate the structure for sending scm call to load image */
- req.qsee_cmd_id = QSEOS_APP_SHUTDOWN_COMMAND;
- req.app_id = data->client.app_id;
+ ret = __qseecom_unload_app(data, data->client.app_id);
- /* SCM_CALL to unload the app */
- ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req,
- sizeof(struct qseecom_unload_app_ireq),
- &resp, sizeof(resp));
- if (ret) {
- pr_err("scm_call to unload app (id = %d) failed\n",
- req.app_id);
- ret = -EFAULT;
- goto unload_exit;
- } else {
- pr_warn("App id %d now unloaded\n", req.app_id);
- }
- if (resp.result == QSEOS_RESULT_FAILURE) {
- pr_err("app (%d) unload_failed!!\n",
- data->client.app_id);
- ret = -EFAULT;
- goto unload_exit;
- }
- if (resp.result == QSEOS_RESULT_SUCCESS)
- pr_debug("App (%d) is unloaded!!\n",
- data->client.app_id);
- if (resp.result == QSEOS_RESULT_INCOMPLETE) {
- ret = __qseecom_process_incomplete_cmd(data, &resp);
- if (ret) {
- pr_err("process_incomplete_cmd fail err: %d\n",
- ret);
- goto unload_exit;
+ /* double check if this app_entry still exists */
+ spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
+ list_for_each_entry(ptr_app,
+ &qseecom.registered_app_list_head, list) {
+ if ((ptr_app->app_id == data->client.app_id) &&
+ (!strcmp((void *)ptr_app->app_name,
+ (void *)data->client.app_name))) {
+ doublecheck = true;
+ break;
}
}
+ spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
+ flags1);
+ if (!doublecheck) {
+ pr_warn("app %d(%s) entry is already removed\n",
+ data->client.app_id,
+ (char *)data->client.app_name);
+ found_app = false;
+ }
}
+unload_exit:
if (found_app) {
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
if (app_crash) {
@@ -2657,12 +2857,105 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags1);
}
-unload_exit:
qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
}
+
+static int qseecom_prepare_unload_app(struct qseecom_dev_handle *data)
+{
+ struct qseecom_unload_app_pending_list *entry = NULL;
+
+ pr_debug("prepare to unload app(%d)(%s), pending %d\n",
+ data->client.app_id, data->client.app_name,
+ data->client.unload_pending);
+ if (data->client.unload_pending)
+ return 0;
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+ entry->data = data;
+ list_add_tail(&entry->list,
+ &qseecom.unload_app_pending_list_head);
+ data->client.unload_pending = true;
+ pr_debug("unload ta %d pending\n", data->client.app_id);
+ return 0;
+}
+
+static void __wakeup_unload_app_kthread(void)
+{
+ atomic_set(&qseecom.unload_app_kthread_state,
+ UNLOAD_APP_KT_WAKEUP);
+ wake_up_interruptible(&qseecom.unload_app_kthread_wq);
+}
+
+static bool __qseecom_find_pending_unload_app(uint32_t app_id, char *app_name)
+{
+ struct qseecom_unload_app_pending_list *entry = NULL;
+ bool found = false;
+
+ mutex_lock(&unload_app_pending_list_lock);
+ list_for_each_entry(entry, &qseecom.unload_app_pending_list_head,
+ list) {
+ if ((entry->data->client.app_id == app_id) &&
+ (!strcmp(entry->data->client.app_name, app_name))) {
+ found = true;
+ break;
+ }
+ }
+ mutex_unlock(&unload_app_pending_list_lock);
+ return found;
+}
+
+static void __qseecom_processing_pending_unload_app(void)
+{
+ struct qseecom_unload_app_pending_list *entry = NULL;
+ struct list_head *pos;
+ int ret = 0;
+
+ mutex_lock(&unload_app_pending_list_lock);
+ while (!list_empty(&qseecom.unload_app_pending_list_head)) {
+ pos = qseecom.unload_app_pending_list_head.next;
+ entry = list_entry(pos,
+ struct qseecom_unload_app_pending_list, list);
+ if (entry && entry->data) {
+ pr_debug("process pending unload app %d (%s)\n",
+ entry->data->client.app_id,
+ entry->data->client.app_name);
+ mutex_unlock(&unload_app_pending_list_lock);
+ mutex_lock(&app_access_lock);
+ ret = qseecom_unload_app(entry->data, true);
+ if (ret)
+ pr_err("unload app %d pending failed %d\n",
+ entry->data->client.app_id, ret);
+ mutex_unlock(&app_access_lock);
+ mutex_lock(&unload_app_pending_list_lock);
+ kzfree(entry->data);
+ }
+ list_del(pos);
+ kzfree(entry);
+ }
+ mutex_unlock(&unload_app_pending_list_lock);
+}
+
+static int __qseecom_unload_app_kthread_func(void *data)
+{
+ while (!kthread_should_stop()) {
+ wait_event_interruptible(
+ qseecom.unload_app_kthread_wq,
+ atomic_read(&qseecom.unload_app_kthread_state)
+ == UNLOAD_APP_KT_WAKEUP);
+ pr_debug("kthread to unload app is called, state %d\n",
+ atomic_read(&qseecom.unload_app_kthread_state));
+ __qseecom_processing_pending_unload_app();
+ atomic_set(&qseecom.unload_app_kthread_state,
+ UNLOAD_APP_KT_SLEEP);
+ }
+ pr_warn("kthread to unload app stopped\n");
+ return 0;
+}
+
static phys_addr_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data,
unsigned long virt)
{
@@ -3066,7 +3359,7 @@ int __qseecom_process_reentrancy(struct qseecom_command_scm_resp *resp,
ret = __qseecom_reentrancy_process_incomplete_cmd(data, resp);
ptr_app->app_blocked = false;
qseecom.app_block_ref_cnt--;
- wake_up_interruptible(&qseecom.app_block_wq);
+ wake_up_interruptible_all(&qseecom.app_block_wq);
if (ret)
pr_err("process_incomplete_cmd failed err: %d\n",
ret);
@@ -3115,6 +3408,13 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
return -ENOENT;
}
+ if (__qseecom_find_pending_unload_app(data->client.app_id,
+ data->client.app_name)) {
+ pr_err("app %d (%s) unload is pending\n",
+ data->client.app_id, data->client.app_name);
+ return -ENOENT;
+ }
+
if (qseecom.qsee_version < QSEE_VERSION_40) {
send_data_req.app_id = data->client.app_id;
send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
@@ -3246,23 +3546,23 @@ int __boundary_checks_offset(struct qseecom_send_modfd_cmd_req *req,
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(req->ifd_data[i].fd > 0)) {
- if ((req->cmd_req_len < sizeof(uint32_t)) ||
- (req->ifd_data[i].cmd_buf_offset >
- req->cmd_req_len - sizeof(uint32_t))) {
- pr_err("Invalid offset (req len) 0x%x\n",
- req->ifd_data[i].cmd_buf_offset);
- return -EINVAL;
- }
+ if ((req->cmd_req_len < sizeof(uint32_t)) ||
+ (req->ifd_data[i].cmd_buf_offset >
+ req->cmd_req_len - sizeof(uint32_t))) {
+ pr_err("Invalid offset (req len) 0x%x\n",
+ req->ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
+ }
} else if ((data->type == QSEECOM_LISTENER_SERVICE) &&
(lstnr_resp->ifd_data[i].fd > 0)) {
- if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
- (lstnr_resp->ifd_data[i].cmd_buf_offset >
- lstnr_resp->resp_len - sizeof(uint32_t))) {
- pr_err("Invalid offset (lstnr resp len) 0x%x\n",
- lstnr_resp->ifd_data[i].cmd_buf_offset);
- return -EINVAL;
- }
+ if ((lstnr_resp->resp_len < sizeof(uint32_t)) ||
+ (lstnr_resp->ifd_data[i].cmd_buf_offset >
+ lstnr_resp->resp_len - sizeof(uint32_t))) {
+ pr_err("Invalid offset (lstnr resp len) 0x%x\n",
+ lstnr_resp->ifd_data[i].cmd_buf_offset);
+ return -EINVAL;
}
+ }
return 0;
}
@@ -3370,6 +3670,7 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
sg = sg_ptr->sgl;
if (sg_ptr->nents == 1) {
uint32_t *update;
+
if (__boundary_checks_offset(req, lstnr_resp, data, i))
goto err;
if ((data->type == QSEECOM_CLIENT_APP &&
@@ -3433,8 +3734,8 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
update = (struct qseecom_sg_entry *)field;
for (j = 0; j < sg_ptr->nents; j++) {
/*
- * Check if sg list PA is under 4GB
- */
+ * Check if sg list PA is under 4GB
+ */
if ((qseecom.qsee_version >=
QSEE_VERSION_40) &&
(!cleanup) &&
@@ -3650,8 +3951,9 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
sg = sg_ptr->sgl;
if (sg_ptr->nents == 1) {
uint64_t *update_64bit;
+
if (__boundary_checks_offset_64(req, lstnr_resp,
- data, i))
+ data, i))
goto err;
/* 64bit app uses 64bit address */
update_64bit = (uint64_t *) field;
@@ -3834,7 +4136,8 @@ static int __qseecom_listener_has_rcvd_req(struct qseecom_dev_handle *data,
struct qseecom_registered_listener_list *svc)
{
int ret;
- ret = (svc->rcv_req_flag != 0);
+
+ ret = (svc->rcv_req_flag == 1);
return ret || data->abort;
}
@@ -3843,14 +4146,17 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
int ret = 0;
struct qseecom_registered_listener_list *this_lstnr;
+ mutex_lock(&listener_access_lock);
this_lstnr = __qseecom_find_svc(data->listener.id);
if (!this_lstnr) {
pr_err("Invalid listener ID\n");
+ mutex_unlock(&listener_access_lock);
return -ENODATA;
}
+ mutex_unlock(&listener_access_lock);
while (1) {
- if (wait_event_freezable(this_lstnr->rcv_req_wq,
+ if (wait_event_interruptible(this_lstnr->rcv_req_wq,
__qseecom_listener_has_rcvd_req(data,
this_lstnr))) {
pr_debug("Interrupted: exiting Listener Service = %d\n",
@@ -3861,10 +4167,12 @@ static int qseecom_receive_req(struct qseecom_dev_handle *data)
if (data->abort) {
pr_err("Aborting Listener Service = %d\n",
- (uint32_t)data->listener.id);
+ (uint32_t)data->listener.id);
return -ENODEV;
}
+ mutex_lock(&listener_access_lock);
this_lstnr->rcv_req_flag = 0;
+ mutex_unlock(&listener_access_lock);
break;
}
return ret;
@@ -4080,9 +4388,19 @@ static int __qseecom_allocate_img_data(struct ion_handle **pihandle,
ion_phys_addr_t pa;
struct ion_handle *ihandle = NULL;
u8 *img_data = NULL;
+ int retry = 0;
+ int ion_flag = ION_FLAG_CACHED;
- ihandle = ion_alloc(qseecom.ion_clnt, fw_size,
- SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), 0);
+ do {
+ if (retry++) {
+ mutex_unlock(&app_access_lock);
+ msleep(QSEECOM_TA_ION_ALLOCATE_DELAY);
+ mutex_lock(&app_access_lock);
+ }
+ ihandle = ion_alloc(qseecom.ion_clnt, fw_size,
+ SZ_4K, ION_HEAP(ION_QSECOM_HEAP_ID), ion_flag);
+ } while (IS_ERR_OR_NULL(ihandle) &&
+ (retry <= QSEECOM_TA_ION_ALLOCATE_MAX_ATTEMP));
if (IS_ERR_OR_NULL(ihandle)) {
pr_err("ION alloc failed\n");
@@ -4228,8 +4546,12 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname,
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, cmd_buf, cmd_len,
&resp, sizeof(resp));
if (ret) {
- pr_err("scm_call to load failed : ret %d\n", ret);
- ret = -EIO;
+ pr_err("scm_call to load failed : ret %d, result %x\n",
+ ret, resp.result);
+ if (resp.result == QSEOS_RESULT_FAIL_APP_ALREADY_LOADED)
+ ret = -EEXIST;
+ else
+ ret = -EIO;
goto exit_disable_clk_vote;
}
@@ -4239,10 +4561,14 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname,
break;
case QSEOS_RESULT_INCOMPLETE:
ret = __qseecom_process_incomplete_cmd(data, &resp);
- if (ret)
- pr_err("process_incomplete_cmd FAILED\n");
- else
+ if (ret) {
+ pr_err("incomp_cmd err %d, %d, unload %d %s\n",
+ ret, resp.result, resp.data, appname);
+ __qseecom_unload_app(data, resp.data);
+ ret = -EFAULT;
+ } else {
*app_id = resp.data;
+ }
break;
case QSEOS_RESULT_FAILURE:
pr_err("scm call failed with response QSEOS_RESULT FAILURE\n");
@@ -4438,6 +4764,9 @@ int qseecom_start_app(struct qseecom_handle **handle,
uint32_t fw_size, app_arch;
uint32_t app_id = 0;
+ __wakeup_unregister_listener_kthread();
+ __wakeup_unload_app_kthread();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4455,19 +4784,13 @@ int qseecom_start_app(struct qseecom_handle **handle,
}
*handle = kzalloc(sizeof(struct qseecom_handle), GFP_KERNEL);
- if (!(*handle)) {
- pr_err("failed to allocate memory for kernel client handle\n");
+ if (!(*handle))
return -ENOMEM;
- }
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
- pr_err("kmalloc failed\n");
- if (ret == 0) {
- kfree(*handle);
- *handle = NULL;
- }
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto exit_handle_free;
}
data->abort = 0;
data->type = QSEECOM_CLIENT_APP;
@@ -4482,18 +4805,17 @@ int qseecom_start_app(struct qseecom_handle **handle,
ION_HEAP(ION_QSECOM_HEAP_ID), 0);
if (IS_ERR_OR_NULL(data->client.ihandle)) {
pr_err("Ion client could not retrieve the handle\n");
- kfree(data);
- kfree(*handle);
- *handle = NULL;
- return -EINVAL;
+ ret = -ENOMEM;
+ goto exit_data_free;
}
mutex_lock(&app_access_lock);
+recheck:
app_ireq.qsee_cmd_id = QSEOS_APP_LOOKUP_COMMAND;
strlcpy(app_ireq.app_name, app_name, MAX_APP_NAME_SIZE);
ret = __qseecom_check_app_exists(app_ireq, &app_id);
if (ret)
- goto err;
+ goto exit_ion_free;
strlcpy(data->client.app_name, app_name, MAX_APP_NAME_SIZE);
if (app_id) {
@@ -4518,28 +4840,31 @@ int qseecom_start_app(struct qseecom_handle **handle,
pr_debug("%s: Loading app for the first time'\n",
qseecom.pdev->init_name);
ret = __qseecom_load_fw(data, app_name, &app_id);
- if (ret < 0)
- goto err;
+ if (ret == -EEXIST) {
+ pr_err("recheck if TA %s is loaded\n", app_name);
+ goto recheck;
+ } else if (ret < 0)
+ goto exit_ion_free;
}
data->client.app_id = app_id;
if (!found_app) {
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
pr_err("kmalloc for app entry failed\n");
- ret = -ENOMEM;
- goto err;
+ ret = -ENOMEM;
+ goto exit_ion_free;
}
entry->app_id = app_id;
entry->ref_cnt = 1;
strlcpy(entry->app_name, app_name, MAX_APP_NAME_SIZE);
if (__qseecom_get_fw_size(app_name, &fw_size, &app_arch)) {
ret = -EIO;
- kfree(entry);
- goto err;
+ goto exit_entry_free;
}
entry->app_arch = app_arch;
entry->app_blocked = false;
entry->blocked_on_listener_id = 0;
+ entry->check_block = 0;
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_add_tail(&entry->list, &qseecom.registered_app_list_head);
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
@@ -4551,7 +4876,7 @@ int qseecom_start_app(struct qseecom_handle **handle,
if (ret) {
pr_err("Cannot get phys_addr for the Ion Client, ret = %d\n",
ret);
- goto err;
+ goto exit_entry_free;
}
/* Populate the structure for sending scm call to load image */
@@ -4560,7 +4885,7 @@ int qseecom_start_app(struct qseecom_handle **handle,
if (IS_ERR_OR_NULL(data->client.sb_virt)) {
pr_err("ION memory mapping for client shared buf failed\n");
ret = -ENOMEM;
- goto err;
+ goto exit_entry_free;
}
data->client.user_virt_sb_base = (uintptr_t)data->client.sb_virt;
data->client.sb_phys = (phys_addr_t)pa;
@@ -4570,9 +4895,8 @@ int qseecom_start_app(struct qseecom_handle **handle,
kclient_entry = kzalloc(sizeof(*kclient_entry), GFP_KERNEL);
if (!kclient_entry) {
- pr_err("kmalloc failed\n");
ret = -ENOMEM;
- goto err;
+ goto exit_ion_unmap_kernel;
}
kclient_entry->handle = *handle;
@@ -4582,13 +4906,28 @@ int qseecom_start_app(struct qseecom_handle **handle,
spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags);
mutex_unlock(&app_access_lock);
+ __wakeup_unload_app_kthread();
return 0;
-err:
- kfree(data);
- kfree(*handle);
- *handle = NULL;
+exit_ion_unmap_kernel:
+ if (!IS_ERR_OR_NULL(data->client.ihandle))
+ ion_unmap_kernel(qseecom.ion_clnt, data->client.ihandle);
+exit_entry_free:
+ kfree(entry);
+exit_ion_free:
mutex_unlock(&app_access_lock);
+ if (!IS_ERR_OR_NULL(data->client.ihandle)) {
+ ion_free(qseecom.ion_clnt, data->client.ihandle);
+ data->client.ihandle = NULL;
+ }
+exit_data_free:
+ kfree(data);
+exit_handle_free:
+ if (*handle) {
+ kfree(*handle);
+ *handle = NULL;
+ }
+ __wakeup_unload_app_kthread();
return ret;
}
EXPORT_SYMBOL(qseecom_start_app);
@@ -4602,6 +4941,9 @@ int qseecom_shutdown_app(struct qseecom_handle **handle)
unsigned long flags = 0;
bool found_handle = false;
+ __wakeup_unregister_listener_kthread();
+ __wakeup_unload_app_kthread();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4637,7 +4979,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle)
kzfree(kclient);
*handle = NULL;
}
-
+ __wakeup_unload_app_kthread();
return ret;
}
EXPORT_SYMBOL(qseecom_shutdown_app);
@@ -4650,6 +4992,9 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
struct qseecom_dev_handle *data;
bool perf_enabled = false;
+ __wakeup_unregister_listener_kthread();
+ __wakeup_unload_app_kthread();
+
if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) {
pr_err("Not allowed to be called in %d state\n",
atomic_read(&qseecom.qseecom_state));
@@ -4680,11 +5025,11 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
}
}
/*
- * On targets where crypto clock is handled by HLOS,
- * if clk_access_cnt is zero and perf_enabled is false,
- * then the crypto clock was not enabled before sending cmd
- * to tz, qseecom will enable the clock to avoid service failure.
- */
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd
+ * to tz, qseecom will enable the clock to avoid service failure.
+ */
if (!qseecom.no_clock_support &&
!qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
pr_debug("ce clock is not enabled!\n");
@@ -4725,6 +5070,7 @@ EXPORT_SYMBOL(qseecom_send_command);
int qseecom_set_bandwidth(struct qseecom_handle *handle, bool high)
{
int ret = 0;
+
if ((handle == NULL) || (handle->dev == NULL)) {
pr_err("No valid kernel client\n");
return -EINVAL;
@@ -4772,6 +5118,7 @@ int qseecom_process_listener_from_smcinvoke(struct scm_desc *desc)
resp.data = desc->ret[2]; /*listener_id*/
dummy_private_data.client.app_id = desc->ret[1];
+ dummy_private_data.client.from_smcinvoke = true;
dummy_app_entry.app_id = desc->ret[1];
mutex_lock(&app_access_lock);
@@ -5441,6 +5788,7 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
MAX_APP_NAME_SIZE);
entry->app_blocked = false;
entry->blocked_on_listener_id = 0;
+ entry->check_block = 0;
spin_lock_irqsave(&qseecom.registered_app_list_lock,
flags);
list_add_tail(&entry->list,
@@ -5722,9 +6070,9 @@ static int __qseecom_update_current_key_user_info(
int ret;
if (usage < QSEOS_KM_USAGE_DISK_ENCRYPTION ||
- usage >= QSEOS_KM_USAGE_MAX) {
- pr_err("Error:: unsupported usage %d\n", usage);
- return -EFAULT;
+ usage >= QSEOS_KM_USAGE_MAX) {
+ pr_err("Error:: unsupported usage %d\n", usage);
+ return -EFAULT;
}
ret = __qseecom_enable_clk(CLK_QSEE);
if (ret)
@@ -5890,6 +6238,9 @@ static int qseecom_create_key(struct qseecom_dev_handle *data,
else
flags |= QSEECOM_ICE_FDE_KEY_SIZE_16_BYTE;
+ if (qseecom.enable_key_wrap_in_ks == true)
+ flags |= ENABLE_KEY_WRAP_IN_KS;
+
generate_key_ireq.flags = flags;
generate_key_ireq.qsee_command_id = QSEOS_GENERATE_KEY;
memset((void *)generate_key_ireq.key_id,
@@ -5938,10 +6289,12 @@ static int qseecom_create_key(struct qseecom_dev_handle *data,
memcpy((void *)set_key_ireq.hash32,
(void *)create_key_req.hash32,
QSEECOM_HASH_SIZE);
-
- /* It will return false if it is GPCE based crypto instance or
- ICE is setup properly */
- if (qseecom_enable_ice_setup(create_key_req.usage))
+ /*
+ * It will return false if it is GPCE based crypto instance or
+ * ICE is setup properly
+ */
+ ret = qseecom_enable_ice_setup(create_key_req.usage);
+ if (ret)
goto free_buf;
do {
@@ -6066,9 +6419,12 @@ static int qseecom_wipe_key(struct qseecom_dev_handle *data,
clear_key_ireq.key_id[i] = QSEECOM_INVALID_KEY_ID;
memset((void *)clear_key_ireq.hash32, 0, QSEECOM_HASH_SIZE);
- /* It will return false if it is GPCE based crypto instance or
- ICE is setup properly */
- if (qseecom_enable_ice_setup(wipe_key_req.usage))
+ /*
+ * It will return false if it is GPCE based crypto instance or
+ * ICE is setup properly
+ */
+ ret = qseecom_enable_ice_setup(wipe_key_req.usage);
+ if (ret)
goto free_buf;
ret = __qseecom_set_clear_ce_key(data, wipe_key_req.usage,
@@ -6149,7 +6505,7 @@ static int qseecom_update_key_user_info(struct qseecom_dev_handle *data,
}
static int qseecom_is_es_activated(void __user *argp)
{
- struct qseecom_is_es_activated_req req;
+ struct qseecom_is_es_activated_req req = {0};
struct qseecom_command_scm_resp resp;
int ret;
@@ -6240,9 +6596,9 @@ static int qseecom_mdtp_cipher_dip(void __user *argp)
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;
- break;
+ pr_err("invalid parameters\n");
+ ret = -EINVAL;
+ break;
}
/* Copy the input buffer from userspace to kernel space */
@@ -6285,7 +6641,7 @@ static int qseecom_mdtp_cipher_dip(void __user *argp)
if (ret)
break;
- ret = scm_call2(TZ_MDTP_CIPHER_DIP_ID, &desc);
+ ret = __qseecom_scm_call2_locked(TZ_MDTP_CIPHER_DIP_ID, &desc);
__qseecom_disable_clk(CLK_QSEE);
@@ -6400,10 +6756,10 @@ static int __qseecom_qteec_handle_pre_alc_fd(struct qseecom_dev_handle *data,
return -ENOMEM;
}
/*
- * Allocate a buffer, populate it with number of entry plus
- * each sg entry's phy addr and lenth; then return the
- * phy_addr of the buffer.
- */
+ * Allocate a buffer, populate it with number of entry plus
+ * each sg entry's phy addr and length; then return the
+ * phy_addr of the buffer.
+ */
size = sizeof(uint32_t) +
sizeof(struct qseecom_sg_entry) * sg_ptr->nents;
size = (size + PAGE_SIZE) & PAGE_MASK;
@@ -6604,6 +6960,12 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
(char *)data->client.app_name);
return -ENOENT;
}
+ if (__qseecom_find_pending_unload_app(data->client.app_id,
+ data->client.app_name)) {
+ pr_err("app %d (%s) unload is pending\n",
+ data->client.app_id, data->client.app_name);
+ return -ENOENT;
+ }
req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
(uintptr_t)req->req_ptr);
@@ -6807,6 +7169,12 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
(char *)data->client.app_name);
return -ENOENT;
}
+ if (__qseecom_find_pending_unload_app(data->client.app_id,
+ data->client.app_name)) {
+ pr_err("app %d (%s) unload is pending\n",
+ data->client.app_id, data->client.app_name);
+ return -ENOENT;
+ }
/* validate offsets */
for (i = 0; i < MAX_ION_FD; i++) {
@@ -6937,61 +7305,8 @@ static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data)
}
}
-
-static int __qseecom_bus_scaling_enable(struct qseecom_dev_handle *data,
- bool *perf_enabled)
-{
- int ret = 0;
-
- if (qseecom.support_bus_scaling) {
- if (!data->mode) {
- mutex_lock(&qsee_bw_mutex);
- __qseecom_register_bus_bandwidth_needs(
- data, HIGH);
- mutex_unlock(&qsee_bw_mutex);
- }
- ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
- if (ret) {
- pr_err("Failed to set bw\n");
- ret = -EINVAL;
- goto exit;
- }
- }
- /*
- * On targets where crypto clock is handled by HLOS,
- * if clk_access_cnt is zero and perf_enabled is false,
- * then the crypto clock was not enabled before sending cmd
- * to tz, qseecom will enable the clock to avoid service failure.
- */
- if (!qseecom.no_clock_support &&
- !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
- pr_debug("ce clock is not enabled\n");
- ret = qseecom_perf_enable(data);
- if (ret) {
- pr_err("Failed to vote for clock with err %d\n",
- ret);
- ret = -EINVAL;
- goto exit;
- }
- *perf_enabled = true;
- }
-exit:
- return ret;
-}
-
-static void __qseecom_bus_scaling_disable(struct qseecom_dev_handle *data,
- bool perf_enabled)
-{
- if (qseecom.support_bus_scaling)
- __qseecom_add_bw_scale_down_timer(
- QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
- if (perf_enabled) {
- qsee_disable_clock_vote(data, CLK_DFAB);
- qsee_disable_clock_vote(data, CLK_SFPB);
- }
-}
-
-long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+long qseecom_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
{
int ret = 0;
struct qseecom_dev_handle *data = file->private_data;
@@ -7007,6 +7322,12 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
pr_err("Aborting qseecom driver\n");
return -ENODEV;
}
+ if (cmd != QSEECOM_IOCTL_RECEIVE_REQ &&
+ cmd != QSEECOM_IOCTL_SEND_RESP_REQ &&
+ cmd != QSEECOM_IOCTL_SEND_MODFD_RESP &&
+ cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64)
+ __wakeup_unregister_listener_kthread();
+ __wakeup_unload_app_kthread();
switch (cmd) {
case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: {
@@ -7017,17 +7338,18 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
pr_debug("ioctl register_listener_req()\n");
- mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
data->type = QSEECOM_LISTENER_SERVICE;
ret = qseecom_register_listener(data, argp);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- mutex_unlock(&app_access_lock);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_register_listener: %d\n", ret);
break;
}
+
case QSEECOM_IOCTL_UNREGISTER_LISTENER_REQ: {
if ((data->listener.id == 0) ||
(data->type != QSEECOM_LISTENER_SERVICE)) {
@@ -7037,12 +7359,12 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
}
pr_debug("ioctl unregister_listener_req()\n");
- mutex_lock(&app_access_lock);
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
ret = qseecom_unregister_listener(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
- mutex_unlock(&app_access_lock);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_unregister_listener: %d\n", ret);
break;
@@ -7057,14 +7379,50 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- ret = __qseecom_bus_scaling_enable(data, &perf_enabled);
- if (ret) {
- mutex_unlock(&app_access_lock);
- break;
+ if (qseecom.support_bus_scaling) {
+ /* register bus bw in case the client doesn't do it */
+ if (!data->mode) {
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_register_bus_bandwidth_needs(
+ data, HIGH);
+ mutex_unlock(&qsee_bw_mutex);
+ }
+ ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
+ if (ret) {
+ pr_err("Failed to set bw.\n");
+ ret = -EINVAL;
+ mutex_unlock(&app_access_lock);
+ break;
+ }
+ }
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd to
+ * tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.no_clock_support &&
+ !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ perf_enabled = true;
}
atomic_inc(&data->ioctl_count);
ret = qseecom_send_cmd(data, argp);
- __qseecom_bus_scaling_disable(data, perf_enabled);
+ if (qseecom.support_bus_scaling)
+ __qseecom_add_bw_scale_down_timer(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -7083,17 +7441,52 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- ret = __qseecom_bus_scaling_enable(data, &perf_enabled);
- if (ret) {
- mutex_unlock(&app_access_lock);
- break;
+ if (qseecom.support_bus_scaling) {
+ if (!data->mode) {
+ mutex_lock(&qsee_bw_mutex);
+ __qseecom_register_bus_bandwidth_needs(
+ data, HIGH);
+ mutex_unlock(&qsee_bw_mutex);
+ }
+ ret = qseecom_scale_bus_bandwidth_timer(INACTIVE);
+ if (ret) {
+ pr_err("Failed to set bw.\n");
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ }
+ /*
+ * On targets where crypto clock is handled by HLOS,
+ * if clk_access_cnt is zero and perf_enabled is false,
+ * then the crypto clock was not enabled before sending cmd to
+ * tz, qseecom will enable the clock to avoid service failure.
+ */
+ if (!qseecom.no_clock_support &&
+ !qseecom.qsee.clk_access_cnt && !data->perf_enabled) {
+ pr_debug("ce clock is not enabled!\n");
+ ret = qseecom_perf_enable(data);
+ if (ret) {
+ pr_err("Failed to vote for clock with err %d\n",
+ ret);
+ mutex_unlock(&app_access_lock);
+ ret = -EINVAL;
+ break;
+ }
+ perf_enabled = true;
}
atomic_inc(&data->ioctl_count);
if (cmd == QSEECOM_IOCTL_SEND_MODFD_CMD_REQ)
ret = qseecom_send_modfd_cmd(data, argp);
else
ret = qseecom_send_modfd_cmd_64(data, argp);
- __qseecom_bus_scaling_disable(data, perf_enabled);
+ if (qseecom.support_bus_scaling)
+ __qseecom_add_bw_scale_down_timer(
+ QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
+ if (perf_enabled) {
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ }
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -7126,6 +7519,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ret = -EINVAL;
break;
}
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
if (!qseecom.qsee_reentrancy_support)
ret = qseecom_send_resp();
@@ -7133,6 +7527,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ret = qseecom_reentrancy_send_resp(data);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_send_resp: %d\n", ret);
break;
@@ -7174,6 +7569,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed load_app request: %d\n", ret);
+ __wakeup_unload_app_kthread();
break;
}
case QSEECOM_IOCTL_UNLOAD_APP_REQ: {
@@ -7192,6 +7588,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed unload_app request: %d\n", ret);
+ __wakeup_unload_app_kthread();
break;
}
case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: {
@@ -7475,6 +7872,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ret = -EINVAL;
break;
}
+ mutex_lock(&listener_access_lock);
atomic_inc(&data->ioctl_count);
if (cmd == QSEECOM_IOCTL_SEND_MODFD_RESP)
ret = qseecom_send_modfd_resp(data, argp);
@@ -7482,6 +7880,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
ret = qseecom_send_modfd_resp_64(data, argp);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
+ mutex_unlock(&listener_access_lock);
if (ret)
pr_err("failed qseecom_send_mod_resp: %d\n", ret);
__qseecom_clean_data_sglistinfo(data);
@@ -7502,14 +7901,8 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- ret = __qseecom_bus_scaling_enable(data, &perf_enabled);
- if (ret) {
- mutex_unlock(&app_access_lock);
- break;
- }
atomic_inc(&data->ioctl_count);
ret = qseecom_qteec_open_session(data, argp);
- __qseecom_bus_scaling_disable(data, perf_enabled);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -7557,14 +7950,8 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
}
/* Only one client allowed here at a time */
mutex_lock(&app_access_lock);
- ret = __qseecom_bus_scaling_enable(data, &perf_enabled);
- if (ret) {
- mutex_unlock(&app_access_lock);
- break;
- }
atomic_inc(&data->ioctl_count);
ret = qseecom_qteec_invoke_modfd_cmd(data, argp);
- __qseecom_bus_scaling_disable(data, perf_enabled);
atomic_dec(&data->ioctl_count);
wake_up_all(&data->abort_wq);
mutex_unlock(&app_access_lock);
@@ -7634,10 +8021,8 @@ static int qseecom_open(struct inode *inode, struct file *file)
struct qseecom_dev_handle *data;
data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- pr_err("kmalloc failed\n");
+ if (!data)
return -ENOMEM;
- }
file->private_data = data;
data->abort = 0;
data->type = QSEECOM_GENERIC;
@@ -7649,24 +8034,57 @@ static int qseecom_open(struct inode *inode, struct file *file)
return ret;
}
+static void __qseecom_release_disable_clk(struct qseecom_dev_handle *data)
+{
+ if (qseecom.no_clock_support)
+ return;
+ if (qseecom.support_bus_scaling) {
+ mutex_lock(&qsee_bw_mutex);
+ if (data->mode != INACTIVE) {
+ qseecom_unregister_bus_bandwidth_needs(data);
+ if (qseecom.cumulative_mode == INACTIVE)
+ __qseecom_set_msm_bus_request(INACTIVE);
+ }
+ mutex_unlock(&qsee_bw_mutex);
+ } else {
+ if (data->fast_load_enabled)
+ qsee_disable_clock_vote(data, CLK_SFPB);
+ if (data->perf_enabled)
+ qsee_disable_clock_vote(data, CLK_DFAB);
+ }
+}
+
static int qseecom_release(struct inode *inode, struct file *file)
{
struct qseecom_dev_handle *data = file->private_data;
int ret = 0;
+ bool free_private_data = true;
- if (data->released == false) {
+ __qseecom_release_disable_clk(data);
+ if (!data->released) {
pr_debug("data: released=false, type=%d, mode=%d, data=0x%pK\n",
data->type, data->mode, data);
switch (data->type) {
case QSEECOM_LISTENER_SERVICE:
- mutex_lock(&app_access_lock);
+ pr_debug("release lsnr svc %d\n", data->listener.id);
+ mutex_lock(&listener_access_lock);
ret = qseecom_unregister_listener(data);
- mutex_unlock(&app_access_lock);
+ if (!ret)
+ free_private_data = false;
+ data->listener.release_called = true;
+ mutex_unlock(&listener_access_lock);
+ __wakeup_unregister_listener_kthread();
break;
case QSEECOM_CLIENT_APP:
- mutex_lock(&app_access_lock);
- ret = qseecom_unload_app(data, true);
- mutex_unlock(&app_access_lock);
+ pr_debug("release app %d (%s)\n",
+ data->client.app_id, data->client.app_name);
+ if (data->client.app_id) {
+ free_private_data = false;
+ mutex_lock(&unload_app_pending_list_lock);
+ ret = qseecom_prepare_unload_app(data);
+ mutex_unlock(&unload_app_pending_list_lock);
+ __wakeup_unload_app_kthread();
+ }
break;
case QSEECOM_SECURE_SERVICE:
case QSEECOM_GENERIC:
@@ -7683,34 +8101,19 @@ static int qseecom_release(struct inode *inode, struct file *file)
}
}
- if (qseecom.support_bus_scaling) {
- mutex_lock(&qsee_bw_mutex);
- if (data->mode != INACTIVE) {
- qseecom_unregister_bus_bandwidth_needs(data);
- if (qseecom.cumulative_mode == INACTIVE) {
- ret = __qseecom_set_msm_bus_request(INACTIVE);
- if (ret)
- pr_err("Fail to scale down bus\n");
- }
- }
- mutex_unlock(&qsee_bw_mutex);
- } else {
- if (data->fast_load_enabled == true)
- qsee_disable_clock_vote(data, CLK_SFPB);
- if (data->perf_enabled == true)
- qsee_disable_clock_vote(data, CLK_DFAB);
- }
- kfree(data);
-
+ if (free_private_data)
+ kfree(data);
return ret;
}
+#ifndef CONFIG_COMPAT
+#define compat_qseecom_ioctl NULL
+#endif
+
static const struct file_operations qseecom_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = qseecom_ioctl,
-#ifdef CONFIG_COMPAT
.compat_ioctl = compat_qseecom_ioctl,
-#endif
.open = qseecom_open,
.release = qseecom_release
};
@@ -7762,14 +8165,14 @@ static int __qseecom_init_clk(enum qseecom_ce_hw_instance ce)
/* Get CE3 src core clk. */
qclk->ce_core_src_clk = clk_get(pdev, core_clk_src);
if (!IS_ERR(qclk->ce_core_src_clk)) {
- rc = clk_set_rate(qclk->ce_core_src_clk,
- qseecom.ce_opp_freq_hz);
- if (rc) {
- clk_put(qclk->ce_core_src_clk);
- qclk->ce_core_src_clk = NULL;
- pr_err("Unable to set the core src clk @%uMhz.\n",
- qseecom.ce_opp_freq_hz/CE_CLK_DIV);
- return -EIO;
+ rc = clk_set_rate(qclk->ce_core_src_clk,
+ qseecom.ce_opp_freq_hz);
+ if (rc) {
+ clk_put(qclk->ce_core_src_clk);
+ qclk->ce_core_src_clk = NULL;
+ pr_err("Unable to set the core src clk @%uMhz.\n",
+ qseecom.ce_opp_freq_hz/CE_CLK_DIV);
+ return -EIO;
}
} else {
pr_warn("Unable to get CE core src clk, set to NULL\n");
@@ -8525,17 +8928,23 @@ static int qseecom_probe(struct platform_device *pdev)
}
INIT_LIST_HEAD(&qseecom.registered_listener_list_head);
- spin_lock_init(&qseecom.registered_listener_list_lock);
INIT_LIST_HEAD(&qseecom.registered_app_list_head);
spin_lock_init(&qseecom.registered_app_list_lock);
+ INIT_LIST_HEAD(&qseecom.unregister_lsnr_pending_list_head);
INIT_LIST_HEAD(&qseecom.registered_kclient_list_head);
spin_lock_init(&qseecom.registered_kclient_list_lock);
init_waitqueue_head(&qseecom.send_resp_wq);
+ init_waitqueue_head(&qseecom.register_lsnr_pending_wq);
+ init_waitqueue_head(&qseecom.unregister_lsnr_kthread_wq);
+ INIT_LIST_HEAD(&qseecom.unload_app_pending_list_head);
+ init_waitqueue_head(&qseecom.unload_app_kthread_wq);
qseecom.send_resp_flag = 0;
qseecom.qsee_version = QSEEE_VERSION_00;
+ mutex_lock(&app_access_lock);
rc = qseecom_scm_call(6, 3, &feature, sizeof(feature),
&resp, sizeof(resp));
+ mutex_unlock(&app_access_lock);
pr_info("qseecom.qsee_version = 0x%x\n", resp.result);
if (rc) {
pr_err("Failed to get QSEE version info %d\n", rc);
@@ -8550,11 +8959,7 @@ static int qseecom_probe(struct platform_device *pdev)
qseecom.ion_clnt = msm_ion_client_create("qseecom-kernel");
if (IS_ERR_OR_NULL(qseecom.ion_clnt)) {
pr_err("Ion client cannot be created\n");
-
- if (qseecom.ion_clnt != ERR_PTR(-EPROBE_DEFER))
- rc = -ENOMEM;
- else
- rc = -EPROBE_DEFER;
+ rc = -ENOMEM;
goto exit_del_cdev;
}
@@ -8601,6 +9006,14 @@ static int qseecom_probe(struct platform_device *pdev)
qseecom.qsee_reentrancy_support);
}
+ qseecom.enable_key_wrap_in_ks =
+ of_property_read_bool((&pdev->dev)->of_node,
+ "qcom,enable-key-wrap-in-ks");
+ if (qseecom.enable_key_wrap_in_ks) {
+ pr_warn("qseecom.enable_key_wrap_in_ks = %d\n",
+ qseecom.enable_key_wrap_in_ks);
+ }
+
/*
* The qseecom bus scaling flag can not be enabled when
* crypto clock is not handled by HLOS.
@@ -8686,9 +9099,11 @@ static int qseecom_probe(struct platform_device *pdev)
rc = -EIO;
goto exit_deinit_clock;
}
+ mutex_lock(&app_access_lock);
rc = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
cmd_buf, cmd_len,
&resp, sizeof(resp));
+ mutex_unlock(&app_access_lock);
__qseecom_disable_clk(CLK_QSEE);
if (rc || (resp.result != QSEOS_RESULT_SUCCESS)) {
pr_err("send secapp reg fail %d resp.res %d\n",
@@ -8727,9 +9142,36 @@ static int qseecom_probe(struct platform_device *pdev)
if (!qseecom.qsee_perf_client)
pr_err("Unable to register bus client\n");
+ /*create a kthread to process pending listener unregister task */
+ qseecom.unregister_lsnr_kthread_task = kthread_run(
+ __qseecom_unregister_listener_kthread_func,
+ NULL, "qseecom-unreg-lsnr");
+ if (IS_ERR(qseecom.unregister_lsnr_kthread_task)) {
+ pr_err("failed to create kthread to unregister listener\n");
+ rc = -EINVAL;
+ goto exit_deinit_clock;
+ }
+ atomic_set(&qseecom.unregister_lsnr_kthread_state,
+ LSNR_UNREG_KT_SLEEP);
+
+ /*create a kthread to process pending ta unloading task */
+ qseecom.unload_app_kthread_task = kthread_run(
+ __qseecom_unload_app_kthread_func,
+ NULL, "qseecom-unload-ta");
+ if (IS_ERR(qseecom.unload_app_kthread_task)) {
+ pr_err("failed to create kthread to unload ta\n");
+ rc = -EINVAL;
+ goto exit_kill_unreg_lsnr_kthread;
+ }
+ atomic_set(&qseecom.unload_app_kthread_state,
+ UNLOAD_APP_KT_SLEEP);
+
atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY);
return 0;
+exit_kill_unreg_lsnr_kthread:
+ kthread_stop(qseecom.unregister_lsnr_kthread_task);
+
exit_deinit_clock:
__qseecom_deinit_clk(CLK_QSEE);
if ((qseecom.qsee.instance != qseecom.ce_drv.instance) &&
@@ -8843,6 +9285,10 @@ static int qseecom_remove(struct platform_device *pdev)
ion_client_destroy(qseecom.ion_clnt);
+ kthread_stop(qseecom.unload_app_kthread_task);
+
+ kthread_stop(qseecom.unregister_lsnr_kthread_task);
+
cdev_del(&qseecom.cdev);
device_destroy(driver_class, qseecom_device_no);
@@ -8858,8 +9304,8 @@ static int qseecom_suspend(struct platform_device *pdev, pm_message_t state)
{
int ret = 0;
struct qseecom_clk *qclk;
- qclk = &qseecom.qsee;
+ qclk = &qseecom.qsee;
atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_SUSPEND);
if (qseecom.no_clock_support)
return 0;
@@ -8900,8 +9346,8 @@ static int qseecom_resume(struct platform_device *pdev)
int mode = 0;
int ret = 0;
struct qseecom_clk *qclk;
- qclk = &qseecom.qsee;
+ qclk = &qseecom.qsee;
if (qseecom.no_clock_support)
goto exit;
@@ -8974,7 +9420,8 @@ exit:
atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY);
return ret;
}
-static struct of_device_id qseecom_match[] = {
+
+static const struct of_device_id qseecom_match[] = {
{
.compatible = "qcom,qseecom",
},
@@ -9004,7 +9451,7 @@ static void qseecom_exit(void)
}
MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("Qualcomm Secure Execution Environment Communicator");
+MODULE_DESCRIPTION("QTI Secure Execution Environment Communicator");
module_init(qseecom_init);
module_exit(qseecom_exit);
diff --git a/include/soc/qcom/qseecomi.h b/include/soc/qcom/qseecomi.h
index e199978302bf..46b1c5da4e90 100644
--- a/include/soc/qcom/qseecomi.h
+++ b/include/soc/qcom/qseecomi.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2019, 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
@@ -19,6 +19,7 @@
#define QSEECOM_KEY_ID_SIZE 32
#define QSEOS_RESULT_FAIL_SEND_CMD_NO_THREAD -19 /*0xFFFFFFED*/
+#define QSEOS_RESULT_FAIL_APP_ALREADY_LOADED -38 /*0xFFFFFFDA*/
#define QSEOS_RESULT_FAIL_UNSUPPORTED_CE_PIPE -63
#define QSEOS_RESULT_FAIL_KS_OP -64
#define QSEOS_RESULT_FAIL_KEY_ID_EXISTS -65
@@ -104,82 +105,82 @@ enum qseecom_qsee_reentrancy_phase {
QSEE_REENTRANCY_PHASE_MAX = 0xFF
};
-__packed struct qsee_apps_region_info_ireq {
+struct qsee_apps_region_info_ireq {
uint32_t qsee_cmd_id;
uint32_t addr;
uint32_t size;
-};
+} __attribute__((__packed__));
-__packed struct qsee_apps_region_info_64bit_ireq {
+struct qsee_apps_region_info_64bit_ireq {
uint32_t qsee_cmd_id;
uint64_t addr;
uint32_t size;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_check_app_ireq {
+struct qseecom_check_app_ireq {
uint32_t qsee_cmd_id;
char app_name[MAX_APP_NAME_SIZE];
-};
+} __attribute__((__packed__));
-__packed struct qseecom_load_app_ireq {
+struct qseecom_load_app_ireq {
uint32_t qsee_cmd_id;
uint32_t mdt_len; /* Length of the mdt file */
uint32_t img_len; /* Length of .bxx and .mdt files */
uint32_t phy_addr; /* phy addr of the start of image */
char app_name[MAX_APP_NAME_SIZE]; /* application name*/
-};
+} __attribute__((__packed__));
-__packed struct qseecom_load_app_64bit_ireq {
+struct qseecom_load_app_64bit_ireq {
uint32_t qsee_cmd_id;
uint32_t mdt_len;
uint32_t img_len;
uint64_t phy_addr;
char app_name[MAX_APP_NAME_SIZE];
-};
+} __attribute__((__packed__));
-__packed struct qseecom_unload_app_ireq {
+struct qseecom_unload_app_ireq {
uint32_t qsee_cmd_id;
uint32_t app_id;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_load_lib_image_ireq {
+struct qseecom_load_lib_image_ireq {
uint32_t qsee_cmd_id;
uint32_t mdt_len;
uint32_t img_len;
uint32_t phy_addr;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_load_lib_image_64bit_ireq {
+struct qseecom_load_lib_image_64bit_ireq {
uint32_t qsee_cmd_id;
uint32_t mdt_len;
uint32_t img_len;
uint64_t phy_addr;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_unload_lib_image_ireq {
+struct qseecom_unload_lib_image_ireq {
uint32_t qsee_cmd_id;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_register_listener_ireq {
+struct qseecom_register_listener_ireq {
uint32_t qsee_cmd_id;
uint32_t listener_id;
uint32_t sb_ptr;
uint32_t sb_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_register_listener_64bit_ireq {
+struct qseecom_register_listener_64bit_ireq {
uint32_t qsee_cmd_id;
uint32_t listener_id;
uint64_t sb_ptr;
uint32_t sb_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_unregister_listener_ireq {
+struct qseecom_unregister_listener_ireq {
uint32_t qsee_cmd_id;
uint32_t listener_id;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_client_send_data_ireq {
+struct qseecom_client_send_data_ireq {
uint32_t qsee_cmd_id;
uint32_t app_id;
uint32_t req_ptr;
@@ -188,9 +189,9 @@ __packed struct qseecom_client_send_data_ireq {
uint32_t rsp_len;
uint32_t sglistinfo_ptr;
uint32_t sglistinfo_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_client_send_data_64bit_ireq {
+struct qseecom_client_send_data_64bit_ireq {
uint32_t qsee_cmd_id;
uint32_t app_id;
uint64_t req_ptr;
@@ -199,36 +200,36 @@ __packed struct qseecom_client_send_data_64bit_ireq {
uint32_t rsp_len;
uint64_t sglistinfo_ptr;
uint32_t sglistinfo_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_reg_log_buf_ireq {
+struct qseecom_reg_log_buf_ireq {
uint32_t qsee_cmd_id;
uint32_t phy_addr;
uint32_t len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_reg_log_buf_64bit_ireq {
+struct qseecom_reg_log_buf_64bit_ireq {
uint32_t qsee_cmd_id;
uint64_t phy_addr;
uint32_t len;
-};
+} __attribute__((__packed__));
/* send_data resp */
-__packed struct qseecom_client_listener_data_irsp {
+struct qseecom_client_listener_data_irsp {
uint32_t qsee_cmd_id;
uint32_t listener_id;
uint32_t status;
uint32_t sglistinfo_ptr;
uint32_t sglistinfo_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_client_listener_data_64bit_irsp {
+struct qseecom_client_listener_data_64bit_irsp {
uint32_t qsee_cmd_id;
uint32_t listener_id;
uint32_t status;
uint64_t sglistinfo_ptr;
uint32_t sglistinfo_len;
-};
+} __attribute__((__packed__));
/*
* struct qseecom_command_scm_resp - qseecom response buffer
@@ -237,40 +238,40 @@ __packed struct qseecom_client_listener_data_64bit_irsp {
* buffer
* @sb_in_rsp_len: length of command response
*/
-__packed struct qseecom_command_scm_resp {
+struct qseecom_command_scm_resp {
uint32_t result;
enum qseecom_command_scm_resp_type resp_type;
unsigned int data;
-};
+} __attribute__((__packed__));
struct qseecom_rpmb_provision_key {
uint32_t key_type;
};
-__packed struct qseecom_client_send_service_ireq {
+struct qseecom_client_send_service_ireq {
uint32_t qsee_cmd_id;
uint32_t key_type; /* in */
unsigned int req_len; /* in */
uint32_t rsp_ptr; /* in/out */
unsigned int rsp_len; /* in/out */
-};
+} __attribute__((__packed__));
-__packed struct qseecom_client_send_service_64bit_ireq {
+struct qseecom_client_send_service_64bit_ireq {
uint32_t qsee_cmd_id;
uint32_t key_type;
unsigned int req_len;
uint64_t rsp_ptr;
unsigned int rsp_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_key_generate_ireq {
+struct qseecom_key_generate_ireq {
uint32_t qsee_command_id;
uint32_t flags;
uint8_t key_id[QSEECOM_KEY_ID_SIZE];
uint8_t hash32[QSEECOM_HASH_SIZE];
-};
+} __attribute__((__packed__));
-__packed struct qseecom_key_select_ireq {
+struct qseecom_key_select_ireq {
uint32_t qsee_command_id;
uint32_t ce;
uint32_t pipe;
@@ -278,33 +279,33 @@ __packed struct qseecom_key_select_ireq {
uint32_t flags;
uint8_t key_id[QSEECOM_KEY_ID_SIZE];
uint8_t hash32[QSEECOM_HASH_SIZE];
-};
+} __attribute__((__packed__));
-__packed struct qseecom_key_delete_ireq {
+struct qseecom_key_delete_ireq {
uint32_t qsee_command_id;
uint32_t flags;
uint8_t key_id[QSEECOM_KEY_ID_SIZE];
uint8_t hash32[QSEECOM_HASH_SIZE];
-};
+} __attribute__((__packed__));
-__packed struct qseecom_key_userinfo_update_ireq {
+struct qseecom_key_userinfo_update_ireq {
uint32_t qsee_command_id;
uint32_t flags;
uint8_t key_id[QSEECOM_KEY_ID_SIZE];
uint8_t current_hash32[QSEECOM_HASH_SIZE];
uint8_t new_hash32[QSEECOM_HASH_SIZE];
-};
+} __attribute__((__packed__));
-__packed struct qseecom_key_max_count_query_ireq {
+struct qseecom_key_max_count_query_ireq {
uint32_t flags;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_key_max_count_query_irsp {
+struct qseecom_key_max_count_query_irsp {
uint32_t max_key_count;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_qteec_ireq {
+struct qseecom_qteec_ireq {
uint32_t qsee_cmd_id;
uint32_t app_id;
uint32_t req_ptr;
@@ -313,9 +314,9 @@ __packed struct qseecom_qteec_ireq {
uint32_t resp_len;
uint32_t sglistinfo_ptr;
uint32_t sglistinfo_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_qteec_64bit_ireq {
+struct qseecom_qteec_64bit_ireq {
uint32_t qsee_cmd_id;
uint32_t app_id;
uint64_t req_ptr;
@@ -324,21 +325,20 @@ __packed struct qseecom_qteec_64bit_ireq {
uint32_t resp_len;
uint64_t sglistinfo_ptr;
uint32_t sglistinfo_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_client_send_fsm_key_req {
+struct qseecom_client_send_fsm_key_req {
uint32_t qsee_cmd_id;
uint32_t req_ptr;
uint32_t req_len;
uint32_t rsp_ptr;
uint32_t rsp_len;
-};
+} __attribute__((__packed__));
-__packed struct qseecom_continue_blocked_request_ireq {
+struct qseecom_continue_blocked_request_ireq {
uint32_t qsee_cmd_id;
uint32_t app_or_session_id; /*legacy: app_id; smcinvoke: session_id*/
-};
-
+} __attribute__((__packed__));
/********** ARMV8 SMC INTERFACE TZ MACRO *******************/
@@ -352,7 +352,8 @@ __packed struct qseecom_continue_blocked_request_ireq {
/*----------------------------------------------------------------------------
* Owning Entity IDs (defined by ARM SMC doc)
- * -------------------------------------------------------------------------*/
+ * ---------------------------------------------------------------------------
+ */
#define TZ_OWNER_ARM 0 /** ARM Architecture call ID */
#define TZ_OWNER_CPU 1 /** CPU service call ID */
#define TZ_OWNER_SIP 2 /** SIP service call ID */
@@ -380,18 +381,18 @@ __packed struct qseecom_continue_blocked_request_ireq {
#define TZ_OWNER_OS_RESERVED_13 62
#define TZ_OWNER_OS_RESERVED_14 63
-#define TZ_SVC_INFO 6 /* Misc. information services */
+#define TZ_SVC_INFO 6 /* Misc. information services */
/** Trusted Application call groups */
-#define TZ_SVC_APP_ID_PLACEHOLDER 0 /* SVC bits will contain App ID */
+#define TZ_SVC_APP_ID_PLACEHOLDER 0 /* SVC bits will contain App ID */
/** General helper macro to create a bitmask from bits low to high. */
#define TZ_MASK_BITS(h, l) ((0xffffffff >> (32 - ((h - l) + 1))) << l)
-/**
- Macro used to define an SMC ID based on the owner ID,
- service ID, and function number.
-*/
+/*
+ * Macro used to define an SMC ID based on the owner ID,
+ * service ID, and function number.
+ */
#define TZ_SYSCALL_CREATE_SMC_ID(o, s, f) \
((uint32_t)((((o & 0x3f) << 24) | (s & 0xff) << 8) | (f & 0xff)))
@@ -412,8 +413,8 @@ __packed struct qseecom_continue_blocked_request_ireq {
((p9&TZ_SYSCALL_PARAM_TYPE_MASK)<<20)+ \
((p10&TZ_SYSCALL_PARAM_TYPE_MASK)<<22))
-/**
- Macros used to create the Parameter ID associated with the syscall
+/*
+ * Macros used to create the Parameter ID associated with the syscall
*/
#define TZ_SYSCALL_CREATE_PARAM_ID_0 0
#define TZ_SYSCALL_CREATE_PARAM_ID_1(p1) \
@@ -437,8 +438,8 @@ __packed struct qseecom_continue_blocked_request_ireq {
#define TZ_SYSCALL_CREATE_PARAM_ID_10(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \
TZ_SYSCALL_CREATE_PARAM_ID(10, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
-/**
- Macro used to obtain the Parameter ID associated with the syscall
+/*
+ * Macro used to obtain the Parameter ID associated with the syscall
*/
#define TZ_SYSCALL_GET_PARAM_ID(CMD_ID) CMD_ID ## _PARAM_ID
diff --git a/include/uapi/linux/qseecom.h b/include/uapi/linux/qseecom.h
index 40c96eef3059..63e2a5f2b671 100644
--- a/include/uapi/linux/qseecom.h
+++ b/include/uapi/linux/qseecom.h
@@ -7,6 +7,11 @@
#define MAX_ION_FD 4
#define MAX_APP_NAME_SIZE 64
#define QSEECOM_HASH_SIZE 32
+
+/* qseecom_ta_heap allocation retry delay (ms) and max attemp count */
+#define QSEECOM_TA_ION_ALLOCATE_DELAY 50
+#define QSEECOM_TA_ION_ALLOCATE_MAX_ATTEMP 20
+
/*
* struct qseecom_register_listener_req -
* for register listener ioctl request