SmartAudio/lichee/linux-4.9/security/fivm/fivm_dev.c

176 lines
3.8 KiB
C
Raw Normal View History

2018-07-13 01:31:50 +00:00
/*
* linux/security/fivm/fivm_dev.c
*
* Copyright (C) 2014 Allwinner Ltd.
*
* Author: ryan.chen <ryanchen@allwinnertech.com>
*
* 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 <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/compat.h>
#include <linux/uaccess.h>
#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(&param_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),
&param->sig_head);
put_user(param_t32.sig_head_size,
&param->sig_head_size);
put_user(compat_ptr(param_t32.sig_table),
&param->sig_table);
put_user(param_t32.sig_table_size,
&param->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<ryanchen@allsoftwinnertech.com>");
MODULE_DESCRIPTION("Sunxi file integrity verify module for system");