diff options
author | Daniel Thompson <daniel.thompson@linaro.org> | 2014-06-17 10:26:08 +0100 |
---|---|---|
committer | Daniel Thompson <daniel.thompson@linaro.org> | 2014-06-20 10:19:48 +0100 |
commit | c7516eabdfac8fa3459e644efc52d56c4dbcf0a8 (patch) | |
tree | ed7c4a6efaf39655341caf29f2f3088b91abdf3b | |
parent | 520d39037a8042284cbb7352c1e88e45c309297e (diff) |
WIP: getputuser test driver
Signed-off-by: Daniel Thompson <daniel.thompson@linaro.org>
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/getputuser.c | 220 |
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); + + |