qseecom: Add support to handle multiple app load & unload

Media server is associated with multiple apps on TZ-side.
Unloading a single app for clean up is not enought. QSEECOM
needs to handle the app load & unload of multiple apps
associated with the client. During app_load & app_unload
along with app_id, app_name should also be checked. Besides,
keymaster will not be unloaded and app search execution
during app unload is optimized.

Change-Id: Ie92e97b9154851b713a8c3394b8ed10fdbdebd2f
Signed-off-by: Zhen Kong <zkong@codeaurora.org>
Signed-off-by: William Clark <wclark@codeaurora.org>
This commit is contained in:
William Clark
2014-07-21 13:21:36 -07:00
committed by Gerrit - the friendly Code Review server
parent bead047a99
commit c7a043d0b1
+93 -27
View File
@@ -116,6 +116,7 @@ struct qseecom_registered_app_list {
struct list_head list;
u32 app_id;
u32 ref_cnt;
char app_name[MAX_APP_NAME_SIZE];
};
struct qseecom_registered_kclient_list {
@@ -185,6 +186,7 @@ struct qseecom_client_handle {
uint32_t user_virt_sb_base;
size_t sb_length;
struct ion_handle *ihandle; /* Retrieve phy addr */
char app_name[MAX_APP_NAME_SIZE];
};
struct qseecom_listener_handle {
@@ -999,7 +1001,9 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
}
entry->app_id = app_id;
entry->ref_cnt = 1;
memset((void *)entry->app_name, 0, MAX_APP_NAME_SIZE);
memcpy((void *)entry->app_name,
(void *)load_img_req.img_name, MAX_APP_NAME_SIZE);
/* Deallocate the handle */
if (!IS_ERR_OR_NULL(ihandle))
ion_free(qseecom.ion_clnt, ihandle);
@@ -1013,6 +1017,9 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp)
(char *)(load_img_req.img_name));
}
data->client.app_id = app_id;
memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
memcpy((void *)data->client.app_name,
(void *)load_img_req.img_name, MAX_APP_NAME_SIZE);
load_img_req.app_id = app_id;
if (copy_to_user(argp, &load_img_req, sizeof(load_img_req))) {
pr_err("copy_to_user failed\n");
@@ -1061,53 +1068,55 @@ 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;
struct qseecom_registered_app_list *ptr_app = NULL;
bool unload = false;
bool found_app = false;
bool found_dead_app = false;
if (!memcmp(data->client.app_name, "keymaste", strlen("keymaste"))) {
pr_warn("Do not unload keymaster app from tz\n");
return 0;
}
if (data->client.app_id > 0) {
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) {
found_app = true;
if (app_crash) {
ptr_app->ref_cnt = 0;
unload = true;
if (!memcmp((void *)ptr_app->app_name,
(void *)data->client.app_name,
strlen(data->client.app_name))) {
found_app = true;
if (app_crash || ptr_app->ref_cnt == 1)
unload = true;
break;
} else {
if (ptr_app->ref_cnt == 1) {
unload = true;
break;
} else {
ptr_app->ref_cnt--;
pr_debug("Can't unload app(%d) inuse\n",
ptr_app->app_id);
break;
}
found_dead_app = true;
break;
}
}
}
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags);
if (found_app == false) {
pr_err("Cannot find app with id = %d\n",
data->client.app_id);
if (found_app == false && found_dead_app == false) {
pr_err("Cannot find app with id = %d (%s)\n",
data->client.app_id,
(char *)data->client.app_name);
return -EINVAL;
}
}
if (found_dead_app) {
pr_warn("cleanup app_id %d(%s)\n", data->client.app_id,
(char *)data->client.app_name);
__qseecom_cleanup_app(data);
}
if (unload) {
struct qseecom_unload_app_ireq req;
__qseecom_cleanup_app(data);
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags);
list_del(&ptr_app->list);
kzfree(ptr_app);
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags);
/* 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;
@@ -1123,6 +1132,15 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
} 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);
return -EFAULT;
}
if (resp.result == QSEOS_RESULT_SUCCESS)
pr_info("App (%d) is unloaded!!\n",
data->client.app_id);
__qseecom_cleanup_app(data);
if (resp.result == QSEOS_RESULT_INCOMPLETE) {
ret = __qseecom_process_incomplete_cmd(data, &resp);
if (ret) {
@@ -1132,6 +1150,29 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data,
}
}
}
if (found_app) {
spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1);
if (app_crash) {
ptr_app->ref_cnt = 0;
pr_debug("app_crash: ref_count = 0\n");
} else {
if (ptr_app->ref_cnt == 1) {
ptr_app->ref_cnt = 0;
pr_info("ref_count set to 0\n");
} else {
ptr_app->ref_cnt--;
pr_info("Can't unload app(%d) inuse\n",
ptr_app->app_id);
}
}
if (unload) {
list_del(&ptr_app->list);
kzfree(ptr_app);
}
spin_unlock_irqrestore(&qseecom.registered_app_list_lock,
flags1);
}
qseecom_unmap_ion_allocated_memory(data);
data->released = true;
return ret;
@@ -1326,6 +1367,9 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
u32 reqd_len_sb_in = 0;
struct qseecom_client_send_data_ireq send_data_req;
struct qseecom_command_scm_resp resp;
unsigned long flags;
struct qseecom_registered_app_list *ptr_app;
bool found_app = false;
if (req->cmd_req_buf == NULL || req->resp_buf == NULL) {
pr_err("cmd buffer or response buffer is null\n");
@@ -1367,6 +1411,26 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data,
return -ENOMEM;
}
/* find app_id & img_name from list */
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) &&
(!memcmp((void *)ptr_app->app_name,
(void *)data->client.app_name,
strlen(data->client.app_name)))) {
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);
return -EINVAL;
}
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 = (void *)(__qseecom_uvirt_to_kphys(data,
@@ -2841,7 +2905,9 @@ static int qseecom_query_app_loaded(struct qseecom_dev_handle *data,
&qseecom.registered_app_list_lock, flags);
data->client.app_id = ret;
query_req.app_id = ret;
memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
memcpy((void *)data->client.app_name,
(void *)query_req.app_name, MAX_APP_NAME_SIZE);
if (copy_to_user(argp, &query_req, sizeof(query_req))) {
pr_err("copy_to_user failed\n");
return -EFAULT;
@@ -3516,7 +3582,6 @@ static long qseecom_ioctl(struct file *file, unsigned cmd,
ret = -EINVAL;
break;
}
data->type = QSEECOM_CLIENT_APP;
pr_debug("SET_MEM_PARAM: qseecom addr = 0x%x\n", (u32)data);
ret = qseecom_set_client_mem_param(data, argp);
if (ret)
@@ -3850,6 +3915,7 @@ static int qseecom_open(struct inode *inode, struct file *file)
data->abort = 0;
data->type = QSEECOM_GENERIC;
data->released = false;
memset((void *)data->client.app_name, 0, MAX_APP_NAME_SIZE);
data->mode = INACTIVE;
init_waitqueue_head(&data->abort_wq);
atomic_set(&data->ioctl_count, 0);