Merge "qseecom: Add support to issue secure service cmd."
diff --git a/arch/arm/mach-msm/include/mach/qseecomi.h b/arch/arm/mach-msm/include/mach/qseecomi.h
index 3a13af8..ea02425 100644
--- a/arch/arm/mach-msm/include/mach/qseecomi.h
+++ b/arch/arm/mach-msm/include/mach/qseecomi.h
@@ -36,6 +36,8 @@
QSEOS_UNLOAD_SERV_IMAGE_COMMAND,
QSEOS_APP_REGION_NOTIFICATION,
QSEOS_REGISTER_LOG_BUF_COMMAND,
+ QSEE_RPMB_PROVISION_KEY_COMMAND,
+ QSEE_RPMB_ERASE_COMMAND,
QSEOS_CMD_MAX = 0xEFFFFFFF
};
@@ -127,4 +129,17 @@
unsigned int data;
};
+struct qseecom_rpmb_provision_key {
+ uint32_t key_type;
+};
+
+__packed struct qseecom_client_send_service_ireq {
+ uint32_t qsee_cmd_id;
+ uint32_t key_type; /* in */
+ unsigned int req_len; /* in */
+ void *rsp_ptr; /* in/out */
+ unsigned int rsp_len; /* in/out */
+};
+
+
#endif /* __QSEECOMI_H_ */
diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c
index 7d76b43..362a391 100644
--- a/drivers/misc/qseecom.c
+++ b/drivers/misc/qseecom.c
@@ -52,6 +52,7 @@
#define QSEEE_VERSION_00 0x400000
#define QSEE_VERSION_01 0x401000
#define QSEE_VERSION_02 0x402000
+#define QSEE_VERSION_03 0x403000
#define QSEOS_CHECK_VERSION_CMD 0x00001803
@@ -65,6 +66,13 @@
CLK_SFPB,
};
+enum qseecom_client_handle_type {
+ QSEECOM_CLIENT_APP = 0,
+ QSEECOM_LISTENER_SERVICE,
+ QSEECOM_SECURE_SERVICE,
+ QSEECOM_GENERIC,
+};
+
static struct class *driver_class;
static dev_t qseecom_device_no;
static struct cdev qseecom_cdev;
@@ -152,7 +160,7 @@
static struct qseecom_control qseecom;
struct qseecom_dev_handle {
- bool service;
+ enum qseecom_client_handle_type type;
union {
struct qseecom_client_handle client;
struct qseecom_listener_handle listener;
@@ -307,7 +315,7 @@
return ret;
}
data->listener.id = 0;
- data->service = true;
+ data->type = QSEECOM_LISTENER_SERVICE;
if (!__qseecom_is_svc_unique(data, &rcvd_lstnr)) {
pr_err("Service is not unique and is already registered\n");
data->released = true;
@@ -544,13 +552,14 @@
sizeof(*resp));
if (ret) {
pr_err("scm_call() failed with err: %d (app_id = %d)\n",
- ret, data->client.app_id);
+ ret, data->client.app_id);
return ret;
}
- if (resp->result == QSEOS_RESULT_FAILURE) {
- pr_err("Response result %d FAIL (app_id = %d)\n",
- resp->result, data->client.app_id);
- return -EINVAL;
+ 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 (rc)
@@ -754,6 +763,17 @@
return 1;
}
+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);
+ data->client.ihandle = NULL;
+ }
+ return ret;
+}
+
static int qseecom_unload_app(struct qseecom_dev_handle *data)
{
unsigned long flags;
@@ -836,11 +856,7 @@
}
}
}
- 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);
- data->client.ihandle = NULL;
- }
+ qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
}
@@ -943,6 +959,96 @@
return ret;
}
+int __qseecom_process_rpmb_svc_cmd(struct qseecom_dev_handle *data_ptr,
+ struct qseecom_send_svc_cmd_req *req_ptr,
+ struct qseecom_client_send_service_ireq *send_svc_ireq_ptr)
+{
+ int ret = 0;
+ if ((req_ptr == NULL) || (send_svc_ireq_ptr == NULL)) {
+ pr_err("Error with pointer: req_ptr = %p, send_svc_ptr = %p\n",
+ req_ptr, send_svc_ireq_ptr);
+ return -EINVAL;
+ }
+ send_svc_ireq_ptr->qsee_cmd_id = req_ptr->cmd_id;
+ send_svc_ireq_ptr->key_type =
+ ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type;
+ send_svc_ireq_ptr->req_len = req_ptr->cmd_req_len;
+ send_svc_ireq_ptr->rsp_ptr = (void *)(__qseecom_uvirt_to_kphys(data_ptr,
+ (uint32_t)req_ptr->resp_buf));
+ send_svc_ireq_ptr->rsp_len = req_ptr->resp_len;
+
+ pr_debug("CMD ID (%x), KEY_TYPE (%d)\n", send_svc_ireq_ptr->qsee_cmd_id,
+ ((struct qseecom_rpmb_provision_key *)req_ptr->cmd_req_buf)->key_type);
+ return ret;
+}
+
+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_command_scm_resp resp;
+ struct qseecom_send_svc_cmd_req req;
+ /*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) {
+ pr_err("cmd buffer or response buffer is null\n");
+ return -EINVAL;
+ }
+
+ data->type = QSEECOM_SECURE_SERVICE;
+
+ switch (req.cmd_id) {
+ case QSEE_RPMB_PROVISION_KEY_COMMAND:
+ case QSEE_RPMB_ERASE_COMMAND:
+ if (__qseecom_process_rpmb_svc_cmd(data, &req,
+ &send_svc_ireq))
+ return -EINVAL;
+ break;
+ default:
+ pr_err("Unsupported cmd_id %d\n", req.cmd_id);
+ return -EINVAL;
+ }
+
+ ret = scm_call(SCM_SVC_TZSCHEDULER, 1, (const void *) &send_svc_ireq,
+ sizeof(send_svc_ireq),
+ &resp, sizeof(resp));
+ if (ret) {
+ pr_err("qseecom_scm_call failed with err: %d\n", ret);
+ return ret;
+ }
+
+ switch (resp.result) {
+ case QSEOS_RESULT_SUCCESS:
+ break;
+ case QSEOS_RESULT_INCOMPLETE:
+ pr_err("qseos_result_incomplete\n");
+ ret = __qseecom_process_incomplete_cmd(data, &resp);
+ if (ret) {
+ pr_err("process_incomplete_cmd fail: err: %d\n",
+ ret);
+ }
+ break;
+ case QSEOS_RESULT_FAILURE:
+ pr_err("process_incomplete_cmd failed err: %d\n", ret);
+ break;
+ default:
+ pr_err("Response result %d not supported\n",
+ resp.result);
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+
+}
+
static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
struct qseecom_send_cmd_req *req)
{
@@ -1504,7 +1610,7 @@
return -ENOMEM;
}
data->abort = 0;
- data->service = false;
+ data->type = QSEECOM_CLIENT_APP;
data->released = false;
data->client.app_id = ret;
data->client.sb_length = size;
@@ -2352,6 +2458,19 @@
mutex_unlock(&app_access_lock);
break;
}
+ case QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ: {
+ if (qseecom.qsee_version < QSEE_VERSION_03) {
+ pr_err("SEND_CMD_SERVICE_REQ: Invalid qsee version %u\n",
+ qseecom.qsee_version);
+ return -EINVAL;
+ }
+ mutex_lock(&app_access_lock);
+ atomic_inc(&data->ioctl_count);
+ ret = qseecom_send_service_cmd(data, argp);
+ atomic_dec(&data->ioctl_count);
+ mutex_unlock(&app_access_lock);
+ break;
+ }
default:
return -EINVAL;
}
@@ -2370,7 +2489,7 @@
}
file->private_data = data;
data->abort = 0;
- data->service = false;
+ data->type = QSEECOM_GENERIC;
data->released = false;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);
@@ -2401,15 +2520,27 @@
if (data->released == false) {
pr_warn("data->released == false\n");
- if (data->service)
+ switch (data->type) {
+ case QSEECOM_LISTENER_SERVICE:
ret = qseecom_unregister_listener(data);
- else
+ break;
+ case QSEECOM_CLIENT_APP:
ret = qseecom_unload_app(data);
- if (ret) {
- pr_err("Close failed\n");
- return ret;
+ break;
+ case QSEECOM_SECURE_SERVICE:
+ ret = qseecom_unmap_ion_allocated_memory(data);
+ if (ret) {
+ pr_err("Close failed\n");
+ return ret;
+ }
+ break;
+ default:
+ pr_err("Unsupported clnt_handle_type %d",
+ data->type);
+ break;
}
}
+
if (data->client.fast_load_enabled == true)
qsee_disable_clock_vote(data, CLK_SFPB);
if (data->client.perf_enabled == true)
diff --git a/include/linux/qseecom.h b/include/linux/qseecom.h
index b0f089b..d29d2fd 100644
--- a/include/linux/qseecom.h
+++ b/include/linux/qseecom.h
@@ -117,6 +117,14 @@
int app_id; /* out */
};
+struct qseecom_send_svc_cmd_req {
+ uint32_t cmd_id;
+ void *cmd_req_buf; /* in */
+ unsigned int cmd_req_len; /* in */
+ void *resp_buf; /* in/out */
+ unsigned int resp_len; /* in/out */
+};
+
#define QSEECOM_IOC_MAGIC 0x97
@@ -165,5 +173,8 @@
#define QSEECOM_IOCTL_APP_LOADED_QUERY_REQ \
_IOWR(QSEECOM_IOC_MAGIC, 15, struct qseecom_qseos_app_load_query)
+#define QSEECOM_IOCTL_SEND_CMD_SERVICE_REQ \
+ _IOWR(QSEECOM_IOC_MAGIC, 16, struct qseecom_send_svc_cmd_req)
+
#endif /* __QSEECOM_H_ */