[RFC PATCH 6/6] char: fastrpc: Add support for compat ioctls

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Thierry Escande <thierry.escande@xxxxxxxxxx>

This patch adds support for compat ioctl from 32 bits userland to
Qualcomm fastrpc driver.

Supported ioctls in this change are INIT, INVOKE, and ALLOC/FREE_DMA.

Most of the work is derived from various downstream Qualcomm kernels.
Credits to various Qualcomm authors who have contributed to this code.
Specially Tharun Kumar Merugu <mtharu@xxxxxxxxxxxxxx>

Signed-off-by: Thierry Escande <thierry.escande@xxxxxxxxxx>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx>
---
 drivers/char/fastrpc.c | 279 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 279 insertions(+)

diff --git a/drivers/char/fastrpc.c b/drivers/char/fastrpc.c
index 3c52502eae9f..0b99a13109ea 100644
--- a/drivers/char/fastrpc.c
+++ b/drivers/char/fastrpc.c
@@ -3,6 +3,7 @@
 // Copyright (c) 2018, Linaro Limited
 
 #include <linux/cdev.h>
+#include <linux/compat.h>
 #include <linux/completion.h>
 #include <linux/device.h>
 #include <linux/dma-buf.h>
@@ -1207,10 +1208,288 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int cmd,
 	return err;
 }
 
