Loading drivers/soc/qcom/smcinvoke.c +34 −41 Original line number Diff line number Diff line /* * SMC Invoke driver * * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019, 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 Loading Loading @@ -134,6 +134,10 @@ #define FILE_IS_REMOTE_OBJ(f) ((f)->f_op && (f)->f_op == &g_smcinvoke_fops) static DEFINE_MUTEX(g_smcinvoke_lock); #define NO_LOCK 0 #define TAKE_LOCK 1 #define MUTEX_LOCK(x) { if (x) mutex_lock(&g_smcinvoke_lock); } #define MUTEX_UNLOCK(x) { if (x) mutex_unlock(&g_smcinvoke_lock); } static DEFINE_HASHTABLE(g_cb_servers, 8); static LIST_HEAD(g_mem_objs); static uint16_t g_last_cb_server_id = CBOBJ_SERVER_ID_START; Loading @@ -143,6 +147,7 @@ static size_t g_max_cb_buf_size = SMCINVOKE_TZ_MIN_BUF_SIZE; static long smcinvoke_ioctl(struct file *, unsigned int, unsigned long); static int smcinvoke_open(struct inode *, struct file *); static int smcinvoke_release(struct inode *, struct file *); static int destroy_cb_server(uint16_t); static const struct file_operations g_smcinvoke_fops = { .owner = THIS_MODULE, Loading Loading @@ -280,10 +285,8 @@ static struct smcinvoke_mem_obj *find_mem_obj_locked(uint16_t mem_obj_id, { struct smcinvoke_mem_obj *mem_obj = NULL; if (list_empty(&g_mem_objs)) { pr_err("%s: mem obj %d not found\n", __func__, mem_obj_id); if (list_empty(&g_mem_objs)) return NULL; } list_for_each_entry(mem_obj, &g_mem_objs, list) { if ((is_mem_rgn_obj && Loading Loading @@ -379,9 +382,11 @@ static void free_pending_cbobj_locked(struct kref *kref) server = obj->server; kfree(obj); if ((server->state == SMCINVOKE_SERVER_STATE_DEFUNCT) && list_empty(&server->pending_cbobjs)) list_empty(&server->pending_cbobjs)) { hash_del(&server->hash); kfree(server); } } static int get_pending_cbobj_locked(uint16_t srvr_id, int16_t obj_id) { Loading Loading @@ -618,10 +623,6 @@ static int get_tzhandle_from_uhandle(int32_t uhandle, int32_t server_fd, } } out: if (ret && *filp) { fput(*filp); *filp = NULL; } return ret; } Loading Loading @@ -669,7 +670,7 @@ static int get_fd_for_obj(uint32_t obj_type, uint32_t obj, int64_t *fd) } static int get_uhandle_from_tzhandle(int32_t tzhandle, int32_t srvr_id, int64_t *uhandle) int64_t *uhandle, bool lock) { int ret = -1; Loading @@ -680,14 +681,14 @@ static int get_uhandle_from_tzhandle(int32_t tzhandle, int32_t srvr_id, if (srvr_id != TZHANDLE_GET_SERVER(tzhandle)) goto out; *uhandle = UHANDLE_MAKE_CB_OBJ(TZHANDLE_GET_OBJID(tzhandle)); mutex_lock(&g_smcinvoke_lock); ret = get_pending_cbobj_locked(srvr_id, MUTEX_LOCK(lock) ret = get_pending_cbobj_locked(TZHANDLE_GET_SERVER(tzhandle), TZHANDLE_GET_OBJID(tzhandle)); mutex_unlock(&g_smcinvoke_lock); MUTEX_UNLOCK(lock) } else if (TZHANDLE_IS_MEM_RGN_OBJ(tzhandle)) { struct smcinvoke_mem_obj *mem_obj = NULL; mutex_lock(&g_smcinvoke_lock); MUTEX_LOCK(lock) mem_obj = find_mem_obj_locked(TZHANDLE_GET_OBJID(tzhandle), SMCINVOKE_MEM_RGN_OBJ); Loading @@ -705,7 +706,7 @@ static int get_uhandle_from_tzhandle(int32_t tzhandle, int32_t srvr_id, ret = 0; } exit_lock: mutex_unlock(&g_smcinvoke_lock); MUTEX_UNLOCK(lock) } else if (TZHANDLE_IS_REMOTE(tzhandle)) { /* if execution comes here => tzhandle is an unsigned int */ ret = get_fd_for_obj(SMCINVOKE_OBJ_TYPE_TZ_OBJ, Loading Loading @@ -882,9 +883,7 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT && OBJECT_OP_METHODID(cb_req->hdr.op) == OBJECT_OP_RELEASE) { mutex_lock(&g_smcinvoke_lock); put_pending_cbobj_locked( TZHANDLE_GET_SERVER(cb_req->hdr.tzhandle), TZHANDLE_GET_OBJID(cb_req->hdr.tzhandle)); release_tzhandle_locked(cb_req->hdr.tzhandle); mutex_unlock(&g_smcinvoke_lock); } } Loading Loading @@ -937,7 +936,8 @@ static int marshal_out_invoke_req(const uint8_t *buf, uint32_t buf_size, * to server who serves it and that info comes from USpace. */ ret = get_uhandle_from_tzhandle(tz_args->handle, args_buf[i].o.cb_server_fd, &(args_buf[i].o.fd)); TZHANDLE_GET_SERVER(tz_args->handle), &(args_buf[i].o.fd), NO_LOCK); if (ret) goto out; tz_args++; Loading Loading @@ -1152,7 +1152,7 @@ static int marshal_in_tzcb_req(const struct smcinvoke_cb_txn *cb_txn, user_req->txn_id = cb_txn->txn_id; if (get_uhandle_from_tzhandle(tzcb_req->hdr.tzhandle, srvr_id, (int64_t *)&user_req->cbobj_id)) { (int64_t *)&user_req->cbobj_id, TAKE_LOCK)) { ret = -EINVAL; goto out; } Loading Loading @@ -1214,7 +1214,7 @@ static int marshal_in_tzcb_req(const struct smcinvoke_cb_txn *cb_txn, * context */ ret = get_uhandle_from_tzhandle(tz_args[i].handle, srvr_id, &(tmp_arg.o.fd)); &(tmp_arg.o.fd), TAKE_LOCK); if (ret) { ret = -EINVAL; goto out; Loading @@ -1238,10 +1238,8 @@ static int marshal_out_tzcb_req(const struct smcinvoke_accept *user_req, int32_t tzhandles_to_release[OBJECT_COUNTS_MAX_OO] = {0}; struct smcinvoke_tzcb_req *tzcb_req = cb_txn->cb_req; union smcinvoke_tz_args *tz_args = tzcb_req->args; put_pending_cbobj_locked( TZHANDLE_GET_SERVER(cb_txn->cb_req->hdr.tzhandle), TZHANDLE_GET_OBJID(cb_txn->cb_req->hdr.tzhandle)); release_tzhandles(&cb_txn->cb_req->hdr.tzhandle, 1); tzcb_req->result = user_req->result; FOR_ARGS(i, tzcb_req->hdr.counts, BO) { union smcinvoke_arg tmp_arg; Loading Loading @@ -1271,18 +1269,16 @@ static int marshal_out_tzcb_req(const struct smcinvoke_accept *user_req, ret = -EFAULT; goto out; } ret = get_tzhandle_from_uhandle(tmp_arg.o.fd, 0, &arr_filp[i], ret = get_tzhandle_from_uhandle(tmp_arg.o.fd, tmp_arg.o.cb_server_fd, &arr_filp[i], &(tz_args[i].handle)); if (ret) goto out; tzhandles_to_release[i] = tz_args[i].handle; } FOR_ARGS(i, tzcb_req->hdr.counts, OI) { if (TZHANDLE_IS_CB_OBJ(tz_args[i].handle)) { put_pending_cbobj_locked( TZHANDLE_GET_SERVER(tz_args[i].handle), TZHANDLE_GET_OBJID(tz_args[i].handle)); } if (TZHANDLE_IS_CB_OBJ(tz_args[i].handle)) release_tzhandles(&tz_args[i].handle, 1); } ret = 0; out: Loading Loading @@ -1375,12 +1371,9 @@ static long process_server_req(struct file *filp, unsigned int cmd, ret = get_fd_for_obj(SMCINVOKE_OBJ_TYPE_SERVER, server_info->server_id, &server_fd); if (ret) { mutex_lock(&g_smcinvoke_lock); hash_del(&server_info->hash); mutex_unlock(&g_smcinvoke_lock); kfree(server_info); } if (ret) destroy_cb_server(server_info->server_id); return server_fd; } Loading Loading @@ -1435,9 +1428,7 @@ static long process_accept_req(struct file *filp, unsigned int cmd, cb_txn->cb_req->result = OBJECT_ERROR_UNAVAIL; if (OBJECT_OP_METHODID(user_args.op) == OBJECT_OP_RELEASE) put_pending_cbobj_locked( TZHANDLE_GET_SERVER(cb_txn->cb_req->hdr.tzhandle), TZHANDLE_GET_OBJID(cb_txn->cb_req->hdr.tzhandle)); release_tzhandles(&cb_txn->cb_req->hdr.tzhandle, 1); cb_txn->state = SMCINVOKE_REQ_PROCESSED; wake_up(&server_info->rsp_wait_q); Loading @@ -1455,8 +1446,10 @@ static long process_accept_req(struct file *filp, unsigned int cmd, do { ret = wait_event_interruptible(server_info->req_wait_q, !hash_empty(server_info->reqs_table)); if (ret) if (ret) { destroy_cb_server(server_obj->server_id); goto out; } mutex_lock(&g_smcinvoke_lock); cb_txn = find_cbtxn_locked(server_info, Loading Loading
drivers/soc/qcom/smcinvoke.c +34 −41 Original line number Diff line number Diff line /* * SMC Invoke driver * * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. * Copyright (c) 2016-2019, 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 Loading Loading @@ -134,6 +134,10 @@ #define FILE_IS_REMOTE_OBJ(f) ((f)->f_op && (f)->f_op == &g_smcinvoke_fops) static DEFINE_MUTEX(g_smcinvoke_lock); #define NO_LOCK 0 #define TAKE_LOCK 1 #define MUTEX_LOCK(x) { if (x) mutex_lock(&g_smcinvoke_lock); } #define MUTEX_UNLOCK(x) { if (x) mutex_unlock(&g_smcinvoke_lock); } static DEFINE_HASHTABLE(g_cb_servers, 8); static LIST_HEAD(g_mem_objs); static uint16_t g_last_cb_server_id = CBOBJ_SERVER_ID_START; Loading @@ -143,6 +147,7 @@ static size_t g_max_cb_buf_size = SMCINVOKE_TZ_MIN_BUF_SIZE; static long smcinvoke_ioctl(struct file *, unsigned int, unsigned long); static int smcinvoke_open(struct inode *, struct file *); static int smcinvoke_release(struct inode *, struct file *); static int destroy_cb_server(uint16_t); static const struct file_operations g_smcinvoke_fops = { .owner = THIS_MODULE, Loading Loading @@ -280,10 +285,8 @@ static struct smcinvoke_mem_obj *find_mem_obj_locked(uint16_t mem_obj_id, { struct smcinvoke_mem_obj *mem_obj = NULL; if (list_empty(&g_mem_objs)) { pr_err("%s: mem obj %d not found\n", __func__, mem_obj_id); if (list_empty(&g_mem_objs)) return NULL; } list_for_each_entry(mem_obj, &g_mem_objs, list) { if ((is_mem_rgn_obj && Loading Loading @@ -379,9 +382,11 @@ static void free_pending_cbobj_locked(struct kref *kref) server = obj->server; kfree(obj); if ((server->state == SMCINVOKE_SERVER_STATE_DEFUNCT) && list_empty(&server->pending_cbobjs)) list_empty(&server->pending_cbobjs)) { hash_del(&server->hash); kfree(server); } } static int get_pending_cbobj_locked(uint16_t srvr_id, int16_t obj_id) { Loading Loading @@ -618,10 +623,6 @@ static int get_tzhandle_from_uhandle(int32_t uhandle, int32_t server_fd, } } out: if (ret && *filp) { fput(*filp); *filp = NULL; } return ret; } Loading Loading @@ -669,7 +670,7 @@ static int get_fd_for_obj(uint32_t obj_type, uint32_t obj, int64_t *fd) } static int get_uhandle_from_tzhandle(int32_t tzhandle, int32_t srvr_id, int64_t *uhandle) int64_t *uhandle, bool lock) { int ret = -1; Loading @@ -680,14 +681,14 @@ static int get_uhandle_from_tzhandle(int32_t tzhandle, int32_t srvr_id, if (srvr_id != TZHANDLE_GET_SERVER(tzhandle)) goto out; *uhandle = UHANDLE_MAKE_CB_OBJ(TZHANDLE_GET_OBJID(tzhandle)); mutex_lock(&g_smcinvoke_lock); ret = get_pending_cbobj_locked(srvr_id, MUTEX_LOCK(lock) ret = get_pending_cbobj_locked(TZHANDLE_GET_SERVER(tzhandle), TZHANDLE_GET_OBJID(tzhandle)); mutex_unlock(&g_smcinvoke_lock); MUTEX_UNLOCK(lock) } else if (TZHANDLE_IS_MEM_RGN_OBJ(tzhandle)) { struct smcinvoke_mem_obj *mem_obj = NULL; mutex_lock(&g_smcinvoke_lock); MUTEX_LOCK(lock) mem_obj = find_mem_obj_locked(TZHANDLE_GET_OBJID(tzhandle), SMCINVOKE_MEM_RGN_OBJ); Loading @@ -705,7 +706,7 @@ static int get_uhandle_from_tzhandle(int32_t tzhandle, int32_t srvr_id, ret = 0; } exit_lock: mutex_unlock(&g_smcinvoke_lock); MUTEX_UNLOCK(lock) } else if (TZHANDLE_IS_REMOTE(tzhandle)) { /* if execution comes here => tzhandle is an unsigned int */ ret = get_fd_for_obj(SMCINVOKE_OBJ_TYPE_TZ_OBJ, Loading Loading @@ -882,9 +883,7 @@ static void process_tzcb_req(void *buf, size_t buf_len, struct file **arr_filp) srvr_info->state == SMCINVOKE_SERVER_STATE_DEFUNCT && OBJECT_OP_METHODID(cb_req->hdr.op) == OBJECT_OP_RELEASE) { mutex_lock(&g_smcinvoke_lock); put_pending_cbobj_locked( TZHANDLE_GET_SERVER(cb_req->hdr.tzhandle), TZHANDLE_GET_OBJID(cb_req->hdr.tzhandle)); release_tzhandle_locked(cb_req->hdr.tzhandle); mutex_unlock(&g_smcinvoke_lock); } } Loading Loading @@ -937,7 +936,8 @@ static int marshal_out_invoke_req(const uint8_t *buf, uint32_t buf_size, * to server who serves it and that info comes from USpace. */ ret = get_uhandle_from_tzhandle(tz_args->handle, args_buf[i].o.cb_server_fd, &(args_buf[i].o.fd)); TZHANDLE_GET_SERVER(tz_args->handle), &(args_buf[i].o.fd), NO_LOCK); if (ret) goto out; tz_args++; Loading Loading @@ -1152,7 +1152,7 @@ static int marshal_in_tzcb_req(const struct smcinvoke_cb_txn *cb_txn, user_req->txn_id = cb_txn->txn_id; if (get_uhandle_from_tzhandle(tzcb_req->hdr.tzhandle, srvr_id, (int64_t *)&user_req->cbobj_id)) { (int64_t *)&user_req->cbobj_id, TAKE_LOCK)) { ret = -EINVAL; goto out; } Loading Loading @@ -1214,7 +1214,7 @@ static int marshal_in_tzcb_req(const struct smcinvoke_cb_txn *cb_txn, * context */ ret = get_uhandle_from_tzhandle(tz_args[i].handle, srvr_id, &(tmp_arg.o.fd)); &(tmp_arg.o.fd), TAKE_LOCK); if (ret) { ret = -EINVAL; goto out; Loading @@ -1238,10 +1238,8 @@ static int marshal_out_tzcb_req(const struct smcinvoke_accept *user_req, int32_t tzhandles_to_release[OBJECT_COUNTS_MAX_OO] = {0}; struct smcinvoke_tzcb_req *tzcb_req = cb_txn->cb_req; union smcinvoke_tz_args *tz_args = tzcb_req->args; put_pending_cbobj_locked( TZHANDLE_GET_SERVER(cb_txn->cb_req->hdr.tzhandle), TZHANDLE_GET_OBJID(cb_txn->cb_req->hdr.tzhandle)); release_tzhandles(&cb_txn->cb_req->hdr.tzhandle, 1); tzcb_req->result = user_req->result; FOR_ARGS(i, tzcb_req->hdr.counts, BO) { union smcinvoke_arg tmp_arg; Loading Loading @@ -1271,18 +1269,16 @@ static int marshal_out_tzcb_req(const struct smcinvoke_accept *user_req, ret = -EFAULT; goto out; } ret = get_tzhandle_from_uhandle(tmp_arg.o.fd, 0, &arr_filp[i], ret = get_tzhandle_from_uhandle(tmp_arg.o.fd, tmp_arg.o.cb_server_fd, &arr_filp[i], &(tz_args[i].handle)); if (ret) goto out; tzhandles_to_release[i] = tz_args[i].handle; } FOR_ARGS(i, tzcb_req->hdr.counts, OI) { if (TZHANDLE_IS_CB_OBJ(tz_args[i].handle)) { put_pending_cbobj_locked( TZHANDLE_GET_SERVER(tz_args[i].handle), TZHANDLE_GET_OBJID(tz_args[i].handle)); } if (TZHANDLE_IS_CB_OBJ(tz_args[i].handle)) release_tzhandles(&tz_args[i].handle, 1); } ret = 0; out: Loading Loading @@ -1375,12 +1371,9 @@ static long process_server_req(struct file *filp, unsigned int cmd, ret = get_fd_for_obj(SMCINVOKE_OBJ_TYPE_SERVER, server_info->server_id, &server_fd); if (ret) { mutex_lock(&g_smcinvoke_lock); hash_del(&server_info->hash); mutex_unlock(&g_smcinvoke_lock); kfree(server_info); } if (ret) destroy_cb_server(server_info->server_id); return server_fd; } Loading Loading @@ -1435,9 +1428,7 @@ static long process_accept_req(struct file *filp, unsigned int cmd, cb_txn->cb_req->result = OBJECT_ERROR_UNAVAIL; if (OBJECT_OP_METHODID(user_args.op) == OBJECT_OP_RELEASE) put_pending_cbobj_locked( TZHANDLE_GET_SERVER(cb_txn->cb_req->hdr.tzhandle), TZHANDLE_GET_OBJID(cb_txn->cb_req->hdr.tzhandle)); release_tzhandles(&cb_txn->cb_req->hdr.tzhandle, 1); cb_txn->state = SMCINVOKE_REQ_PROCESSED; wake_up(&server_info->rsp_wait_q); Loading @@ -1455,8 +1446,10 @@ static long process_accept_req(struct file *filp, unsigned int cmd, do { ret = wait_event_interruptible(server_info->req_wait_q, !hash_empty(server_info->reqs_table)); if (ret) if (ret) { destroy_cb_server(server_obj->server_id); goto out; } mutex_lock(&g_smcinvoke_lock); cb_txn = find_cbtxn_locked(server_info, Loading