From e8d5a43b9f283142308639f602f3108ad5a67933 Mon Sep 17 00:00:00 2001 From: Joshua Cha Date: Tue, 25 Feb 2025 17:21:45 +0900 Subject: [PATCH] nvsciipc: add endpoint mutex add endpoint mutex to nvsciipc KMD JIRA NVIPC-3427 Change-Id: I1644213f59d24da4c4eeb693fa3016904388a26b Signed-off-by: Joshua Cha Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3309493 Reviewed-by: Suneel Kumar Pemmineti Reviewed-by: Simon Je GVS: buildbot_gerritrpt --- drivers/misc/nvsciipc/nvsciipc.c | 162 ++++++++++++++++++++++++++-- drivers/misc/nvsciipc/nvsciipc.h | 6 ++ include/uapi/linux/nvsciipc_ioctl.h | 13 ++- 3 files changed, 173 insertions(+), 8 deletions(-) diff --git a/drivers/misc/nvsciipc/nvsciipc.c b/drivers/misc/nvsciipc/nvsciipc.c index 4a98ea35..862b03a2 100644 --- a/drivers/misc/nvsciipc/nvsciipc.c +++ b/drivers/misc/nvsciipc/nvsciipc.c @@ -42,7 +42,8 @@ */ #define DEBUG_VALIDATE_TOKEN 0 -DEFINE_MUTEX(nvsciipc_mutex); +static DEFINE_MUTEX(nvsciipc_mutex); +static DEFINE_MUTEX(ep_mutex); static struct platform_device *nvsciipc_pdev; static struct nvsciipc *s_ctx; @@ -214,10 +215,13 @@ static void nvsciipc_free_db(struct nvsciipc *ctx) int i; if ((ctx->num_eps != 0) && (ctx->set_db_f == true)) { - for (i = 0; i < ctx->num_eps; i++) + for (i = 0; i < ctx->num_eps; i++) { kfree(ctx->db[i]); + kfree(ctx->stat[i]); + } kfree(ctx->db); + kfree(ctx->stat); } ctx->num_eps = 0; @@ -337,6 +341,109 @@ static int nvsciipc_ioctl_get_db_by_idx(struct nvsciipc *ctx, unsigned int cmd, return 0; } +static int nvsciipc_ioctl_reserve_ep(struct nvsciipc *ctx, unsigned int cmd, + unsigned long arg) +{ + struct nvsciipc_reserve_ep reserve_ep; + pid_t current_pid = task_pid_nr(current); + int i; + + if ((ctx->num_eps == 0) || (ctx->set_db_f != true)) { + ERR("%s[%d] need to set endpoint database first\n", __func__, + get_current()->pid); + return -EPERM; + } + + if (copy_from_user(&reserve_ep, (void __user *)arg, _IOC_SIZE(cmd))) { + ERR("%s : copy_from_user failed\n", __func__); + return -EFAULT; + } + + /* read operation */ + for (i = 0; i < ctx->num_eps; i++) { + if (!strncmp(reserve_ep.ep_name, ctx->db[i]->ep_name, + NVSCIIPC_MAX_EP_NAME)) { +// FIXME: consider android +#if defined(CONFIG_ANDROID) || defined(CONFIG_TEGRA_SYSTEM_TYPE_ACK) + /* Authenticate the client process with valid UID */ + if ((ctx->db[i]->uid != 0xFFFFFFFF) && + (current_cred()->uid.val != 0) && + (current_cred()->uid.val != ctx->db[i]->uid)) { + ERR("%s[Client_UID = %d] : " + "Unauthorized access to endpoint\n", + __func__, current_cred()->uid.val); + return -EPERM; + } +#endif /* CONFIG_ANDROID || CONFIG_TEGRA_SYSTEM_TYPE_ACK */ + mutex_lock(&ep_mutex); + /* reserve */ + if (reserve_ep.action == NVSCIIPC_EP_RESERVE) { + struct task_struct *task; + struct pid *pid_struct; + + pid_struct = find_get_pid(ctx->stat[i]->owner_pid); + task = pid_task(pid_struct, PIDTYPE_PID); + + /* endpoint is reserved and process is running */ + if (ctx->stat[i]->reserved && task) { + ERR("%s:RES %s is already reserved by %d\n", __func__, + reserve_ep.ep_name, ctx->stat[i]->owner_pid); + mutex_unlock(&ep_mutex); + return -EBUSY; + } + if (!task && (ctx->stat[i]->owner_pid != 0)) { + INFO("%s:RES pid(%d) for %s is NOT running\n", __func__, + ctx->stat[i]->owner_pid, reserve_ep.ep_name); + } + + ctx->stat[i]->reserved = NVSCIIPC_EP_RESERVE; + ctx->stat[i]->owner_pid = current_pid; + } + /* release */ + else if (reserve_ep.action == NVSCIIPC_EP_RELEASE) { + struct task_struct *task; + struct pid *pid_struct; + + pid_struct = find_get_pid(ctx->stat[i]->owner_pid); + task = pid_task(pid_struct, PIDTYPE_PID); + + if (ctx->stat[i]->reserved && + ((ctx->stat[i]->owner_pid != current_pid) && task)) { + ERR("%s:REL %s is already reserved by %d\n", __func__, + reserve_ep.ep_name, ctx->stat[i]->owner_pid); + mutex_unlock(&ep_mutex); + return -EPERM; + } + if (!task && (ctx->stat[i]->owner_pid != 0)) { + INFO("%s:REL pid(%d) for %s is NOT running\n", __func__, + ctx->stat[i]->owner_pid, reserve_ep.ep_name); + } + + ctx->stat[i]->reserved = NVSCIIPC_EP_RELEASE; + ctx->stat[i]->owner_pid = 0; + } + /* unknown action command */ + else { + mutex_unlock(&ep_mutex); + return -EINVAL; + } + mutex_unlock(&ep_mutex); + break; + } + } + + if (i == ctx->num_eps) { + INFO("%s: no entry (%s)\n", __func__, reserve_ep.ep_name); + return -ENOENT; + } else if (copy_to_user((void __user *)arg, &reserve_ep, + _IOC_SIZE(cmd))) { + ERR("%s : copy_to_user failed\n", __func__); + return -EFAULT; + } + + return 0; +} + static int nvsciipc_ioctl_get_db_by_name(struct nvsciipc *ctx, unsigned int cmd, unsigned long arg) { @@ -541,6 +648,16 @@ static int nvsciipc_ioctl_set_db(struct nvsciipc *ctx, unsigned int cmd, goto ptr_error; } + ctx->stat = (struct nvsciipc_res_stat **) + kzalloc(ctx->num_eps * sizeof(struct nvsciipc_res_stat *), + GFP_KERNEL); + + if (ctx->stat == NULL) { + ERR("memory allocation for ctx->stat failed\n"); + ret = -EFAULT; + goto ptr_error; + } + for (i = 0; i < ctx->num_eps; i++) { ctx->db[i] = (struct nvsciipc_config_entry *) kzalloc(sizeof(struct nvsciipc_config_entry), @@ -559,6 +676,16 @@ static int nvsciipc_ioctl_set_db(struct nvsciipc *ctx, unsigned int cmd, ret = -EFAULT; goto ptr_error; } + + ctx->stat[i] = (struct nvsciipc_res_stat *) + kzalloc(sizeof(struct nvsciipc_res_stat), + GFP_KERNEL); + + if (ctx->stat[i] == NULL) { + ERR("memory allocation for ctx->stat[%d] failed\n", i); + ret = -EFAULT; + goto ptr_error; + } } if (s_guestid != -1) { @@ -607,6 +734,18 @@ ptr_error: ctx->db = NULL; } + if (ctx->stat != NULL) { + for (i = 0; i < ctx->num_eps; i++) { + if (ctx->stat[i] != NULL) { + memset(ctx->stat[i], 0, sizeof(struct nvsciipc_res_stat)); + kfree(ctx->stat[i]); + } + } + + kfree(ctx->stat); + ctx->db = NULL; + } + if (entry_ptr != NULL) kfree(entry_ptr); @@ -670,6 +809,9 @@ long nvsciipc_dev_ioctl(struct file *filp, unsigned int cmd, case NVSCIIPC_IOCTL_GET_DB_BY_NAME: ret = nvsciipc_ioctl_get_db_by_name(ctx, cmd, arg); break; + case NVSCIIPC_IOCTL_RESERVE_EP: + ret = nvsciipc_ioctl_reserve_ep(ctx, cmd, arg); + break; case NVSCIIPC_IOCTL_GET_DB_BY_VUID: ret = nvsciipc_ioctl_get_db_by_vuid(ctx, cmd, arg); break; @@ -712,7 +854,7 @@ static ssize_t nvsciipc_dbg_read(struct file *filp, char __user *buf, /* check root user */ if ((current_cred()->uid.val != 0) && - (current_cred()->uid.val != 2000)) { + (current_cred()->uid.val != s_nvsciipc_uid)) { ERR("no permission to read db\n"); return -EPERM; } @@ -723,18 +865,23 @@ static ssize_t nvsciipc_dbg_read(struct file *filp, char __user *buf, return -EPERM; } + mutex_lock(&nvsciipc_mutex); + mutex_lock(&ep_mutex); for (i = 0; i < ctx->num_eps; i++) { - INFO("EP[%03d]: ep_name: %s, dev_name: %s, backend: %u, nframes: %u, ", + INFO("EP[%03d]: ep_name:%s, dev_name:%s, backend:%u, nframes:%u, frame_size:%u, id:%u, noti:%d(TRAP:1,MSI:2), uid:%d, res:%d, pid:%d\n", i, ctx->db[i]->ep_name, ctx->db[i]->dev_name, ctx->db[i]->backend, - ctx->db[i]->nframes); - INFO("frame_size: %u, id: %u, noti:%d(TRAP:1,MSI:2), uid: %d\n", + ctx->db[i]->nframes, ctx->db[i]->frame_size, ctx->db[i]->id, ctx->db[i]->noti_type, - ctx->db[i]->uid); + ctx->db[i]->uid, + ctx->stat[i]->reserved, + ctx->stat[i]->owner_pid); } + mutex_unlock(&ep_mutex); + mutex_unlock(&nvsciipc_mutex); return 0; } @@ -977,6 +1124,7 @@ static int nvsciipc_resume(struct platform_device *pdev) } #endif /* CONFIG_PM */ + static struct platform_driver nvsciipc_driver = { .probe = nvsciipc_probe, .remove = nvsciipc_remove_wrapper, diff --git a/drivers/misc/nvsciipc/nvsciipc.h b/drivers/misc/nvsciipc/nvsciipc.h index 1de00fcb..d5eae13e 100644 --- a/drivers/misc/nvsciipc/nvsciipc.h +++ b/drivers/misc/nvsciipc/nvsciipc.h @@ -22,6 +22,11 @@ #define NVSCIIPC_BACKEND_C2C_NPM 4U #define NVSCIIPC_BACKEND_UNKNOWN 0xFFFFFFFFU +struct nvsciipc_res_stat { + int reserved; + pid_t owner_pid; +}; + struct nvsciipc { struct device *dev; @@ -34,6 +39,7 @@ struct nvsciipc { int num_eps; struct nvsciipc_config_entry **db; volatile bool set_db_f; + struct nvsciipc_res_stat **stat; }; struct vuid_bitfield_64 { diff --git a/include/uapi/linux/nvsciipc_ioctl.h b/include/uapi/linux/nvsciipc_ioctl.h index bf57e486..cfebdf08 100644 --- a/include/uapi/linux/nvsciipc_ioctl.h +++ b/include/uapi/linux/nvsciipc_ioctl.h @@ -10,6 +10,9 @@ #define NVSCIIPC_MAX_RDMA_NAME 64U #define NVSCIIPC_MAX_IP_NAME 16U +#define NVSCIIPC_EP_RESERVE 1U +#define NVSCIIPC_EP_RELEASE 0U + struct nvsciipc_config_entry { /* endpoint name */ char ep_name[NVSCIIPC_MAX_EP_NAME]; @@ -82,6 +85,11 @@ struct nvsciipc_map_vuid { uint64_t peer_vuid; }; +struct nvsciipc_reserve_ep { + char ep_name[NVSCIIPC_MAX_EP_NAME]; + uint32_t action; +}; + /* IOCTL magic number - seen available in ioctl-number.txt*/ #define NVSCIIPC_IOCTL_MAGIC 0xC3 @@ -112,6 +120,9 @@ struct nvsciipc_map_vuid { #define NVSCIIPC_IOCTL_GET_DB_BY_IDX \ _IOWR(NVSCIIPC_IOCTL_MAGIC, 9, struct nvsciipc_get_db_by_idx) -#define NVSCIIPC_IOCTL_NUMBER_MAX 9 +#define NVSCIIPC_IOCTL_RESERVE_EP \ + _IOWR(NVSCIIPC_IOCTL_MAGIC, 10, struct nvsciipc_reserve_ep) + +#define NVSCIIPC_IOCTL_NUMBER_MAX 10 #endif /* __NVSCIIPC_IOCTL_H__ */