/* * linux/security/fivm/fivm_dev.c * * Copyright (C) 2014 Allwinner Ltd. * * Author: ryan.chen * * allwinner fivm controller device * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include "fivm.h" #define CMD_FIVM_INIT _IO('M', 0) #define CMD_FIVM_ENABLE _IO('M', 1) #define CMD_FIVM_SET _IOR('M', 2, struct fivm_param) #ifdef CONFIG_COMPAT #define CMD_FIVM_SET32 _IOR('M', 2, struct fivm_param_t32) #endif static dev_t dev; static struct cdev c_dev; static struct class *cl; static int fivm_open(struct inode *i, struct file *f) { return 0; } static int fivm_close(struct inode *i, struct file *f) { return 0; } extern int fivm_init(void); static long fivm_ioctl ( struct file *file, unsigned int cmd, unsigned long arg) { int rc = 0; switch (cmd) { case CMD_FIVM_ENABLE: rc = fivm_enable(); break; case CMD_FIVM_SET: rc = fivm_set((void *)arg); break; default: rc = -EINVAL; break; } return rc; } #ifdef CONFIG_COMPAT static long fivm_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg ) { int rc = 0; struct fivm_param_t32 param_t32; struct fivm_param __user *param; switch (cmd) { case CMD_FIVM_ENABLE: rc = fivm_enable(); break; case CMD_FIVM_SET32: if (copy_from_user(¶m_t32, (const void __user *)arg, sizeof(param_t32))) { pr_err("wrong copy from user param\n"); return -EFAULT; } param = compat_alloc_user_space(sizeof(*param)); if (!access_ok(VERIFY_READ, param, sizeof(*param))) { pr_err("access read fail for param\n"); return -EINVAL; } put_user(compat_ptr(param_t32.sig_head), ¶m->sig_head); put_user(param_t32.sig_head_size, ¶m->sig_head_size); put_user(compat_ptr(param_t32.sig_table), ¶m->sig_table); put_user(param_t32.sig_table_size, ¶m->sig_table_size); rc = fivm_set((void *)param); break; default: rc = -EINVAL; break; } return rc; } #endif static const struct file_operations fivm_fops = { .owner = THIS_MODULE, .open = fivm_open, .release = fivm_close, .unlocked_ioctl = fivm_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = fivm_compat_ioctl, #endif }; static int __init fivm_dev_init(void) /* Constructor */ { if (alloc_chrdev_region(&dev, 0, 1, "fivm_dev") < 0) { pr_err("fivm chrdev create fail\n"); return -1; } cl = class_create(THIS_MODULE, "fivm_drv"); if (!cl) { pr_err("fivm class create fail\n"); unregister_chrdev_region(dev, 1); return -1; } if (device_create(cl, NULL, dev, NULL, "fivm") == NULL) { pr_err("fivm device create fail\n"); class_destroy(cl); unregister_chrdev_region(dev, 1); return -1; } cdev_init(&c_dev, &fivm_fops); if (cdev_add(&c_dev, dev, 1) == -1) { pr_err("fivm cdev add fail\n"); device_destroy(cl, dev); class_destroy(cl); unregister_chrdev_region(dev, 1); return -1; } if (fivm_init() < 0) { pr_err("fivm init fail\n"); return -1; } pr_info("FIVM device register ok \n"); return 0; } static void __exit fivm_dev_exit(void) /* Destructor */ { cdev_del(&c_dev); device_destroy(cl, dev); class_destroy(cl); unregister_chrdev_region(dev, 1); fivm_cleanup(); } module_init(fivm_dev_init); module_exit(fivm_dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("ryan chen"); MODULE_DESCRIPTION("Sunxi file integrity verify module for system");