Skip to content
Snippets Groups Projects
Select Git revision
  • 40aef25d3cdb59ebabd268a2d924466dd95218f3
  • main default protected
2 results

basic_functions.h

Blame
  • kmod.c 4.17 KiB
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/cdev.h>
    #include <linux/vmalloc.h>
    #include <linux/uaccess.h>
    #include <linux/hrtimer.h>
    #include <linux/kthread.h>
    #include "../common/include/message.h"
    
    #define DEVICE_NAME "amogus"
    #define CLASS_NAME "amogus_class"
    
    #define SLOTS 4
    #define SLOT_INTERVAL_NS 250000
    
    static int major_number;
    static struct class* class = NULL;
    static struct cdev mycdev;
    
    static message_t* message;
    
    static struct hrtimer timer;
    static ktime_t interval;
    
    static struct task_struct *timed_thread;
    
    static DECLARE_WAIT_QUEUE_HEAD(wq);
    static atomic_t wake_counter = ATOMIC_INIT(0);
    
    static int slot = 0;
    
    static int device_open(struct inode *inode, struct file *file)
    {
        return 0;
    }
    
    static int device_release(struct inode *inode, struct file *file)
    {
        return 0;
    }
    
    static ssize_t device_write(struct file *filp, const char *input,
                               size_t length, loff_t *offset)
    {
        if(length != sizeof(message_t)) {
            printk(KERN_ALERT "lkm: Tried to to write more bytes than allowed\n");
            return -EFAULT;
        }
    
        if (copy_from_user((void*)message, input, length)) {
            return -EFAULT;
        }
    
        printk(KERN_INFO "lkm: received write of size %zu\n",length);
    
        return length;
    }
    
    static const struct file_operations fops = {
        .write = device_write,
        .open = device_open,
        .release = device_release
    };
    
    static enum hrtimer_restart timer_callback(struct hrtimer *timer) {
        atomic_inc(&wake_counter);
        wake_up_interruptible(&wq);
    
        hrtimer_forward_now(timer, interval);
        return HRTIMER_RESTART;
    }
    
    static int timed_thread_fn(void *args) {
        while (!kthread_should_stop()) {
            wait_event_interruptible(wq, atomic_read(&wake_counter) > 0);
            atomic_dec(&wake_counter);
    
            if (slot == 0) {}
    
            slot = (slot + 1) % SLOTS;
        }
    
        return 0;
    }
    
    static int __init lkm_init(void)
    {
        dev_t dev;
    
        message = (message_t*)vmalloc(sizeof(message_t));
    
        if(message == NULL) {
            return -1;
        }
    
        // Dynamically allocate major number
        if (alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME) < 0) {
            vfree(message);
            printk(KERN_ALERT "Failed to allocate major number\n");
            return -1;
        }
        major_number = MAJOR(dev);
    
        class = class_create(CLASS_NAME);
        if (IS_ERR(class)) {
            vfree(message);
            unregister_chrdev_region(MKDEV(major_number, 0), 1);
            printk(KERN_ALERT "Failed to create device class\n");
            return PTR_ERR(class);
        }
    
        if (device_create(class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME) == NULL) {
            vfree(message);
            class_destroy(class);
            unregister_chrdev_region(MKDEV(major_number, 0), 1);
            printk(KERN_ALERT "Failed to create device\n");
            return -1;
        }
    
        cdev_init(&mycdev, &fops);
        if (cdev_add(&mycdev, MKDEV(major_number, 0), 1) < 0) {
            vfree(message);
            device_destroy(class, MKDEV(major_number, 0));
            class_destroy(class);
            unregister_chrdev_region(MKDEV(major_number, 0), 1);
            printk(KERN_ALERT "Failed to add character device\n");
            return -1;
        }
    
        printk(KERN_INFO "lkm: device created successfully\n");
    
        interval = ktime_set(0, SLOT_INTERVAL_NS);
        hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
        timer.function = timer_callback;
        hrtimer_start(&timer, interval, HRTIMER_MODE_REL);
    
        timed_thread = kthread_run(timed_thread_fn, NULL, "timed_thread");
        if (IS_ERR(timed_thread)) {
            vfree(message);
            cdev_del(&mycdev);
            device_destroy(class, MKDEV(major_number, 0));
            class_destroy(class);
            unregister_chrdev_region(MKDEV(major_number, 0), 1);
    
            hrtimer_cancel(&timer);
    
            printk(KERN_ALERT "Failed to create timed thread\n");
            return -1;
        }
    
        return 0;
    }
    
    static void __exit lkm_exit(void)
    {
        vfree(message);
        cdev_del(&mycdev);
        device_destroy(class, MKDEV(major_number, 0));
        class_destroy(class);
        unregister_chrdev_region(MKDEV(major_number, 0), 1);
        printk(KERN_INFO "lkm: device removed successfully\n");
    
        hrtimer_cancel(&timer);
    }
    
    module_init(lkm_init);
    module_exit(lkm_exit);
    
    MODULE_LICENSE("GPL");