qseecom: fix issues when processing blocked listener request

When processing blocked listener request, ptr_app's app_blocked
flag should be set to prevent it being unloaded at this time;
Besides, need to check unblock request's scm_call response result
to see if it is blocked again; and removed redundant codes.

Change-Id: I2d72a88e9e600d6b7e944ae978b9d89a7b6db242
Signed-off-by: Zhen Kong <zkong@codeaurora.org>
This commit is contained in:
Zhen Kong 2018-02-02 17:21:04 -08:00
parent b3ba6ffa2c
commit 4aa1034bf7

View file

@ -1845,7 +1845,7 @@ static int __qseecom_process_incomplete_cmd(struct qseecom_dev_handle *data,
return ret; return ret;
} }
static int __qseecom_process_blocked_on_listener_legacy( static int __qseecom_process_reentrancy_blocked_on_listener(
struct qseecom_command_scm_resp *resp, struct qseecom_command_scm_resp *resp,
struct qseecom_registered_app_list *ptr_app, struct qseecom_registered_app_list *ptr_app,
struct qseecom_dev_handle *data) struct qseecom_dev_handle *data)
@ -1854,10 +1854,11 @@ static int __qseecom_process_blocked_on_listener_legacy(
int ret = 0; int ret = 0;
struct qseecom_continue_blocked_request_ireq ireq; struct qseecom_continue_blocked_request_ireq ireq;
struct qseecom_command_scm_resp continue_resp; struct qseecom_command_scm_resp continue_resp;
bool found_app = false; unsigned int session_id;
unsigned long flags;
sigset_t new_sigset; sigset_t new_sigset;
sigset_t old_sigset; sigset_t old_sigset;
unsigned long flags;
bool found_app = false;
if (!resp || !data) { if (!resp || !data) {
pr_err("invalid resp or data pointer\n"); pr_err("invalid resp or data pointer\n");
@ -1888,16 +1889,20 @@ static int __qseecom_process_blocked_on_listener_legacy(
} }
} }
do {
session_id = resp->resp_type;
list_ptr = __qseecom_find_svc(resp->data); list_ptr = __qseecom_find_svc(resp->data);
if (!list_ptr) { if (!list_ptr) {
pr_err("Invalid listener ID\n"); pr_err("Invalid listener ID %d\n", resp->data);
ret = -ENODATA; ret = -ENODATA;
goto exit; goto exit;
} }
pr_debug("lsntr %d in_use = %d\n",
resp->data, list_ptr->listener_in_use);
ptr_app->blocked_on_listener_id = resp->data; ptr_app->blocked_on_listener_id = resp->data;
pr_warn("Lsntr %d in_use %d, block session(%d) app(%d)\n",
resp->data, list_ptr->listener_in_use,
session_id, data->client.app_id);
/* sleep until listener is available */ /* sleep until listener is available */
sigfillset(&new_sigset); sigfillset(&new_sigset);
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset); sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
@ -1917,111 +1922,48 @@ static int __qseecom_process_blocked_on_listener_legacy(
sigprocmask(SIG_SETMASK, &old_sigset, NULL); sigprocmask(SIG_SETMASK, &old_sigset, NULL);
ptr_app->blocked_on_listener_id = 0; ptr_app->blocked_on_listener_id = 0;
/* notify the blocked app that listener is available */ pr_warn("Lsntr %d is available, unblock session(%d) app(%d)\n",
pr_warn("Lsntr %d is available, unblock app(%d) %s in TZ\n", resp->data, session_id, data->client.app_id);
resp->data, data->client.app_id,
data->client.app_name);
ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
ireq.app_or_session_id = data->client.app_id;
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
&ireq, sizeof(ireq),
&continue_resp, sizeof(continue_resp));
if (ret) {
pr_err("scm_call for continue blocked req for app(%d) %s failed, ret %d\n",
data->client.app_id,
data->client.app_name, ret);
goto exit;
}
/*
* After TZ app is unblocked, then continue to next case
* for incomplete request processing
*/
resp->result = QSEOS_RESULT_INCOMPLETE;
exit:
return ret;
}
static int __qseecom_process_blocked_on_listener_smcinvoke(
struct qseecom_command_scm_resp *resp, uint32_t app_id)
{
struct qseecom_registered_listener_list *list_ptr;
int ret = 0;
struct qseecom_continue_blocked_request_ireq ireq;
struct qseecom_command_scm_resp continue_resp;
unsigned int session_id;
sigset_t new_sigset;
sigset_t old_sigset;
if (!resp) {
pr_err("invalid resp pointer\n");
ret = -EINVAL;
goto exit;
}
session_id = resp->resp_type;
list_ptr = __qseecom_find_svc(resp->data);
if (!list_ptr) {
pr_err("Invalid listener ID\n");
ret = -ENODATA;
goto exit;
}
pr_debug("lsntr %d in_use = %d\n",
resp->data, list_ptr->listener_in_use);
/* sleep until listener is available */
sigfillset(&new_sigset);
sigprocmask(SIG_SETMASK, &new_sigset, &old_sigset);
do {
qseecom.app_block_ref_cnt++;
mutex_unlock(&app_access_lock);
wait_event_freezable(
list_ptr->listener_block_app_wq,
!list_ptr->listener_in_use);
mutex_lock(&app_access_lock);
qseecom.app_block_ref_cnt--;
} while (list_ptr->listener_in_use);
sigprocmask(SIG_SETMASK, &old_sigset, NULL);
/* notify TZ that listener is available */ /* notify TZ that listener is available */
pr_warn("Lsntr %d is available, unblock session(%d) in TZ\n",
resp->data, session_id);
ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND; ireq.qsee_cmd_id = QSEOS_CONTINUE_BLOCKED_REQ_COMMAND;
if (qseecom.smcinvoke_support)
ireq.app_or_session_id = session_id; ireq.app_or_session_id = session_id;
else
ireq.app_or_session_id = data->client.app_id;
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
&ireq, sizeof(ireq), &ireq, sizeof(ireq),
&continue_resp, sizeof(continue_resp)); &continue_resp, sizeof(continue_resp));
if (ret) { if (ret && qseecom.smcinvoke_support) {
/* retry with legacy cmd */ /* retry with legacy cmd */
qseecom.smcinvoke_support = false; qseecom.smcinvoke_support = false;
ireq.app_or_session_id = app_id; ireq.app_or_session_id = data->client.app_id;
ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1,
&ireq, sizeof(ireq), &ireq, sizeof(ireq),
&continue_resp, sizeof(continue_resp)); &continue_resp, sizeof(continue_resp));
qseecom.smcinvoke_support = true; qseecom.smcinvoke_support = true;
if (ret) { if (ret) {
pr_err("cont block req for app %d or session %d fail\n", pr_err("unblock app %d or session %d fail\n",
app_id, session_id); data->client.app_id, session_id);
goto exit; goto exit;
} }
} }
resp->result = QSEOS_RESULT_INCOMPLETE; resp->result = continue_resp.result;
resp->resp_type = continue_resp.resp_type;
resp->data = continue_resp.data;
pr_debug("unblock resp = %d\n", resp->result);
} while (resp->result == QSEOS_RESULT_BLOCKED_ON_LISTENER);
if (resp->result != QSEOS_RESULT_INCOMPLETE) {
pr_err("Unexpected unblock resp %d\n", resp->result);
ret = -EINVAL;
}
exit: exit:
return ret; return ret;
} }
static int __qseecom_process_reentrancy_blocked_on_listener(
struct qseecom_command_scm_resp *resp,
struct qseecom_registered_app_list *ptr_app,
struct qseecom_dev_handle *data)
{
if (!qseecom.smcinvoke_support)
return __qseecom_process_blocked_on_listener_legacy(
resp, ptr_app, data);
else
return __qseecom_process_blocked_on_listener_smcinvoke(
resp, data->client.app_id);
}
static int __qseecom_reentrancy_process_incomplete_cmd( static int __qseecom_reentrancy_process_incomplete_cmd(
struct qseecom_dev_handle *data, struct qseecom_dev_handle *data,
struct qseecom_command_scm_resp *resp) struct qseecom_command_scm_resp *resp)