Loading drivers/misc/qseecom.c +228 −51 Original line number Original line Diff line number Diff line Loading @@ -146,6 +146,11 @@ enum qseecom_listener_unregister_kthread_state { LSNR_UNREG_KT_WAKEUP, 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 struct class *driver_class; static dev_t qseecom_device_no; static dev_t qseecom_device_no; Loading @@ -153,6 +158,7 @@ static DEFINE_MUTEX(qsee_bw_mutex); static DEFINE_MUTEX(app_access_lock); static DEFINE_MUTEX(app_access_lock); static DEFINE_MUTEX(clk_access_lock); static DEFINE_MUTEX(clk_access_lock); static DEFINE_MUTEX(listener_access_lock); static DEFINE_MUTEX(listener_access_lock); static DEFINE_MUTEX(unload_app_pending_list_lock); struct sglist_info { struct sglist_info { Loading Loading @@ -307,6 +313,16 @@ struct qseecom_control { struct task_struct *unregister_lsnr_kthread_task; struct task_struct *unregister_lsnr_kthread_task; wait_queue_head_t unregister_lsnr_kthread_wq; wait_queue_head_t unregister_lsnr_kthread_wq; atomic_t unregister_lsnr_kthread_state; 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 { struct qseecom_sec_buf_fd_info { Loading @@ -332,6 +348,7 @@ struct qseecom_client_handle { u32 app_arch; u32 app_arch; struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD]; struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD]; bool from_smcinvoke; bool from_smcinvoke; bool unload_pending; }; }; struct qseecom_listener_handle { struct qseecom_listener_handle { Loading Loading @@ -409,6 +426,8 @@ static int qseecom_free_ce_info(struct qseecom_dev_handle *data, void __user *argp); void __user *argp); static int qseecom_query_ce_info(struct qseecom_dev_handle *data, static int qseecom_query_ce_info(struct qseecom_dev_handle *data, void __user *argp); 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) static int get_qseecom_keymaster_status(char *str) { { Loading Loading @@ -2561,8 +2580,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) if (resp.result == QSEOS_RESULT_INCOMPLETE) { if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { if (ret) { pr_err("process_incomplete_cmd failed err: %d\n", /* TZ has created app_id, need to unload it */ ret); 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)) if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); ion_free(qseecom.ion_clnt, ihandle); ret = -EFAULT; ret = -EFAULT; Loading Loading @@ -2682,18 +2704,61 @@ static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data) return ret; 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, static int qseecom_unload_app(struct qseecom_dev_handle *data, bool app_crash) bool app_crash) { { unsigned long flags; unsigned long flags; unsigned long flags1; unsigned long flags1; int ret = 0; int ret = 0; struct qseecom_command_scm_resp resp; struct qseecom_registered_app_list *ptr_app = NULL; struct qseecom_registered_app_list *ptr_app = NULL; bool unload = false; bool unload = false; bool found_app = false; bool found_app = false; bool found_dead_app = false; bool found_dead_app = false; bool scm_called = false; bool doublecheck = false; if (!data) { if (!data) { pr_err("Invalid/uninitialized device handle\n"); pr_err("Invalid/uninitialized device handle\n"); Loading Loading @@ -2743,48 +2808,9 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, (char *)data->client.app_name); (char *)data->client.app_name); if (unload) { if (unload) { struct qseecom_unload_app_ireq req; ret = __qseecom_unload_app(data, data->client.app_id); /* 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; /* SCM_CALL to unload the app */ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(struct qseecom_unload_app_ireq), &resp, sizeof(resp)); scm_called = true; if (ret) { pr_err("scm_call to unload app (id = %d) failed\n", req.app_id); ret = -EFAULT; goto scm_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 scm_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 scm_exit; } } } scm_exit: if (scm_called) { /* double check if this app_entry still exists */ /* double check if this app_entry still exists */ bool doublecheck = false; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); list_for_each_entry(ptr_app, list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, list) { &qseecom.registered_app_list_head, list) { Loading @@ -2804,6 +2830,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, found_app = false; found_app = false; } } } } unload_exit: unload_exit: if (found_app) { if (found_app) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); Loading Loading @@ -2832,6 +2859,102 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, return ret; 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; mutex_lock(&unload_app_pending_list_lock); list_add_tail(&entry->list, &qseecom.unload_app_pending_list_head); mutex_unlock(&unload_app_pending_list_lock); 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, static phys_addr_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data, unsigned long virt) unsigned long virt) { { Loading Loading @@ -3284,6 +3407,13 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, return -ENOENT; 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) { if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_req.app_id = data->client.app_id; send_data_req.app_id = data->client.app_id; send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( Loading Loading @@ -4430,10 +4560,14 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, break; break; case QSEOS_RESULT_INCOMPLETE: case QSEOS_RESULT_INCOMPLETE: ret = __qseecom_process_incomplete_cmd(data, &resp); ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) if (ret) { pr_err("process_incomplete_cmd FAILED\n"); pr_err("incomp_cmd err %d, %d, unload %d %s\n", else ret, resp.result, resp.data, appname); __qseecom_unload_app(data, resp.data); ret = -EFAULT; } else { *app_id = resp.data; *app_id = resp.data; } break; break; case QSEOS_RESULT_FAILURE: case QSEOS_RESULT_FAILURE: pr_err("scm call failed with response QSEOS_RESULT FAILURE\n"); pr_err("scm call failed with response QSEOS_RESULT FAILURE\n"); Loading Loading @@ -4630,6 +4764,7 @@ int qseecom_start_app(struct qseecom_handle **handle, uint32_t app_id = 0; uint32_t app_id = 0; __wakeup_unregister_listener_kthread(); __wakeup_unregister_listener_kthread(); __wakeup_unload_app_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", pr_err("Not allowed to be called in %d state\n", Loading Loading @@ -4770,6 +4905,7 @@ int qseecom_start_app(struct qseecom_handle **handle, spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags); spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags); mutex_unlock(&app_access_lock); mutex_unlock(&app_access_lock); __wakeup_unload_app_kthread(); return 0; return 0; exit_ion_unmap_kernel: exit_ion_unmap_kernel: Loading @@ -4790,6 +4926,7 @@ int qseecom_start_app(struct qseecom_handle **handle, kfree(*handle); kfree(*handle); *handle = NULL; *handle = NULL; } } __wakeup_unload_app_kthread(); return ret; return ret; } } EXPORT_SYMBOL(qseecom_start_app); EXPORT_SYMBOL(qseecom_start_app); Loading @@ -4804,6 +4941,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) bool found_handle = false; bool found_handle = false; __wakeup_unregister_listener_kthread(); __wakeup_unregister_listener_kthread(); __wakeup_unload_app_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", pr_err("Not allowed to be called in %d state\n", Loading Loading @@ -4840,7 +4978,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) kzfree(kclient); kzfree(kclient); *handle = NULL; *handle = NULL; } } __wakeup_unload_app_kthread(); return ret; return ret; } } EXPORT_SYMBOL(qseecom_shutdown_app); EXPORT_SYMBOL(qseecom_shutdown_app); Loading @@ -4854,6 +4992,7 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, bool perf_enabled = false; bool perf_enabled = false; __wakeup_unregister_listener_kthread(); __wakeup_unregister_listener_kthread(); __wakeup_unload_app_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", pr_err("Not allowed to be called in %d state\n", Loading Loading @@ -6818,6 +6957,12 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, (char *)data->client.app_name); (char *)data->client.app_name); return -ENOENT; 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, req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req->req_ptr); (uintptr_t)req->req_ptr); Loading Loading @@ -7021,6 +7166,12 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, (char *)data->client.app_name); (char *)data->client.app_name); return -ENOENT; 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 */ /* validate offsets */ for (i = 0; i < MAX_ION_FD; i++) { for (i = 0; i < MAX_ION_FD; i++) { Loading Loading @@ -7173,6 +7324,7 @@ static long qseecom_ioctl(struct file *file, cmd != QSEECOM_IOCTL_SEND_MODFD_RESP && cmd != QSEECOM_IOCTL_SEND_MODFD_RESP && cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64) cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64) __wakeup_unregister_listener_kthread(); __wakeup_unregister_listener_kthread(); __wakeup_unload_app_kthread(); switch (cmd) { switch (cmd) { case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: { case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: { Loading Loading @@ -7425,6 +7577,7 @@ static long qseecom_ioctl(struct file *file, mutex_unlock(&app_access_lock); mutex_unlock(&app_access_lock); if (ret) if (ret) pr_err("failed load_app request: %d\n", ret); pr_err("failed load_app request: %d\n", ret); __wakeup_unload_app_kthread(); break; break; } } case QSEECOM_IOCTL_UNLOAD_APP_REQ: { case QSEECOM_IOCTL_UNLOAD_APP_REQ: { Loading @@ -7443,6 +7596,7 @@ static long qseecom_ioctl(struct file *file, mutex_unlock(&app_access_lock); mutex_unlock(&app_access_lock); if (ret) if (ret) pr_err("failed unload_app request: %d\n", ret); pr_err("failed unload_app request: %d\n", ret); __wakeup_unload_app_kthread(); break; break; } } case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: { case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: { Loading Loading @@ -7907,9 +8061,12 @@ static int qseecom_release(struct inode *inode, struct file *file) mutex_unlock(&listener_access_lock); mutex_unlock(&listener_access_lock); break; break; case QSEECOM_CLIENT_APP: case QSEECOM_CLIENT_APP: mutex_lock(&app_access_lock); pr_debug("release app %d (%s)\n", ret = qseecom_unload_app(data, true); data->client.app_id, data->client.app_name); mutex_unlock(&app_access_lock); if (data->client.app_id) { free_private_data = false; ret = qseecom_prepare_unload_app(data); } break; break; case QSEECOM_SECURE_SERVICE: case QSEECOM_SECURE_SERVICE: case QSEECOM_GENERIC: case QSEECOM_GENERIC: Loading Loading @@ -8780,6 +8937,8 @@ static int qseecom_probe(struct platform_device *pdev) init_waitqueue_head(&qseecom.send_resp_wq); init_waitqueue_head(&qseecom.send_resp_wq); init_waitqueue_head(&qseecom.register_lsnr_pending_wq); init_waitqueue_head(&qseecom.register_lsnr_pending_wq); init_waitqueue_head(&qseecom.unregister_lsnr_kthread_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.send_resp_flag = 0; qseecom.qsee_version = QSEEE_VERSION_00; qseecom.qsee_version = QSEEE_VERSION_00; Loading Loading @@ -8995,9 +9154,25 @@ static int qseecom_probe(struct platform_device *pdev) } } atomic_set(&qseecom.unregister_lsnr_kthread_state, atomic_set(&qseecom.unregister_lsnr_kthread_state, LSNR_UNREG_KT_SLEEP); 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); atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return 0; return 0; exit_kill_unreg_lsnr_kthread: kthread_stop(qseecom.unregister_lsnr_kthread_task); exit_deinit_clock: exit_deinit_clock: __qseecom_deinit_clk(CLK_QSEE); __qseecom_deinit_clk(CLK_QSEE); if ((qseecom.qsee.instance != qseecom.ce_drv.instance) && if ((qseecom.qsee.instance != qseecom.ce_drv.instance) && Loading Loading @@ -9111,6 +9286,8 @@ static int qseecom_remove(struct platform_device *pdev) ion_client_destroy(qseecom.ion_clnt); ion_client_destroy(qseecom.ion_clnt); kthread_stop(qseecom.unload_app_kthread_task); kthread_stop(qseecom.unregister_lsnr_kthread_task); kthread_stop(qseecom.unregister_lsnr_kthread_task); cdev_del(&qseecom.cdev); cdev_del(&qseecom.cdev); Loading Loading
drivers/misc/qseecom.c +228 −51 Original line number Original line Diff line number Diff line Loading @@ -146,6 +146,11 @@ enum qseecom_listener_unregister_kthread_state { LSNR_UNREG_KT_WAKEUP, 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 struct class *driver_class; static dev_t qseecom_device_no; static dev_t qseecom_device_no; Loading @@ -153,6 +158,7 @@ static DEFINE_MUTEX(qsee_bw_mutex); static DEFINE_MUTEX(app_access_lock); static DEFINE_MUTEX(app_access_lock); static DEFINE_MUTEX(clk_access_lock); static DEFINE_MUTEX(clk_access_lock); static DEFINE_MUTEX(listener_access_lock); static DEFINE_MUTEX(listener_access_lock); static DEFINE_MUTEX(unload_app_pending_list_lock); struct sglist_info { struct sglist_info { Loading Loading @@ -307,6 +313,16 @@ struct qseecom_control { struct task_struct *unregister_lsnr_kthread_task; struct task_struct *unregister_lsnr_kthread_task; wait_queue_head_t unregister_lsnr_kthread_wq; wait_queue_head_t unregister_lsnr_kthread_wq; atomic_t unregister_lsnr_kthread_state; 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 { struct qseecom_sec_buf_fd_info { Loading @@ -332,6 +348,7 @@ struct qseecom_client_handle { u32 app_arch; u32 app_arch; struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD]; struct qseecom_sec_buf_fd_info sec_buf_fd[MAX_ION_FD]; bool from_smcinvoke; bool from_smcinvoke; bool unload_pending; }; }; struct qseecom_listener_handle { struct qseecom_listener_handle { Loading Loading @@ -409,6 +426,8 @@ static int qseecom_free_ce_info(struct qseecom_dev_handle *data, void __user *argp); void __user *argp); static int qseecom_query_ce_info(struct qseecom_dev_handle *data, static int qseecom_query_ce_info(struct qseecom_dev_handle *data, void __user *argp); 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) static int get_qseecom_keymaster_status(char *str) { { Loading Loading @@ -2561,8 +2580,11 @@ static int qseecom_load_app(struct qseecom_dev_handle *data, void __user *argp) if (resp.result == QSEOS_RESULT_INCOMPLETE) { if (resp.result == QSEOS_RESULT_INCOMPLETE) { ret = __qseecom_process_incomplete_cmd(data, &resp); ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) { if (ret) { pr_err("process_incomplete_cmd failed err: %d\n", /* TZ has created app_id, need to unload it */ ret); 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)) if (!IS_ERR_OR_NULL(ihandle)) ion_free(qseecom.ion_clnt, ihandle); ion_free(qseecom.ion_clnt, ihandle); ret = -EFAULT; ret = -EFAULT; Loading Loading @@ -2682,18 +2704,61 @@ static int qseecom_unmap_ion_allocated_memory(struct qseecom_dev_handle *data) return ret; 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, static int qseecom_unload_app(struct qseecom_dev_handle *data, bool app_crash) bool app_crash) { { unsigned long flags; unsigned long flags; unsigned long flags1; unsigned long flags1; int ret = 0; int ret = 0; struct qseecom_command_scm_resp resp; struct qseecom_registered_app_list *ptr_app = NULL; struct qseecom_registered_app_list *ptr_app = NULL; bool unload = false; bool unload = false; bool found_app = false; bool found_app = false; bool found_dead_app = false; bool found_dead_app = false; bool scm_called = false; bool doublecheck = false; if (!data) { if (!data) { pr_err("Invalid/uninitialized device handle\n"); pr_err("Invalid/uninitialized device handle\n"); Loading Loading @@ -2743,48 +2808,9 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, (char *)data->client.app_name); (char *)data->client.app_name); if (unload) { if (unload) { struct qseecom_unload_app_ireq req; ret = __qseecom_unload_app(data, data->client.app_id); /* 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; /* SCM_CALL to unload the app */ ret = qseecom_scm_call(SCM_SVC_TZSCHEDULER, 1, &req, sizeof(struct qseecom_unload_app_ireq), &resp, sizeof(resp)); scm_called = true; if (ret) { pr_err("scm_call to unload app (id = %d) failed\n", req.app_id); ret = -EFAULT; goto scm_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 scm_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 scm_exit; } } } scm_exit: if (scm_called) { /* double check if this app_entry still exists */ /* double check if this app_entry still exists */ bool doublecheck = false; spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); list_for_each_entry(ptr_app, list_for_each_entry(ptr_app, &qseecom.registered_app_list_head, list) { &qseecom.registered_app_list_head, list) { Loading @@ -2804,6 +2830,7 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, found_app = false; found_app = false; } } } } unload_exit: unload_exit: if (found_app) { if (found_app) { spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); spin_lock_irqsave(&qseecom.registered_app_list_lock, flags1); Loading Loading @@ -2832,6 +2859,102 @@ static int qseecom_unload_app(struct qseecom_dev_handle *data, return ret; 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; mutex_lock(&unload_app_pending_list_lock); list_add_tail(&entry->list, &qseecom.unload_app_pending_list_head); mutex_unlock(&unload_app_pending_list_lock); 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, static phys_addr_t __qseecom_uvirt_to_kphys(struct qseecom_dev_handle *data, unsigned long virt) unsigned long virt) { { Loading Loading @@ -3284,6 +3407,13 @@ static int __qseecom_send_cmd(struct qseecom_dev_handle *data, return -ENOENT; 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) { if (qseecom.qsee_version < QSEE_VERSION_40) { send_data_req.app_id = data->client.app_id; send_data_req.app_id = data->client.app_id; send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( send_data_req.req_ptr = (uint32_t)(__qseecom_uvirt_to_kphys( Loading Loading @@ -4430,10 +4560,14 @@ static int __qseecom_load_fw(struct qseecom_dev_handle *data, char *appname, break; break; case QSEOS_RESULT_INCOMPLETE: case QSEOS_RESULT_INCOMPLETE: ret = __qseecom_process_incomplete_cmd(data, &resp); ret = __qseecom_process_incomplete_cmd(data, &resp); if (ret) if (ret) { pr_err("process_incomplete_cmd FAILED\n"); pr_err("incomp_cmd err %d, %d, unload %d %s\n", else ret, resp.result, resp.data, appname); __qseecom_unload_app(data, resp.data); ret = -EFAULT; } else { *app_id = resp.data; *app_id = resp.data; } break; break; case QSEOS_RESULT_FAILURE: case QSEOS_RESULT_FAILURE: pr_err("scm call failed with response QSEOS_RESULT FAILURE\n"); pr_err("scm call failed with response QSEOS_RESULT FAILURE\n"); Loading Loading @@ -4630,6 +4764,7 @@ int qseecom_start_app(struct qseecom_handle **handle, uint32_t app_id = 0; uint32_t app_id = 0; __wakeup_unregister_listener_kthread(); __wakeup_unregister_listener_kthread(); __wakeup_unload_app_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", pr_err("Not allowed to be called in %d state\n", Loading Loading @@ -4770,6 +4905,7 @@ int qseecom_start_app(struct qseecom_handle **handle, spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags); spin_unlock_irqrestore(&qseecom.registered_kclient_list_lock, flags); mutex_unlock(&app_access_lock); mutex_unlock(&app_access_lock); __wakeup_unload_app_kthread(); return 0; return 0; exit_ion_unmap_kernel: exit_ion_unmap_kernel: Loading @@ -4790,6 +4926,7 @@ int qseecom_start_app(struct qseecom_handle **handle, kfree(*handle); kfree(*handle); *handle = NULL; *handle = NULL; } } __wakeup_unload_app_kthread(); return ret; return ret; } } EXPORT_SYMBOL(qseecom_start_app); EXPORT_SYMBOL(qseecom_start_app); Loading @@ -4804,6 +4941,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) bool found_handle = false; bool found_handle = false; __wakeup_unregister_listener_kthread(); __wakeup_unregister_listener_kthread(); __wakeup_unload_app_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", pr_err("Not allowed to be called in %d state\n", Loading Loading @@ -4840,7 +4978,7 @@ int qseecom_shutdown_app(struct qseecom_handle **handle) kzfree(kclient); kzfree(kclient); *handle = NULL; *handle = NULL; } } __wakeup_unload_app_kthread(); return ret; return ret; } } EXPORT_SYMBOL(qseecom_shutdown_app); EXPORT_SYMBOL(qseecom_shutdown_app); Loading @@ -4854,6 +4992,7 @@ int qseecom_send_command(struct qseecom_handle *handle, void *send_buf, bool perf_enabled = false; bool perf_enabled = false; __wakeup_unregister_listener_kthread(); __wakeup_unregister_listener_kthread(); __wakeup_unload_app_kthread(); if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { if (atomic_read(&qseecom.qseecom_state) != QSEECOM_STATE_READY) { pr_err("Not allowed to be called in %d state\n", pr_err("Not allowed to be called in %d state\n", Loading Loading @@ -6818,6 +6957,12 @@ static int __qseecom_qteec_issue_cmd(struct qseecom_dev_handle *data, (char *)data->client.app_name); (char *)data->client.app_name); return -ENOENT; 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, req->req_ptr = (void *)__qseecom_uvirt_to_kvirt(data, (uintptr_t)req->req_ptr); (uintptr_t)req->req_ptr); Loading Loading @@ -7021,6 +7166,12 @@ static int qseecom_qteec_invoke_modfd_cmd(struct qseecom_dev_handle *data, (char *)data->client.app_name); (char *)data->client.app_name); return -ENOENT; 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 */ /* validate offsets */ for (i = 0; i < MAX_ION_FD; i++) { for (i = 0; i < MAX_ION_FD; i++) { Loading Loading @@ -7173,6 +7324,7 @@ static long qseecom_ioctl(struct file *file, cmd != QSEECOM_IOCTL_SEND_MODFD_RESP && cmd != QSEECOM_IOCTL_SEND_MODFD_RESP && cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64) cmd != QSEECOM_IOCTL_SEND_MODFD_RESP_64) __wakeup_unregister_listener_kthread(); __wakeup_unregister_listener_kthread(); __wakeup_unload_app_kthread(); switch (cmd) { switch (cmd) { case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: { case QSEECOM_IOCTL_REGISTER_LISTENER_REQ: { Loading Loading @@ -7425,6 +7577,7 @@ static long qseecom_ioctl(struct file *file, mutex_unlock(&app_access_lock); mutex_unlock(&app_access_lock); if (ret) if (ret) pr_err("failed load_app request: %d\n", ret); pr_err("failed load_app request: %d\n", ret); __wakeup_unload_app_kthread(); break; break; } } case QSEECOM_IOCTL_UNLOAD_APP_REQ: { case QSEECOM_IOCTL_UNLOAD_APP_REQ: { Loading @@ -7443,6 +7596,7 @@ static long qseecom_ioctl(struct file *file, mutex_unlock(&app_access_lock); mutex_unlock(&app_access_lock); if (ret) if (ret) pr_err("failed unload_app request: %d\n", ret); pr_err("failed unload_app request: %d\n", ret); __wakeup_unload_app_kthread(); break; break; } } case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: { case QSEECOM_IOCTL_GET_QSEOS_VERSION_REQ: { Loading Loading @@ -7907,9 +8061,12 @@ static int qseecom_release(struct inode *inode, struct file *file) mutex_unlock(&listener_access_lock); mutex_unlock(&listener_access_lock); break; break; case QSEECOM_CLIENT_APP: case QSEECOM_CLIENT_APP: mutex_lock(&app_access_lock); pr_debug("release app %d (%s)\n", ret = qseecom_unload_app(data, true); data->client.app_id, data->client.app_name); mutex_unlock(&app_access_lock); if (data->client.app_id) { free_private_data = false; ret = qseecom_prepare_unload_app(data); } break; break; case QSEECOM_SECURE_SERVICE: case QSEECOM_SECURE_SERVICE: case QSEECOM_GENERIC: case QSEECOM_GENERIC: Loading Loading @@ -8780,6 +8937,8 @@ static int qseecom_probe(struct platform_device *pdev) init_waitqueue_head(&qseecom.send_resp_wq); init_waitqueue_head(&qseecom.send_resp_wq); init_waitqueue_head(&qseecom.register_lsnr_pending_wq); init_waitqueue_head(&qseecom.register_lsnr_pending_wq); init_waitqueue_head(&qseecom.unregister_lsnr_kthread_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.send_resp_flag = 0; qseecom.qsee_version = QSEEE_VERSION_00; qseecom.qsee_version = QSEEE_VERSION_00; Loading Loading @@ -8995,9 +9154,25 @@ static int qseecom_probe(struct platform_device *pdev) } } atomic_set(&qseecom.unregister_lsnr_kthread_state, atomic_set(&qseecom.unregister_lsnr_kthread_state, LSNR_UNREG_KT_SLEEP); 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); atomic_set(&qseecom.qseecom_state, QSEECOM_STATE_READY); return 0; return 0; exit_kill_unreg_lsnr_kthread: kthread_stop(qseecom.unregister_lsnr_kthread_task); exit_deinit_clock: exit_deinit_clock: __qseecom_deinit_clk(CLK_QSEE); __qseecom_deinit_clk(CLK_QSEE); if ((qseecom.qsee.instance != qseecom.ce_drv.instance) && if ((qseecom.qsee.instance != qseecom.ce_drv.instance) && Loading Loading @@ -9111,6 +9286,8 @@ static int qseecom_remove(struct platform_device *pdev) ion_client_destroy(qseecom.ion_clnt); ion_client_destroy(qseecom.ion_clnt); kthread_stop(qseecom.unload_app_kthread_task); kthread_stop(qseecom.unregister_lsnr_kthread_task); kthread_stop(qseecom.unregister_lsnr_kthread_task); cdev_del(&qseecom.cdev); cdev_del(&qseecom.cdev); Loading