+#ifdef CONFIG_COMPAT
+
+#define FASTRPC_COMPAT_IOCTL_ALLOC_DMA_BUFF \
+		_IOWR('R', 1, struct fastrpc_compat_ioctl_alloc_dma_buf)
+#define FASTRPC_COMPAT_IOCTL_FREE_DMA_BUFF \
+		_IOWR('R', 2, uint32_t)
+#define FASTRPC_COMPAT_IOCTL_INVOKE \
+		_IOWR('R', 3, struct fastrpc_compat_ioctl_invoke)
+#define FASTRPC_COMPAT_IOCTL_INIT \
+		_IOWR('R', 4, struct fastrpc_compat_ioctl_init)
+
+struct compat_remote_buf {
+	compat_uptr_t pv;	/* buffer pointer */
+	compat_size_t len;	/* length of buffer */
+};
+
+union compat_remote_arg {
+	struct compat_remote_buf buf;
+	compat_uint_t h;
+};
+
+struct fastrpc_compat_ioctl_alloc_dma_buf {
+	compat_int_t   fd;
+	compat_ssize_t size;
+	compat_uint_t  flags;
+};
+
+struct fastrpc_compat_ioctl_invoke {
+	compat_uint_t handle;	/* remote handle */
+	compat_uint_t sc;	/* scalars describing the data */
+	compat_uptr_t pra;	/* remote arguments list */
+	compat_uptr_t fds;	/* fd list */
+	compat_uptr_t attrs;	/* attribute list */
+	compat_uptr_t crc;	/* crc list */
+};
+
+struct fastrpc_compat_ioctl_init {
+	compat_uint_t flags;	/* one of FASTRPC_INIT_* macros */
+	compat_uptr_t file;	/* pointer to elf file */
+	compat_int_t filelen;	/* elf file length */
+	compat_int_t filefd;	/* dmabuf fd for the file */
+	compat_uptr_t mem;	/* mem for the PD */
+	compat_int_t memlen;	/* mem length */
+	compat_int_t memfd;	/* dmabuf fd for the mem */
+	compat_int_t attrs;	/* attributes to init process */
+	compat_int_t siglen;	/* test signature file length */
+};
+
+static int fastrpc_compat_get_ioctl_alloc_dma_buf(
+			struct fastrpc_compat_ioctl_alloc_dma_buf __user *buf32,
+			struct fastrpc_ioctl_alloc_dma_buf __user *buf)
+{
+	compat_size_t size;
+	compat_uint_t flags;
+	int err;
+
+	err = put_user(0, &buf->fd);
+	err |= get_user(size, &buf32->size);
+	err |= put_user(size, &buf->size);
+	err |= get_user(flags, &buf32->flags);
+	err |= put_user(flags, &buf->flags);
+
+	return err;
+}
+
+static int fastrpc_compat_put_ioctl_alloc_dma_buf(
+			struct fastrpc_compat_ioctl_alloc_dma_buf __user *buf32,
+			struct fastrpc_ioctl_alloc_dma_buf __user *buf)
+{
+	compat_int_t fd;
+	int err;
+
+	err = get_user(fd, &buf->fd);
+	err |= put_user(fd, &buf32->fd);
+
+	return err;
+}
+
+static int compat_get_fastrpc_ioctl_invoke(
+			struct fastrpc_compat_ioctl_invoke __user *inv32,
+			struct fastrpc_ioctl_invoke __user **inva)
+{
+	compat_uint_t u, sc;
+	compat_size_t s;
+	compat_uptr_t p;
+	struct fastrpc_ioctl_invoke *inv;
+	union compat_remote_arg *pra32;
+	union remote_arg *pra;
+	int err, len, j;
+
+	err = get_user(sc, &inv32->sc);
+	if (err)
+		return err;
+
+	len = REMOTE_SCALARS_LENGTH(sc);
+	inv = compat_alloc_user_space(sizeof(*inv) + len * sizeof(*pra));
+	if (!inv)
+		return -EFAULT;
+
+	pra = (union remote_arg *)(inv + 1);
+	err = put_user(pra, &inv->pra);
+	err |= put_user(sc, &inv->sc);
+	err |= get_user(u, &inv32->handle);
+	err |= put_user(u, &inv->handle);
+	err |= get_user(p, &inv32->pra);
+	if (err)
+		return err;
+
+	pra32 = compat_ptr(p);
+	pra = (union remote_arg *)(inv + 1);
+	for (j = 0; j < len; j++) {
+		err |= get_user(p, &pra32[j].buf.pv);
+		err |= put_user(p, (uintptr_t *)&pra[j].buf.pv);
+		err |= get_user(s, &pra32[j].buf.len);
+		err |= put_user(s, &pra[j].buf.len);
+	}
+
+	err |= put_user(NULL, &inv->fds);
+	if (inv32->fds) {
+		err |= get_user(p, &inv32->fds);
+		err |= put_user(p, (compat_uptr_t *)&inv->fds);
+	}
+
+	err |= put_user(NULL, &inv->attrs);
+	if (inv32->attrs) {
+		err |= get_user(p, &inv32->attrs);
+		err |= put_user(p, (compat_uptr_t *)&inv->attrs);
+	}
+
+	err |= put_user(NULL, (compat_uptr_t __user **)&inv->crc);
+	if (inv32->crc) {
+		err |= get_user(p, &inv32->crc);
+		err |= put_user(p, (compat_uptr_t __user *)&inv->crc);
+	}
+
+	*inva = inv;
+
+	return err;
+}
+
+static int compat_get_fastrpc_ioctl_init(
+				struct fastrpc_compat_ioctl_init __user *init32,
+				struct fastrpc_ioctl_init __user *init)
+{
+	compat_uint_t u;
+	compat_uptr_t p;
+	compat_int_t i;
+	int err;
+
+	err = get_user(u, &init32->flags);
+	err |= put_user(u, &init->flags);
+	err |= get_user(p, &init32->file);
+	err |= put_user(p, &init->file);
+	err |= get_user(i, &init32->filelen);
+	err |= put_user(i, &init->filelen);
+	err |= get_user(i, &init32->filefd);
+	err |= put_user(i, &init->filefd);
+	err |= get_user(p, &init32->mem);
+	err |= put_user(p, &init->mem);
+	err |= get_user(i, &init32->memlen);
+	err |= put_user(i, &init->memlen);
+	err |= get_user(i, &init32->memfd);
+	err |= put_user(i, &init->memfd);
+
+	err |= put_user(0, &init->attrs);
+	if (init32->attrs) {
+		err |= get_user(i, &init32->attrs);
+		err |= put_user(i, &init->attrs);
+	}
+
+	err |= put_user(0, &init->siglen);
+	if (init32->siglen) {
+		err |= get_user(i, &init32->siglen);
+		err |= put_user(i, &init->siglen);
+	}
+
+	return err;
+}
+
+static long fastrpc_compat_device_ioctl(struct file *filp, unsigned int cmd,
+					unsigned long arg)
+{
+	int err;
+
+	if (!filp->f_op || !filp->f_op->unlocked_ioctl)
+		return -ENOTTY;
+
+	switch (cmd) {
+	case FASTRPC_COMPAT_IOCTL_ALLOC_DMA_BUFF: {
+		struct fastrpc_compat_ioctl_alloc_dma_buf __user *buf32;
+		struct fastrpc_ioctl_alloc_dma_buf __user *buf;
+
+		buf32 = compat_ptr(arg);
+		buf = compat_alloc_user_space(sizeof(*buf));
+		if (!buf) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = fastrpc_compat_get_ioctl_alloc_dma_buf(buf32, buf);
+		if (err)
+			break;
+
+		err = filp->f_op->unlocked_ioctl(filp,
+						 FASTRPC_IOCTL_ALLOC_DMA_BUFF,
+						 (unsigned long)buf);
+		if (err)
+			break;
+
+		err = fastrpc_compat_put_ioctl_alloc_dma_buf(buf32, buf);
+		break;
+	}
+	case FASTRPC_COMPAT_IOCTL_FREE_DMA_BUFF: {
+		compat_uptr_t __user *info32;
+		uint32_t __user *info;
+		compat_uint_t u;
+
+		info32 = compat_ptr(arg);
+		info = compat_alloc_user_space(sizeof(*info));
+		if (!info) {
+			err = -EFAULT;
+			break;
+		}
+
+		err = get_user(u, info32);
+		err |= put_user(u, info);
+		if (err)
+			break;
+
+		err = filp->f_op->unlocked_ioctl(filp,
+						 FASTRPC_IOCTL_FREE_DMA_BUFF,
+						 (unsigned long)info);
+		break;
+	}
+	case FASTRPC_COMPAT_IOCTL_INVOKE: {
+		struct fastrpc_compat_ioctl_invoke __user *inv32;
+		struct fastrpc_ioctl_invoke __user *inv;
+
+		inv32 = compat_ptr(arg);
+
+		err = compat_get_fastrpc_ioctl_invoke(inv32, &inv);
+		if (err)
+			break;
+
+		err = filp->f_op->unlocked_ioctl(filp,
+				FASTRPC_IOCTL_INVOKE, (unsigned long)inv);
+		break;
+	}
+	case FASTRPC_COMPAT_IOCTL_INIT: {
+		struct fastrpc_compat_ioctl_init __user *init32;
+		struct fastrpc_ioctl_init __user *init;
+
+		init32 = compat_ptr(arg);
+		init = compat_alloc_user_space(sizeof(*init));
+		if (!init)
+			return -EFAULT;
+
+		err = compat_get_fastrpc_ioctl_init(init32, init);
+		if (err)
+			return err;
+
+		err = filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_INIT,
+						 (unsigned long)init);
+		break;
+	}
+	default:
+		err = -ENOTTY;
+		pr_info("bad ioctl: %d\n", cmd);
+		break;
+	}
+
+	return err;
+}
+#endif /* CONFIG_COMPAT */
+
 static const struct file_operations fastrpc_fops = {
 	.open = fastrpc_device_open,
 	.release = fastrpc_device_release,
 	.unlocked_ioctl = fastrpc_device_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = fastrpc_compat_device_ioctl,
+#endif
 };
 
 static int fastrpc_cb_probe(struct platform_device *pdev)
-- 
2.19.2




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux