aboutsummaryrefslogtreecommitdiff
path: root/drivers/misc/qseecom.c
diff options
context:
space:
mode:
authorRygebin <kaankulahli@gmail.com>2017-06-20 14:29:27 +0000
committerRygebin <kaankulahli@gmail.com>2017-06-20 14:29:27 +0000
commitafa9ad70f02491fbe10df2203f8f2fa42f956228 (patch)
treeb6dce4ed04f62fd443721a94ac3e7f81427e0ad1 /drivers/misc/qseecom.c
parent582eb92a1e8bf6c0e743774c1fb550e630715433 (diff)
parent08d1ec9238c605a9a5cf1229fd60961efcd21ff1 (diff)
Merge https://github.com/OneDeveloperOrganization/android_kernel_google_shamrock into n7.1HEADn7.1
Diffstat (limited to 'drivers/misc/qseecom.c')
-rw-r--r--drivers/misc/qseecom.c666
1 files changed, 536 insertions, 130 deletions
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index b228952f554..79f5c7843fd 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -1,6 +1,6 @@
/*Qualcomm Secure Execution Environment Communicator (QSEECOM) driver
*
- * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -78,6 +78,9 @@
/* Encrypt/Decrypt Data Integrity Partition (DIP) for MDTP */
#define SCM_MDTP_CIPHER_DIP 0x01
+/* Maximum Allowed Size (128K) of Data Integrity Partition (DIP) for MDTP */
+#define MAX_DIP 0x20000
+
#define RPMB_SERVICE 0x2000
#define SSD_SERVICE 0x3000
@@ -116,6 +119,35 @@ static DEFINE_MUTEX(qsee_bw_mutex);
static DEFINE_MUTEX(app_access_lock);
static DEFINE_MUTEX(clk_access_lock);
+struct sglist_info {
+ uint32_t indexAndFlags;
+ uint32_t sizeOrCount;
+};
+
+/*
+ * The 31th bit indicates only one or multiple physical address inside
+ * the request buffer. If it is set, the index locates a single physical addr
+ * inside the request buffer, and `sizeOrCount` is the size of the memory being
+ * shared at that physical address.
+ * Otherwise, the index locates an array of {start, len} pairs (a
+ * "scatter/gather list"), and `sizeOrCount` gives the number of entries in
+ * that array.
+ *
+ * The 30th bit indicates 64 or 32bit address; when it is set, physical addr
+ * and scatter gather entry sizes are 64-bit values. Otherwise, 32-bit values.
+ *
+ * The bits [0:29] of `indexAndFlags` hold an offset into the request buffer.
+ */
+#define SGLISTINFO_SET_INDEX_FLAG(c, s, i) \
+ ((uint32_t)(((c & 1) << 31) | ((s & 1) << 30) | (i & 0x3fffffff)))
+
+#define SGLISTINFO_TABLE_SIZE (sizeof(struct sglist_info) * MAX_ION_FD)
+
+#define FEATURE_ID_WHITELIST 15 /*whitelist feature id*/
+
+#define MAKE_WHITELIST_VERSION(major, minor, patch) \
+ (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF))
+
struct qseecom_registered_listener_list {
struct list_head list;
struct qseecom_register_listener_req svc;
@@ -130,6 +162,8 @@ struct qseecom_registered_listener_list {
bool listener_in_use;
/* wq for thread blocked on this listener*/
wait_queue_head_t listener_block_app_wq;
+ struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+ uint32_t sglist_cnt;
};
struct qseecom_registered_app_list {
@@ -181,6 +215,7 @@ struct qseecom_control {
uint32_t qseos_version;
uint32_t qsee_version;
struct device *pdev;
+ bool whitelist_support;
bool commonlib_loaded;
bool commonlib64_loaded;
struct ion_handle *cmnlib_ion_handle;
@@ -254,6 +289,9 @@ struct qseecom_dev_handle {
bool perf_enabled;
bool fast_load_enabled;
enum qseecom_bandwidth_request_mode mode;
+ struct sglist_info sglistinfo_ptr[MAX_ION_FD];
+ uint32_t sglist_cnt;
+ bool use_legacy_cmd;
};
struct qseecom_key_id_usage_desc {
@@ -513,6 +551,34 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
ret = scm_call2(smc_id, &desc);
break;
}
+ case QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST: {
+ struct qseecom_client_listener_data_irsp *req;
+ struct qseecom_client_listener_data_64bit_irsp *req_64;
+
+ smc_id =
+ TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_ID;
+ desc.arginfo =
+ TZ_OS_LISTENER_RESPONSE_HANDLER_WITH_WHITELIST_PARAM_ID;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ req =
+ (struct qseecom_client_listener_data_irsp *)
+ req_buf;
+ desc.args[0] = req->listener_id;
+ desc.args[1] = req->status;
+ desc.args[2] = req->sglistinfo_ptr;
+ desc.args[3] = req->sglistinfo_len;
+ } else {
+ req_64 =
+ (struct qseecom_client_listener_data_64bit_irsp *)
+ req_buf;
+ desc.args[0] = req_64->listener_id;
+ desc.args[1] = req_64->status;
+ desc.args[2] = req_64->sglistinfo_ptr;
+ desc.args[3] = req_64->sglistinfo_len;
+ }
+ ret = scm_call2(smc_id, &desc);
+ break;
+ }
case QSEOS_LOAD_EXTERNAL_ELF_COMMAND: {
struct qseecom_load_app_ireq *req;
struct qseecom_load_app_64bit_ireq *req_64bit;
@@ -568,6 +634,38 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
ret = scm_call2(smc_id, &desc);
break;
}
+ case QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST: {
+ struct qseecom_client_send_data_ireq *req;
+ struct qseecom_client_send_data_64bit_ireq *req_64bit;
+
+ smc_id = TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID;
+ desc.arginfo =
+ TZ_APP_QSAPP_SEND_DATA_WITH_WHITELIST_ID_PARAM_ID;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ req = (struct qseecom_client_send_data_ireq *)
+ req_buf;
+ desc.args[0] = req->app_id;
+ desc.args[1] = req->req_ptr;
+ desc.args[2] = req->req_len;
+ desc.args[3] = req->rsp_ptr;
+ desc.args[4] = req->rsp_len;
+ desc.args[5] = req->sglistinfo_ptr;
+ desc.args[6] = req->sglistinfo_len;
+ } else {
+ req_64bit =
+ (struct qseecom_client_send_data_64bit_ireq *)
+ req_buf;
+ desc.args[0] = req_64bit->app_id;
+ desc.args[1] = req_64bit->req_ptr;
+ desc.args[2] = req_64bit->req_len;
+ desc.args[3] = req_64bit->rsp_ptr;
+ desc.args[4] = req_64bit->rsp_len;
+ desc.args[5] = req_64bit->sglistinfo_ptr;
+ desc.args[6] = req_64bit->sglistinfo_len;
+ }
+ ret = scm_call2(smc_id, &desc);
+ break;
+ }
case QSEOS_RPMB_PROVISION_KEY_COMMAND: {
struct qseecom_client_send_service_ireq *req;
req = (struct qseecom_client_send_service_ireq *)
@@ -695,6 +793,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
ret = scm_call2(smc_id, &desc);
break;
}
+ case QSEOS_TEE_OPEN_SESSION_WHITELIST: {
+ struct qseecom_qteec_ireq *req;
+ struct qseecom_qteec_64bit_ireq *req_64bit;
+
+ smc_id = TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID;
+ desc.arginfo =
+ TZ_APP_GPAPP_OPEN_SESSION_WITH_WHITELIST_ID_PARAM_ID;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ req = (struct qseecom_qteec_ireq *)req_buf;
+ desc.args[0] = req->app_id;
+ desc.args[1] = req->req_ptr;
+ desc.args[2] = req->req_len;
+ desc.args[3] = req->resp_ptr;
+ desc.args[4] = req->resp_len;
+ desc.args[5] = req->sglistinfo_ptr;
+ desc.args[6] = req->sglistinfo_len;
+ } else {
+ req_64bit = (struct qseecom_qteec_64bit_ireq *)
+ req_buf;
+ desc.args[0] = req_64bit->app_id;
+ desc.args[1] = req_64bit->req_ptr;
+ desc.args[2] = req_64bit->req_len;
+ desc.args[3] = req_64bit->resp_ptr;
+ desc.args[4] = req_64bit->resp_len;
+ desc.args[5] = req_64bit->sglistinfo_ptr;
+ desc.args[6] = req_64bit->sglistinfo_len;
+ }
+ ret = scm_call2(smc_id, &desc);
+ break;
+ }
case QSEOS_TEE_INVOKE_COMMAND: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
@@ -719,6 +847,36 @@ static int qseecom_scm_call2(uint32_t svc_id, uint32_t tz_cmd_id,
ret = scm_call2(smc_id, &desc);
break;
}
+ case QSEOS_TEE_INVOKE_COMMAND_WHITELIST: {
+ struct qseecom_qteec_ireq *req;
+ struct qseecom_qteec_64bit_ireq *req_64bit;
+
+ smc_id = TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID;
+ desc.arginfo =
+ TZ_APP_GPAPP_INVOKE_COMMAND_WITH_WHITELIST_ID_PARAM_ID;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ req = (struct qseecom_qteec_ireq *)req_buf;
+ desc.args[0] = req->app_id;
+ desc.args[1] = req->req_ptr;
+ desc.args[2] = req->req_len;
+ desc.args[3] = req->resp_ptr;
+ desc.args[4] = req->resp_len;
+ desc.args[5] = req->sglistinfo_ptr;
+ desc.args[6] = req->sglistinfo_len;
+ } else {
+ req_64bit = (struct qseecom_qteec_64bit_ireq *)
+ req_buf;
+ desc.args[0] = req_64bit->app_id;
+ desc.args[1] = req_64bit->req_ptr;
+ desc.args[2] = req_64bit->req_len;
+ desc.args[3] = req_64bit->resp_ptr;
+ desc.args[4] = req_64bit->resp_len;
+ desc.args[5] = req_64bit->sglistinfo_ptr;
+ desc.args[6] = req_64bit->sglistinfo_len;
+ }
+ ret = scm_call2(smc_id, &desc);
+ break;
+ }
case QSEOS_TEE_CLOSE_SESSION: {
struct qseecom_qteec_ireq *req;
struct qseecom_qteec_64bit_ireq *req_64bit;
@@ -946,7 +1104,7 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data,
return -EBUSY;
}
- new_entry = kmalloc(sizeof(*new_entry), GFP_KERNEL);
+ new_entry = kzalloc(sizeof(*new_entry), GFP_KERNEL);
if (!new_entry) {
pr_err("kmalloc failed\n");
return -ENOMEM;
@@ -1398,6 +1556,16 @@ static int __qseecom_qseos_fail_return_resp_tz(struct qseecom_dev_handle *data,
return ret;
}
+static void __qseecom_clean_listener_sglistinfo(
+ struct qseecom_registered_listener_list *ptr_svc)
+{
+ if (ptr_svc->sglist_cnt) {
+ memset(ptr_svc->sglistinfo_ptr, 0,
+ SGLISTINFO_TABLE_SIZE);
+ ptr_svc->sglist_cnt = 0;
+ }
+}
+
static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
struct qseecom_command_scm_resp *resp)
{
@@ -1406,9 +1574,14 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
uint32_t lstnr;
unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp;
+ struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit;
struct qseecom_registered_listener_list *ptr_svc = NULL;
sigset_t new_sigset;
sigset_t old_sigset;
+ uint32_t status;
+ void *cmd_buf = NULL;
+ size_t cmd_len;
+ struct sglist_info *table = NULL;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
@@ -1420,6 +1593,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
list_for_each_entry(ptr_svc,
&qseecom.registered_listener_list_head, list) {
if (ptr_svc->svc.listener_id == lstnr) {
+ ptr_svc->listener_in_use = true;
ptr_svc->rcv_req_flag = 1;
wake_up_interruptible(&ptr_svc->rcv_req_wq);
break;
@@ -1467,14 +1641,42 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
rc = -ENODEV;
- send_data_rsp.status = QSEOS_RESULT_FAILURE;
+ status = QSEOS_RESULT_FAILURE;
} else {
- send_data_rsp.status = QSEOS_RESULT_SUCCESS;
+ status = QSEOS_RESULT_SUCCESS;
}
qseecom.send_resp_flag = 0;
- send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
- send_data_rsp.listener_id = lstnr;
+ ptr_svc->send_resp_flag = 0;
+ table = ptr_svc->sglistinfo_ptr;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ send_data_rsp.listener_id = lstnr;
+ send_data_rsp.status = status;
+ send_data_rsp.sglistinfo_ptr =
+ (uint32_t)virt_to_phys(table);
+ send_data_rsp.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ cmd_buf = (void *)&send_data_rsp;
+ cmd_len = sizeof(send_data_rsp);
+ } else {
+ send_data_rsp_64bit.listener_id = lstnr;
+ send_data_rsp_64bit.status = status;
+ send_data_rsp_64bit.sglistinfo_ptr =
+ virt_to_phys(table);
+ send_data_rsp_64bit.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ cmd_buf = (void *)&send_data_rsp_64bit;
+ cmd_len = sizeof(send_data_rsp_64bit);
+ }
+ if (qseecom.whitelist_support == false)
+ *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
+ else
+ *(uint32_t *)cmd_buf =
+ QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
if (ptr_svc)
msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
@@ -1484,9 +1686,9 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
__qseecom_enable_clk(CLK_QSEE);
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
- (const void *)&send_data_rsp,
- sizeof(send_data_rsp), resp,
- sizeof(*resp));
+ cmd_buf, cmd_len, resp, sizeof(*resp));
+ ptr_svc->listener_in_use = false;
+ __qseecom_clean_listener_sglistinfo(ptr_svc);
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
ret, data->client.app_id);
@@ -1519,9 +1721,14 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
uint32_t lstnr;
unsigned long flags;
struct qseecom_client_listener_data_irsp send_data_rsp;
+ struct qseecom_client_listener_data_64bit_irsp send_data_rsp_64bit;
struct qseecom_registered_listener_list *ptr_svc = NULL;
sigset_t new_sigset;
sigset_t old_sigset;
+ uint32_t status;
+ void *cmd_buf = NULL;
+ size_t cmd_len;
+ struct sglist_info *table = NULL;
while (resp->result == QSEOS_RESULT_INCOMPLETE) {
lstnr = resp->data;
@@ -1585,13 +1792,38 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
pr_err("Abort clnt %d waiting on lstnr svc %d, ret %d",
data->client.app_id, lstnr, ret);
rc = -ENODEV;
- send_data_rsp.status = QSEOS_RESULT_FAILURE;
+ status = QSEOS_RESULT_FAILURE;
} else {
- send_data_rsp.status = QSEOS_RESULT_SUCCESS;
+ status = QSEOS_RESULT_SUCCESS;
}
-
- send_data_rsp.qsee_cmd_id = QSEOS_LISTENER_DATA_RSP_COMMAND;
- send_data_rsp.listener_id = lstnr;
+ table = ptr_svc->sglistinfo_ptr;
+ if (qseecom.qsee_version < QSEE_VERSION_40) {
+ send_data_rsp.listener_id = lstnr;
+ send_data_rsp.status = status;
+ send_data_rsp.sglistinfo_ptr =
+ (uint32_t)virt_to_phys(table);
+ send_data_rsp.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ cmd_buf = (void *)&send_data_rsp;
+ cmd_len = sizeof(send_data_rsp);
+ } else {
+ send_data_rsp_64bit.listener_id = lstnr;
+ send_data_rsp_64bit.status = status;
+ send_data_rsp_64bit.sglistinfo_ptr =
+ virt_to_phys(table);
+ send_data_rsp_64bit.sglistinfo_len =
+ SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
+ cmd_buf = (void *)&send_data_rsp_64bit;
+ cmd_len = sizeof(send_data_rsp_64bit);
+ }
+ if (qseecom.whitelist_support == false)
+ *(uint32_t *)cmd_buf = QSEOS_LISTENER_DATA_RSP_COMMAND;
+ else
+ *(uint32_t *)cmd_buf =
+ QSEOS_LISTENER_DATA_RSP_COMMAND_WHITELIST;
if (ptr_svc)
msm_ion_do_cache_op(qseecom.ion_clnt, ptr_svc->ihandle,
ptr_svc->sb_virt, ptr_svc->sb_length,
@@ -1601,11 +1833,9 @@ static int __qseecom_reentrancy_process_incomplete_cmd(
__qseecom_enable_clk(CLK_QSEE);
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
- (const void *)&send_data_rsp,
- sizeof(send_data_rsp), resp,
- sizeof(*resp));
-
+ cmd_buf, cmd_len, resp, sizeof(*resp));
ptr_svc->listener_in_use = false;
+ __qseecom_clean_listener_sglistinfo(ptr_svc);
wake_up_interruptible(&ptr_svc->listener_block_app_wq);
if (ret) {
@@ -2134,11 +2364,6 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
return -EINVAL;
}
- if ((!req_ptr->cmd_req_buf) || (!req_ptr->resp_buf)) {
- pr_err("Invalid req/resp buffer, exiting\n");
- return -EINVAL;
- }
-
/* Clients need to ensure req_buf is at base offset of shared buffer */
if ((uintptr_t)req_ptr->cmd_req_buf !=
data_ptr->client.user_virt_sb_base) {
@@ -2146,15 +2371,11 @@ int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
return -EINVAL;
}
- if (((uintptr_t)req_ptr->resp_buf <
- data_ptr->client.user_virt_sb_base) ||
- ((uintptr_t)req_ptr->resp_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))){
- pr_err("response buffer address not within shared bufffer\n");
+ if (data_ptr->client.sb_length <
+ sizeof(struct qseecom_rpmb_provision_key)) {
+ pr_err("shared buffer is too small to hold key type\n");
return -EINVAL;
}
-
req_buf = data_ptr->client.sb_virt;
send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
@@ -2181,36 +2402,6 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
return -EINVAL;
}
- if (((uintptr_t)req_ptr->cmd_req_buf <
- data_ptr->client.user_virt_sb_base) ||
- ((uintptr_t)req_ptr->cmd_req_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))) {
- pr_err("cmd buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if (((uintptr_t)req_ptr->resp_buf <
- data_ptr->client.user_virt_sb_base) ||
- ((uintptr_t)req_ptr->resp_buf >=
- (data_ptr->client.user_virt_sb_base +
- data_ptr->client.sb_length))){
- pr_err("response buffer address not within shared bufffer\n");
- return -EINVAL;
- }
-
- if ((req_ptr->cmd_req_len == 0) || (req_ptr->resp_len == 0) ||
- req_ptr->cmd_req_len > data_ptr->client.sb_length ||
- req_ptr->resp_len > data_ptr->client.sb_length) {
- pr_err("cmd buffer length or response buffer length not valid\n");
- return -EINVAL;
- }
-
- if (req_ptr->cmd_req_len > UINT_MAX - req_ptr->resp_len) {
- pr_err("Integer overflow detected in req_len & rsp_len, exiting now\n");
- return -EINVAL;
- }
-
reqd_len_sb_in = req_ptr->cmd_req_len + req_ptr->resp_len;
if (reqd_len_sb_in > data_ptr->client.sb_length) {
pr_err("Not enough memory to fit cmd_buf and resp_buf. ");
@@ -2232,28 +2423,11 @@ int __qseecom_process_fsm_key_svc_cmd(struct qseecom_dev_handle *data_ptr,
return ret;
}
-static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
- void __user *argp)
+static int __validate_send_service_cmd_inputs(struct qseecom_dev_handle *data,
+ struct qseecom_send_svc_cmd_req *req)
{
- int ret = 0;
- struct qseecom_client_send_service_ireq send_svc_ireq;
- struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
- struct qseecom_command_scm_resp resp;
- struct qseecom_send_svc_cmd_req req;
- void *send_req_ptr;
- size_t req_buf_size;
-
- /*struct qseecom_command_scm_resp resp;*/
-
- if (copy_from_user(&req,
- (void __user *)argp,
- sizeof(req))) {
- pr_err("copy_from_user failed\n");
- return -EFAULT;
- }
-
- if ((req.resp_buf == NULL) || (req.cmd_req_buf == NULL)) {
- pr_err("cmd buffer or response buffer is null\n");
+ if (!req || !req->resp_buf || !req->cmd_req_buf) {
+ pr_err("req or cmd buffer or response buffer is null\n");
return -EINVAL;
}
@@ -2277,6 +2451,86 @@ static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
return -EINVAL;
}
+ if (((uintptr_t)req->cmd_req_buf <
+ data->client.user_virt_sb_base) ||
+ ((uintptr_t)req->cmd_req_buf >=
+ (data->client.user_virt_sb_base + data->client.sb_length))) {
+ pr_err("cmd buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+ if (((uintptr_t)req->resp_buf <
+ data->client.user_virt_sb_base) ||
+ ((uintptr_t)req->resp_buf >=
+ (data->client.user_virt_sb_base + data->client.sb_length))) {
+ pr_err("response buffer address not within shared bufffer\n");
+ return -EINVAL;
+ }
+ if ((req->cmd_req_len == 0) || (req->resp_len == 0) ||
+ (req->cmd_req_len > data->client.sb_length) ||
+ (req->resp_len > data->client.sb_length)) {
+ pr_err("cmd buf length or response buf length not valid\n");
+ return -EINVAL;
+ }
+ if (req->cmd_req_len > UINT_MAX - req->resp_len) {
+ pr_err("Integer overflow detected in req_len & rsp_len\n");
+ return -EINVAL;
+ }
+
+ if ((req->cmd_req_len + req->resp_len) > data->client.sb_length) {
+ pr_debug("Not enough memory to fit cmd_buf.\n");
+ pr_debug("resp_buf. Required: %u, Available: %zu\n",
+ (req->cmd_req_len + req->resp_len),
+ data->client.sb_length);
+ return -ENOMEM;
+ }
+ if ((uintptr_t)req->cmd_req_buf > (ULONG_MAX - req->cmd_req_len)) {
+ pr_err("Integer overflow in req_len & cmd_req_buf\n");
+ return -EINVAL;
+ }
+ if ((uintptr_t)req->resp_buf > (ULONG_MAX - req->resp_len)) {
+ pr_err("Integer overflow in resp_len & resp_buf\n");
+ return -EINVAL;
+ }
+ if (data->client.user_virt_sb_base >
+ (ULONG_MAX - data->client.sb_length)) {
+ pr_err("Integer overflow in user_virt_sb_base & sb_length\n");
+ return -EINVAL;
+ }
+ if ((((uintptr_t)req->cmd_req_buf + req->cmd_req_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length)) ||
+ (((uintptr_t)req->resp_buf + req->resp_len) >
+ ((uintptr_t)data->client.user_virt_sb_base +
+ data->client.sb_length))) {
+ pr_err("cmd buf or resp buf is out of shared buffer region\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int qseecom_send_service_cmd(struct qseecom_dev_handle *data,
+ void __user *argp)
+{
+ int ret = 0;
+ struct qseecom_client_send_service_ireq send_svc_ireq;
+ struct qseecom_client_send_fsm_key_req send_fsm_key_svc_ireq;
+ struct qseecom_command_scm_resp resp;
+ struct qseecom_send_svc_cmd_req req;
+ void *send_req_ptr;
+ size_t req_buf_size;
+
+ /*struct qseecom_command_scm_resp resp;*/
+
+ if (copy_from_user(&req,
+ (void __user *)argp,
+ sizeof(req))) {
+ pr_err("copy_from_user failed\n");
+ return -EFAULT;
+ }
+
+ if (__validate_send_service_cmd_inputs(data, &req))
+ return -EINVAL;
+
data->type = QSEECOM_SECURE_SERVICE;
switch (req.cmd_id) {
@@ -2528,8 +2782,8 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
{
int ret = 0;
u32 reqd_len_sb_in = 0;
- struct qseecom_client_send_data_ireq send_data_req;
- struct qseecom_client_send_data_64bit_ireq send_data_req_64bit;
+ struct qseecom_client_send_data_ireq send_data_req = {0};
+ struct qseecom_client_send_data_64bit_ireq send_data_req_64bit = {0};
struct qseecom_command_scm_resp resp;
unsigned long flags;
struct qseecom_registered_app_list *ptr_app;
@@ -2537,6 +2791,7 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
int name_len = 0;
void *cmd_buf = NULL;
size_t cmd_len;
+ struct sglist_info *table = data->sglistinfo_ptr;
reqd_len_sb_in = req->cmd_req_len + req->resp_len;
/* find app_id & img_name from list */
@@ -2561,7 +2816,6 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
}
if (qseecom.qsee_version < QSEE_VERSION_40) {
- send_data_req.qsee_cmd_id = QSEOS_CLIENT_SEND_DATA_COMMAND;
send_data_req.app_id = data->client.app_id;
send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
data, (uintptr_t)req->cmd_req_buf));
@@ -2569,11 +2823,14 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
send_data_req.rsp_ptr = (uint32_t)(__qseecom_uvirt_to_kphys(
data, (uintptr_t)req->resp_buf));
send_data_req.rsp_len = req->resp_len;
+ send_data_req.sglistinfo_ptr =
+ (uint32_t)virt_to_phys(table);
+ send_data_req.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
cmd_buf = (void *)&send_data_req;
cmd_len = sizeof(struct qseecom_client_send_data_ireq);
} else {
- send_data_req_64bit.qsee_cmd_id =
- QSEOS_CLIENT_SEND_DATA_COMMAND;
send_data_req_64bit.app_id = data->client.app_id;
send_data_req_64bit.req_ptr = __qseecom_uvirt_to_kphys(data,
(uintptr_t)req->cmd_req_buf);
@@ -2595,10 +2852,20 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
send_data_req_64bit.rsp_len);
return -EFAULT;
}
+ send_data_req_64bit.sglistinfo_ptr =
+ (uint64_t)virt_to_phys(table);
+ send_data_req_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
cmd_buf = (void *)&send_data_req_64bit;
cmd_len = sizeof(struct qseecom_client_send_data_64bit_ireq);
}
+ if (qseecom.whitelist_support == false || data->use_legacy_cmd == true)
+ *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND;
+ else
+ *(uint32_t *)cmd_buf = QSEOS_CLIENT_SEND_DATA_COMMAND_WHITELIST;
+
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
reqd_len_sb_in,
@@ -2699,6 +2966,8 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
struct qseecom_send_modfd_cmd_req *req = NULL;
struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
struct qseecom_registered_listener_list *this_lstnr = NULL;
+ uint32_t offset;
+ struct sg_table *sg_ptr;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(data->type != QSEECOM_CLIENT_APP))
@@ -2720,7 +2989,6 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
}
for (i = 0; i < MAX_ION_FD; i++) {
- struct sg_table *sg_ptr = NULL;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(req->ifd_data[i].fd > 0)) {
ihandle = ion_import_dma_buf(qseecom.ion_clnt,
@@ -2852,14 +3120,37 @@ static int __qseecom_update_cmd_buf(void *msg, bool cleanup,
goto err;
}
}
- if (cleanup)
+
+ if (cleanup) {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_INV_CACHES);
- else
+ } else {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
+ if (data->type == QSEECOM_CLIENT_APP) {
+ offset = req->ifd_data[i].cmd_buf_offset;
+ data->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 0, offset);
+ data->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ data->sglist_cnt = i + 1;
+ } else {
+ offset = (lstnr_resp->ifd_data[i].cmd_buf_offset
+ + (uintptr_t)lstnr_resp->resp_buf_ptr -
+ (uintptr_t)this_lstnr->sb_virt);
+ this_lstnr->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 0, offset);
+ this_lstnr->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ this_lstnr->sglist_cnt = i + 1;
+ }
+ }
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -2883,6 +3174,8 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
struct qseecom_send_modfd_cmd_req *req = NULL;
struct qseecom_send_modfd_listener_resp *lstnr_resp = NULL;
struct qseecom_registered_listener_list *this_lstnr = NULL;
+ uint32_t offset;
+ struct sg_table *sg_ptr;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(data->type != QSEECOM_CLIENT_APP))
@@ -2904,7 +3197,6 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
}
for (i = 0; i < MAX_ION_FD; i++) {
- struct sg_table *sg_ptr = NULL;
if ((data->type != QSEECOM_LISTENER_SERVICE) &&
(req->ifd_data[i].fd > 0)) {
ihandle = ion_import_dma_buf(qseecom.ion_clnt,
@@ -2994,14 +3286,36 @@ static int __qseecom_update_cmd_buf_64(void *msg, bool cleanup,
sg = sg_next(sg);
}
}
- if (cleanup)
+ if (cleanup) {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_INV_CACHES);
- else
+ } else {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, len,
ION_IOC_CLEAN_INV_CACHES);
+ if (data->type == QSEECOM_CLIENT_APP) {
+ offset = req->ifd_data[i].cmd_buf_offset;
+ data->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 1, offset);
+ data->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ data->sglist_cnt = i + 1;
+ } else {
+ offset = (lstnr_resp->ifd_data[i].cmd_buf_offset
+ + (uintptr_t)lstnr_resp->resp_buf_ptr -
+ (uintptr_t)this_lstnr->sb_virt);
+ this_lstnr->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 1, offset);
+ this_lstnr->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ this_lstnr->sglist_cnt = i + 1;
+ }
+ }
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -3195,7 +3509,7 @@ static bool __qseecom_is_fw_image_valid(const struct firmware *fw_entry)
return true;
}
-static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size,
+static int __qseecom_get_fw_size(const char *appname, uint32_t *fw_size,
uint32_t *app_arch)
{
int ret = -1;
@@ -3233,14 +3547,21 @@ static int __qseecom_get_fw_size(char *appname, uint32_t *fw_size,
}
pr_debug("QSEE %s app, arch %u\n", appname, *app_arch);
release_firmware(fw_entry);
+ fw_entry = NULL;
for (i = 0; i < num_images; i++) {
memset(fw_name, 0, sizeof(fw_name));
snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
if (ret)
goto err;
+ if (*fw_size > U32_MAX - fw_entry->size) {
+ pr_err("QSEE %s app file size overflow\n", appname);
+ ret = -EINVAL;
+ goto err;
+ }
*fw_size += fw_entry->size;
release_firmware(fw_entry);
+ fw_entry = NULL;
}
return ret;
@@ -3251,8 +3572,9 @@ err:
return ret;
}
-static int __qseecom_get_fw_data(char *appname, u8 *img_data,
- struct qseecom_load_app_ireq *load_req)
+static int __qseecom_get_fw_data(const char *appname, u8 *img_data,
+ uint32_t fw_size,
+ struct qseecom_load_app_ireq *load_req)
{
int ret = -1;
int i = 0, rc = 0;
@@ -3272,6 +3594,12 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
}
load_req->img_len = fw_entry->size;
+ if (load_req->img_len > fw_size) {
+ pr_err("app %s size %zu is larger than buf size %u\n",
+ appname, fw_entry->size, fw_size);
+ ret = -EINVAL;
+ goto err;
+ }
memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
img_data_ptr = img_data_ptr + fw_entry->size;
load_req->mdt_len = fw_entry->size; /*Get MDT LEN*/
@@ -3290,6 +3618,7 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
goto err;
}
release_firmware(fw_entry);
+ fw_entry = NULL;
for (i = 0; i < num_images; i++) {
snprintf(fw_name, ARRAY_SIZE(fw_name), "%s.b%02d", appname, i);
ret = request_firmware(&fw_entry, fw_name, qseecom.pdev);
@@ -3297,10 +3626,17 @@ static int __qseecom_get_fw_data(char *appname, u8 *img_data,
pr_err("Failed to locate blob %s\n", fw_name);
goto err;
}
+ if ((fw_entry->size > U32_MAX - load_req->img_len) ||
+ (fw_entry->size + load_req->img_len > fw_size)) {
+ pr_err("Invalid file size for %s\n", fw_name);
+ ret = -EINVAL;
+ goto err;
+ }
memcpy(img_data_ptr, fw_entry->data, fw_entry->size);
img_data_ptr = img_data_ptr + fw_entry->size;
load_req->img_len += fw_entry->size;
release_firmware(fw_entry);
+ fw_entry = NULL;
}
return ret;
err:
@@ -3405,7 +3741,7 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname)
if (ret)
return ret;
- ret = __qseecom_get_fw_data(appname, img_data, &load_req);
+ ret = __qseecom_get_fw_data(appname, img_data, fw_size, &load_req);
if (ret) {
ret = -EIO;
goto exit_free_img_data;
@@ -3526,7 +3862,7 @@ static int qseecom_load_commonlib_image(struct qseecom_dev_handle *data,
if (ret)
return -EIO;
- ret = __qseecom_get_fw_data(cmnlib_name, img_data, &load_req);
+ ret = __qseecom_get_fw_data(cmnlib_name, img_data, fw_size, &load_req);
if (ret) {
ret = -EIO;
goto exit_free_img_data;
@@ -3894,8 +4230,11 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf,
}
perf_enabled = true;
}
+ if (!strcmp(data->client.app_name, "securemm"))
+ data->use_legacy_cmd = true;
ret = __qseecom_send_cmd(data, &req);
+ data->use_legacy_cmd = false;
if (qseecom.support_bus_scaling)
__qseecom_add_bw_scale_down_timer(
QSEECOM_SEND_CMD_CRYPTO_TIMEOUT);
@@ -5295,7 +5634,8 @@ static int qseecom_mdtp_cipher_dip(void __user *argp)
}
if (req.in_buf == NULL || req.out_buf == NULL ||
- req.in_buf_size == 0 || req.out_buf_size == 0 ||
+ req.in_buf_size == 0 || req.in_buf_size > MAX_DIP ||
+ req.out_buf_size == 0 || req.out_buf_size > MAX_DIP ||
req.direction > 1) {
pr_err("invalid parameters\n");
ret = -EINVAL;
@@ -5575,14 +5915,23 @@ static int __qseecom_update_qteec_req_buf(struct qseecom_qteec_modfd_req *req,
*update = (uint32_t)sg_dma_address(sg_ptr->sgl);
}
clean:
- if (cleanup)
+ if (cleanup) {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, sg->length,
ION_IOC_INV_CACHES);
- else
+ } else {
msm_ion_do_cache_op(qseecom.ion_clnt,
ihandle, NULL, sg->length,
ION_IOC_CLEAN_INV_CACHES);
+ data->sglistinfo_ptr[i].indexAndFlags =
+ SGLISTINFO_SET_INDEX_FLAG(
+ (sg_ptr->nents == 1), 0,
+ req->ifd_data[i].cmd_buf_offset);
+ data->sglistinfo_ptr[i].sizeOrCount =
+ (sg_ptr->nents == 1) ?
+ sg->length : sg_ptr->nents;
+ data->sglist_cnt = i + 1;
+ }
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -5607,6 +5956,7 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
uint32_t reqd_len_sb_in = 0;
void *cmd_buf = NULL;
size_t cmd_len;
+ struct sglist_info *table = data->sglistinfo_ptr;
ret = __qseecom_qteec_validate_msg(data, req);
if (ret)
@@ -5631,8 +5981,15 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
return -ENOENT;
}
+ if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
+ (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
+ ret = __qseecom_update_qteec_req_buf(
+ (struct qseecom_qteec_modfd_req *)req, data, false);
+ if (ret)
+ return ret;
+ }
+
if (qseecom.qsee_version < QSEE_VERSION_40) {
- ireq.qsee_cmd_id = cmd_id;
ireq.app_id = data->client.app_id;
ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
(uintptr_t)req->req_ptr);
@@ -5640,10 +5997,13 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
(uintptr_t)req->resp_ptr);
ireq.resp_len = req->resp_len;
+ ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
+ ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
cmd_buf = (void *)&ireq;
cmd_len = sizeof(struct qseecom_qteec_ireq);
} else {
- ireq_64bit.qsee_cmd_id = cmd_id;
ireq_64bit.app_id = data->client.app_id;
ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
(uintptr_t)req->req_ptr);
@@ -5663,17 +6023,19 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data,
ireq_64bit.resp_ptr, ireq_64bit.resp_len);
return -EFAULT;
}
+ ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
+ ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
cmd_buf = (void *)&ireq_64bit;
cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
}
+ if (qseecom.whitelist_support == true
+ && cmd_id == QSEOS_TEE_OPEN_SESSION)
+ *(uint32_t *)cmd_buf = QSEOS_TEE_OPEN_SESSION_WHITELIST;
+ else
+ *(uint32_t *)cmd_buf = cmd_id;
- if ((cmd_id == QSEOS_TEE_OPEN_SESSION) ||
- (cmd_id == QSEOS_TEE_REQUEST_CANCELLATION)) {
- ret = __qseecom_update_qteec_req_buf(
- (struct qseecom_qteec_modfd_req *)req, data, false);
- if (ret)
- return ret;
- }
reqd_len_sb_in = req->req_len + req->resp_len;
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
@@ -5771,6 +6133,9 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
uint32_t reqd_len_sb_in = 0;
void *cmd_buf = NULL;
size_t cmd_len;
+ struct sglist_info *table = data->sglistinfo_ptr;
+ void *req_ptr = NULL;
+ void *resp_ptr = NULL;
ret = copy_from_user(&req, argp,
sizeof(struct qseecom_qteec_modfd_req));
@@ -5782,6 +6147,8 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
(struct qseecom_qteec_req *)(&req));
if (ret)
return ret;
+ req_ptr = req.req_ptr;
+ resp_ptr = req.resp_ptr;
/* find app_id & img_name from list */
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
@@ -5802,45 +6169,56 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data,
return -ENOENT;
}
+ /* validate offsets */
+ for (i = 0; i < MAX_ION_FD; i++) {
+ if (req.ifd_data[i].fd) {
+ if (req.ifd_data[i].cmd_buf_offset >= req.req_len)
+ return -EINVAL;
+ }
+ }
+ req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
+ (uintptr_t)req.req_ptr);
+ req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
+ (uintptr_t)req.resp_ptr);
+ ret = __qseecom_update_qteec_req_buf(&req, data, false);
+ if (ret)
+ return ret;
+
if (qseecom.qsee_version < QSEE_VERSION_40) {
- ireq.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND;
ireq.app_id = data->client.app_id;
ireq.req_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
- (uintptr_t)req.req_ptr);
+ (uintptr_t)req_ptr);
ireq.req_len = req.req_len;
ireq.resp_ptr = (uint32_t)__qseecom_uvirt_to_kphys(data,
- (uintptr_t)req.resp_ptr);
+ (uintptr_t)resp_ptr);
ireq.resp_len = req.resp_len;
cmd_buf = (void *)&ireq;
cmd_len = sizeof(struct qseecom_qteec_ireq);
+ ireq.sglistinfo_ptr = (uint32_t)virt_to_phys(table);
+ ireq.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
} else {
- ireq_64bit.qsee_cmd_id = QSEOS_TEE_INVOKE_COMMAND;
ireq_64bit.app_id = data->client.app_id;
ireq_64bit.req_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
- (uintptr_t)req.req_ptr);
+ (uintptr_t)req_ptr);
ireq_64bit.req_len = req.req_len;
ireq_64bit.resp_ptr = (uint64_t)__qseecom_uvirt_to_kphys(data,
- (uintptr_t)req.resp_ptr);
+ (uintptr_t)resp_ptr);
ireq_64bit.resp_len = req.resp_len;
cmd_buf = (void *)&ireq_64bit;
cmd_len = sizeof(struct qseecom_qteec_64bit_ireq);
+ ireq_64bit.sglistinfo_ptr = (uint64_t)virt_to_phys(table);
+ ireq_64bit.sglistinfo_len = SGLISTINFO_TABLE_SIZE;
+ dmac_flush_range((void *)table,
+ (void *)table + SGLISTINFO_TABLE_SIZE);
}
reqd_len_sb_in = req.req_len + req.resp_len;
+ if (qseecom.whitelist_support == true)
+ *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND_WHITELIST;
+ else
+ *(uint32_t *)cmd_buf = QSEOS_TEE_INVOKE_COMMAND;
- /* validate offsets */
- for (i = 0; i < MAX_ION_FD; i++) {
- if (req.ifd_data[i].fd) {
- if (req.ifd_data[i].cmd_buf_offset >= req.req_len)
- return -EINVAL;
- }
- }
- req.req_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
- (uintptr_t)req.req_ptr);
- req.resp_ptr = (void *)__qseecom_uvirt_to_kvirt(data,
- (uintptr_t)req.resp_ptr);
- ret = __qseecom_update_qteec_req_buf(&req, data, false);
- if (ret)
- return ret;
msm_ion_do_cache_op(qseecom.ion_clnt, data->client.ihandle,
data->client.sb_virt,
reqd_len_sb_in,
@@ -5903,6 +6281,15 @@ static int qseecom_qteec_request_cancellation(struct qseecom_dev_handle *data,
return ret;
}
+static void __qseecom_clean_data_sglistinfo(struct qseecom_dev_handle *data)
+{
+ if (data->sglist_cnt) {
+ memset(data->sglistinfo_ptr, 0,
+ SGLISTINFO_TABLE_SIZE);
+ data->sglist_cnt = 0;
+ }
+}
+
long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
int ret = 0;
@@ -6082,6 +6469,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed qseecom_send_cmd: %d\n", ret);
+ __qseecom_clean_data_sglistinfo(data);
break;
}
case QSEECOM_IOCTL_RECEIVE_REQ: {
@@ -6455,6 +6843,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
wake_up_all(&data->abort_wq);
if (ret)
pr_err("failed qseecom_send_mod_resp: %d\n", ret);
+ __qseecom_clean_data_sglistinfo(data);
break;
}
case QSEECOM_QTEEC_IOCTL_OPEN_SESSION_REQ: {
@@ -6479,6 +6868,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed open_session_cmd: %d\n", ret);
+ __qseecom_clean_data_sglistinfo(data);
break;
}
case QSEECOM_QTEEC_IOCTL_CLOSE_SESSION_REQ: {
@@ -6527,6 +6917,7 @@ long qseecom_ioctl(struct file *file, unsigned cmd, unsigned long arg)
mutex_unlock(&app_access_lock);
if (ret)
pr_err("failed Invoke cmd: %d\n", ret);
+ __qseecom_clean_data_sglistinfo(data);
break;
}
case QSEECOM_QTEEC_IOCTL_REQUEST_CANCELLATION_REQ: {
@@ -6578,7 +6969,6 @@ static int qseecom_open(struct inode *inode, struct file *file)
data->mode = INACTIVE;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
-
return ret;
}
@@ -6773,6 +7163,17 @@ static void __qseecom_deinit_clk(enum qseecom_ce_hw_instance ce)
qclk->instance = CLK_INVALID;
}
+/*
+ * Check whitelist feature, and if TZ feature version is < 1.0.0,
+ * then whitelist feature is not supported.
+ */
+static int qseecom_check_whitelist_feature(void)
+{
+ int version = scm_get_feat_version(FEATURE_ID_WHITELIST);
+
+ return version >= MAKE_WHITELIST_VERSION(1, 0, 0);
+}
+
static int qseecom_probe(struct platform_device *pdev)
{
int rc;
@@ -6804,6 +7205,7 @@ static int qseecom_probe(struct platform_device *pdev)
qseecom.app_block_ref_cnt = 0;
init_waitqueue_head(&qseecom.app_block_wq);
+ qseecom.whitelist_support = true;
rc = alloc_chrdev_region(&qseecom_device_no, 0, 1, QSEECOM_DEV);
if (rc < 0) {
@@ -7096,6 +7498,10 @@ static int qseecom_probe(struct platform_device *pdev)
qseecom.qsee_perf_client = msm_bus_scale_register_client(
qseecom_platform_support);
+ qseecom.whitelist_support = qseecom_check_whitelist_feature();
+ pr_warn("qseecom.whitelist_support = %d\n",
+ qseecom.whitelist_support);
+
if (!qseecom.qsee_perf_client)
pr_err("Unable to register bus client\n");
return 0;