176 lines
3.8 KiB
C
176 lines
3.8 KiB
C
|
/*
|
||
|
* 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(¶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<ryanchen@allsoftwinnertech.com>");
|
||
|
MODULE_DESCRIPTION("Sunxi file integrity verify module for system");
|
||
|
|