161 lines
3.1 KiB
C
161 lines
3.1 KiB
C
#include <asm/pgtable_64.h>
|
|
#include <linux/device.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <linux/uaccess.h>
|
|
#include <stddef.h>
|
|
|
|
#define DEVICE_NAME "lkm"
|
|
#define CLASS_NAME "lkmclass"
|
|
|
|
static int lkm_major;
|
|
static struct class *lkm_class;
|
|
static struct device *lkm_device;
|
|
|
|
static int lkm_init(void);
|
|
static void lkm_exit(void);
|
|
int lkm_open(struct inode *, struct file *);
|
|
int lkm_release(struct inode *, struct file *);
|
|
long lkm_ioctl(struct file *, unsigned int, long unsigned int);
|
|
|
|
static struct file_operations lkm_fops = {
|
|
.owner = THIS_MODULE,
|
|
.open = lkm_open,
|
|
.release = lkm_release,
|
|
.unlocked_ioctl = lkm_ioctl,
|
|
};
|
|
|
|
void
|
|
is2mb(size_t addr)
|
|
{
|
|
unsigned long above = ((long)addr) >> __VIRTUAL_MASK_SHIFT;
|
|
pgd_t *pgd;
|
|
p4d_t *p4d;
|
|
pud_t *pud;
|
|
pmd_t *pmd;
|
|
pte_t *pte;
|
|
|
|
if (above != 0 && above != -1UL)
|
|
return 0;
|
|
|
|
pgd = pgd_offset_pgd(_init_top_pgt, addr);
|
|
if (pgd_none(*pgd))
|
|
return 0;
|
|
|
|
p4d = p4d_offset(pgd, addr);
|
|
if (!p4d_present(*p4d))
|
|
return 0;
|
|
|
|
pud = pud_offset(p4d, addr);
|
|
if (!pud_present(*pud))
|
|
return 0;
|
|
|
|
if (pud_large(*pud))
|
|
return 0;
|
|
|
|
pmd = pmd_offset(pud, addr);
|
|
if (!pmd_present(*pmd))
|
|
return 0;
|
|
|
|
if (pmd_large(*pmd))
|
|
return 1;
|
|
|
|
pte = pte_offset_kernel(pmd, addr);
|
|
if (pte_none(*pte))
|
|
return 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
lkm_init(void)
|
|
{
|
|
printk(KERN_INFO "lkm: init: start\n");
|
|
int ret;
|
|
|
|
ret = register_chrdev(0, DEVICE_NAME, &lkm_fops);
|
|
if (ret < 0) {
|
|
printk(KERN_ERR "lkm: init: register chrdev failed\n");
|
|
return ret;
|
|
}
|
|
|
|
lkm_major = ret;
|
|
lkm_class = class_create(CLASS_NAME);
|
|
|
|
if (IS_ERR(lkm_class)) {
|
|
ret = PTR_ERR(lkm_device);
|
|
printk(KERN_ERR "lkm: init: create class failed\n");
|
|
unregister_chrdev(lkm_major, CLASS_NAME);
|
|
return ret;
|
|
}
|
|
|
|
lkm_device = device_create(lkm_class, 0, MKDEV(lkm_major, 0), 0,
|
|
DEVICE_NAME);
|
|
if (IS_ERR(lkm_device)) {
|
|
ret = PTR_ERR(lkm_device);
|
|
printk(KERN_ERR "lkm: init: create device failed\n");
|
|
class_unregister(lkm_class);
|
|
class_destroy(lkm_class);
|
|
unregister_chrdev(lkm_major, CLASS_NAME);
|
|
return ret;
|
|
}
|
|
|
|
printk(KERN_INFO "lkm: device driver created\n");
|
|
|
|
printk(KERN_INFO "lkm: init: done\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
lkm_exit(void)
|
|
{
|
|
printk(KERN_INFO "lkm: exit: start\n");
|
|
|
|
device_destroy(lkm_class, MKDEV(lkm_major, 0));
|
|
class_unregister(lkm_class);
|
|
unregister_chrdev(lkm_major, DEVICE_NAME);
|
|
|
|
printk(KERN_INFO "lkm: exit: done\n");
|
|
}
|
|
|
|
int
|
|
lkm_open(struct inode *inode, struct file *fp)
|
|
{
|
|
printk(KERN_INFO "lkm: open: start\n");
|
|
|
|
try_module_get(THIS_MODULE);
|
|
|
|
printk(KERN_INFO "lkm: open: done\n");
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
lkm_release(struct inode *inode, struct file *fp)
|
|
{
|
|
printk(KERN_INFO "lkm: release: start\n");
|
|
|
|
module_put(THIS_MODULE);
|
|
|
|
printk(KERN_INFO "lkm: release: done\n");
|
|
return 0;
|
|
}
|
|
|
|
long
|
|
lkm_ioctl(struct file *fp, unsigned num, long unsigned int param)
|
|
{
|
|
printk(KERN_INFO "lkm: release: start\n");
|
|
|
|
printk(KERN_INFO "lkm: release: done\n");
|
|
return 0;
|
|
}
|
|
|
|
MODULE_AUTHOR("Mira Chacku Purakal");
|
|
MODULE_DESCRIPTION("Generic Module");
|
|
MODULE_VERSION("0.1");
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_init(lkm_init);
|
|
module_exit(lkm_exit);
|