aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Thompson <daniel.thompson@linaro.org>2014-06-17 10:26:08 +0100
committerDaniel Thompson <daniel.thompson@linaro.org>2014-06-20 10:19:48 +0100
commitc7516eabdfac8fa3459e644efc52d56c4dbcf0a8 (patch)
treeed7c4a6efaf39655341caf29f2f3088b91abdf3b
parent520d39037a8042284cbb7352c1e88e45c309297e (diff)
WIP: getputuser test driver
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/getputuser.c220
2 files changed, 221 insertions, 0 deletions
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c8f7bfc235b9..0ed44a04db5e 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_GENWQE) += genwqe/
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
obj-y += lockup.o
+obj-y += getputuser.o
diff --git a/drivers/misc/getputuser.c b/drivers/misc/getputuser.c
new file mode 100644
index 000000000000..0dcbd3cbc0d0
--- /dev/null
+++ b/drivers/misc/getputuser.c
@@ -0,0 +1,220 @@
+/*
+ * getputuser.c
+ *
+ * ioctl to fetch data from userspace and check its OK.
+ *
+ * Copyright (C) 2014 Linaro Limited
+ * Daniel Thompson <daniel.thompson@linaro.org>
+ */
+
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#define GPUSR_MAX_DEVS 1
+
+static struct class *gpusr_class;
+static int gpusr_major;
+static struct cdev gpusr_cdev;
+
+struct gpusr_device {
+ int dummy;
+};
+
+struct gpusr_input {
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
+ int8_t s8;
+ int16_t s16;
+ int32_t s32;
+ int64_t s64;
+};
+
+struct gpusr_cmd {
+ struct gpusr_input *input;
+ uint8_t *pu8;
+ uint16_t *pu16;
+ uint32_t *pu32;
+ uint64_t *pu64;
+};
+
+#define IOC_GET_COPY _IOWR('g', 0x01, struct gpusr_cmd)
+
+static struct gpusr_device gpusr_devs[GPUSR_MAX_DEVS];
+
+static int gpusr_open(struct inode *inode, struct file *file)
+{
+ struct gpusr_device *gpusr;
+
+ gpusr = &gpusr_devs[0]; /* HACK */
+ file->private_data = gpusr;
+
+ return 0;
+}
+
+static int gpusr_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static long gpusr_getuser_copytouser(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct gpusr_cmd __user *gpcmd = (void __user *)arg;
+ struct gpusr_input __user *input;
+ uint8_t au8[8];
+ uint16_t au16[8];
+ uint32_t au32[8];
+ uint64_t au64[8];
+
+ memset(au64, 0xcc, sizeof(au64));
+
+ if (get_user(input, &gpcmd->input))
+ return -EFAULT;
+
+ if (get_user(au8[0], &input->u8))
+ return -EFAULT;
+ if (get_user(au8[1], &input->u16))
+ return -EFAULT;
+ if (get_user(au8[2], &input->u32))
+ return -EFAULT;
+ if (get_user(au8[3], &input->u64))
+ return -EFAULT;
+ if (get_user(au8[4], &input->s8))
+ return -EFAULT;
+ if (get_user(au8[5], &input->s16))
+ return -EFAULT;
+ if (get_user(au8[6], &input->s32))
+ return -EFAULT;
+ if (get_user(au8[7], &input->s64))
+ return -EFAULT;
+
+ if (get_user(au16[0], &input->u8))
+ return -EFAULT;
+ if (get_user(au16[1], &input->u16))
+ return -EFAULT;
+ if (get_user(au16[2], &input->u32))
+ return -EFAULT;
+ if (get_user(au16[3], &input->u64))
+ return -EFAULT;
+ if (get_user(au16[4], &input->s8))
+ return -EFAULT;
+ if (get_user(au16[5], &input->s16))
+ return -EFAULT;
+ if (get_user(au16[6], &input->s32))
+ return -EFAULT;
+ if (get_user(au16[7], &input->s64))
+ return -EFAULT;
+
+ if (get_user(au32[0], &input->u8))
+ return -EFAULT;
+ if (get_user(au32[1], &input->u16))
+ return -EFAULT;
+ if (get_user(au32[2], &input->u32))
+ return -EFAULT;
+ if (get_user(au32[3], &input->u64))
+ return -EFAULT;
+ if (get_user(au32[4], &input->s8))
+ return -EFAULT;
+ if (get_user(au32[5], &input->s16))
+ return -EFAULT;
+ if (get_user(au32[6], &input->s32))
+ return -EFAULT;
+ if (get_user(au32[7], &input->s64))
+ return -EFAULT;
+
+ if (get_user(au64[0], &input->u8))
+ return -EFAULT;
+ if (get_user(au64[1], &input->u16))
+ return -EFAULT;
+ if (get_user(au64[2], &input->u32))
+ return -EFAULT;
+ if (get_user(au64[3], &input->u64))
+ return -EFAULT;
+ if (get_user(au64[4], &input->s8))
+ return -EFAULT;
+ if (get_user(au64[5], &input->s16))
+ return -EFAULT;
+ if (get_user(au64[6], &input->s32))
+ return -EFAULT;
+ if (get_user(au64[7], &input->s64))
+ return -EFAULT;
+
+ if (copy_to_user(gpcmd->pu8, au8, sizeof(au8)))
+ return -EFAULT;
+ if (copy_to_user(gpcmd->pu16, au16, sizeof(au16)))
+ return -EFAULT;
+ if (copy_to_user(gpcmd->pu32, au32, sizeof(au32)))
+ return -EFAULT;
+ if (copy_to_user(gpcmd->pu64, au64, sizeof(au64)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static long gpusr_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case IOC_GET_COPY:
+ return gpusr_getuser_copytouser(file, cmd, arg);
+ }
+
+ return -ENODEV;
+}
+
+static const struct file_operations gpusr_fops = {
+ .owner = THIS_MODULE,
+ .open = gpusr_open,
+ .release = gpusr_release,
+ .unlocked_ioctl = gpusr_ioctl,
+};
+
+static int __init gpusr_init(void)
+{
+ int ret;
+ dev_t devid;
+
+ gpusr_class = class_create(THIS_MODULE, "gpusr");
+ if (IS_ERR(gpusr_class))
+ return PTR_ERR(gpusr_class);
+
+ ret = alloc_chrdev_region(&devid, 0, GPUSR_MAX_DEVS, "gpusr");
+ if (ret)
+ goto destroy_class;
+
+ gpusr_major = MAJOR(devid);
+
+ cdev_init(&gpusr_cdev, &gpusr_fops);
+ ret = cdev_add(&gpusr_cdev, MKDEV(gpusr_major, 0), GPUSR_MAX_DEVS);
+ if (ret)
+ goto unregister_chrdev;
+
+ /* This code isn't enough... I've missed something but need to
+ * make some progress TODAY.
+ */
+ debugfs_create_file("getputuser", S_IRUGO | S_IWUSR, NULL, NULL,
+ &gpusr_fops);
+
+ pr_info("gpusr: getputuser test driver\n");
+ return 0;
+
+unregister_chrdev:
+ unregister_chrdev_region(MKDEV(gpusr_major, 0), GPUSR_MAX_DEVS);
+destroy_class:
+ class_destroy(gpusr_class);
+ return ret;
+}
+module_init(gpusr_init);
+
+static void __exit gpusr_exit(void)
+{
+ unregister_chrdev_region(MKDEV(gpusr_major, 0), GPUSR_MAX_DEVS);
+ class_destroy(gpusr_class);
+}
+module_exit(gpusr_exit);
+
+