diff --git a/work/tp2/Makefile b/work/tp2/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..21007509478e580d274df46a65949efd70803fcc --- /dev/null +++ b/work/tp2/Makefile @@ -0,0 +1,9 @@ +KDIR=../../build/kvm/ + +obj-m += pipebis.o +PWD := $(CURDIR) + +all: + make -C $(KDIR) M=$(PWD) modules +clean: + make -C $(KDIR) M=$(PWD) clean diff --git a/work/tp2/modules.order b/work/tp2/modules.order new file mode 100644 index 0000000000000000000000000000000000000000..fd9a996b3556a2bd158216de1636cfb0b0e20c1b --- /dev/null +++ b/work/tp2/modules.order @@ -0,0 +1 @@ +/root/Desktop/asee/work/tp2/pipebis.o diff --git a/work/tp2/pipebis.c b/work/tp2/pipebis.c new file mode 100644 index 0000000000000000000000000000000000000000..43e97c4b49f356faa1ef3d0c9b5fa2e8d33ff438 --- /dev/null +++ b/work/tp2/pipebis.c @@ -0,0 +1,241 @@ +/* + * pipebis.c: Creates a read-only char device that says how many times + * you have read from the dev file + */ + +#include <linux/atomic.h> +#include <linux/cdev.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> /* for sprintf() */ +#include <linux/module.h> +#include <linux/printk.h> +#include <linux/types.h> +#include <linux/uaccess.h> /* for get_user and put_user */ +#include <linux/version.h> + +#include <asm/errno.h> + +/* Prototypes - this would normally go in a .h file */ +static int device_open(struct inode *, struct file *); +static int device_release(struct inode *, struct file *); +static ssize_t device_read(struct file *, char __user *, size_t, loff_t *); +static ssize_t device_write(struct file *, const char __user *, size_t, + loff_t *); + +#define SUCCESS 0 +#define DEVICE_NAME "asee_mod" /* Dev name as it appears in /proc/devices */ +#define BUF_LEN 16 /* Max length of the message from the device */ + +/* Global variables are declared as static, so are global within the file. */ + +static char *msg; /* The msg the device will give when asked */ + +static struct kobject *pipebis_module; + +static int asee_buf_count = 0; + +static int asee_buf_size = BUF_LEN; + +static ssize_t asee_buf_size_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", asee_buf_size); +} + +static ssize_t asee_buf_size_store(struct kobject *kobj, struct kobj_attribute *attr, char *buf, size_t count) +{ + int old_size = asee_buf_size; + sscanf(buf, "%du", &asee_buf_size); + if (asee_buf_size <= asee_buf_count) { + asee_buf_size = old_size; + pr_err("New size for buffer should be less than current content in it"); + return count; + } + + char * second_message = kcalloc(asee_buf_size, sizeof(char), GFP_KERNEL); + for(int cpt = 0; cpt < old_size; cpt++) { + second_message[cpt] = msg[cpt]; + } + kfree(msg); + msg = second_message; + // TODO: incresae buffer size + return count; +} + +static struct kobj_attribute asee_buf_size_attribute = __ATTR(asee_buf_size, 0660, asee_buf_size_show, (void *)asee_buf_size_store); + + +static ssize_t asee_buf_count_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", asee_buf_count); +} + +static ssize_t asee_buf_count_store(struct kobject *kobj, struct kobj_attribute *attr, char *buf, size_t count) +{ + return count; +} + +static struct kobj_attribute asee_buf_count_attribute = __ATTR(asee_buf_count, 0660, asee_buf_count_show, (void *)asee_buf_count_store); + +static int major; /* major number assigned to our device driver */ + +enum { + CDEV_NOT_USED = 0, + CDEV_EXCLUSIVE_OPEN = 1, +}; + +/* Is device open? Used to prevent multiple access to device */ +static atomic_t already_open = ATOMIC_INIT(CDEV_NOT_USED); + +static struct class *cls; + +static struct file_operations pipebis_fops = { + .read = device_read, + .write = device_write, + .open = device_open, + .release = device_release, +}; + +static int __init pipebis_init(void) +{ + major = register_chrdev(0, DEVICE_NAME, &pipebis_fops); + + if (major < 0) { + pr_alert("Registering char device failed with %d\n", major); + return major; + } + + pr_info("I was assigned major number %d.\n", major); + + msg = kcalloc(asee_buf_size, sizeof(char), GFP_KERNEL); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 4, 0) + cls = class_create(DEVICE_NAME); +#else + cls = class_create(THIS_MODULE, DEVICE_NAME); +#endif + device_create(cls, NULL, MKDEV(major, 0), NULL, DEVICE_NAME); + + pr_info("Device created on /dev/%s\n", DEVICE_NAME); + + pipebis_module = kobject_create_and_add("asee_mod", kernel_kobj); + if (!pipebis_module) return -ENOMEM; + + int error = 0; + error = sysfs_create_file(pipebis_module, &asee_buf_size_attribute.attr); + error += sysfs_create_file(pipebis_module, &asee_buf_count_attribute.attr); + if (error) { + pr_info("failed to create a asee variable in /sys/kernel/asee_mod\n"); + return error; + } + + return SUCCESS; +} + +static void __exit pipebis_exit(void) +{ + device_destroy(cls, MKDEV(major, 0)); + class_destroy(cls); + + /* Unregister the device */ + unregister_chrdev(major, DEVICE_NAME); + kobject_put(pipebis_module); +} + +/* Methods */ + +/* Called when a process tries to open the device file, like + * "sudo cat /dev/pipebis" + */ +static int device_open(struct inode *inode, struct file *file) +{ + if (atomic_cmpxchg(&already_open, CDEV_NOT_USED, CDEV_EXCLUSIVE_OPEN)) + return -EBUSY; + + try_module_get(THIS_MODULE); + + return SUCCESS; +} + +/* Called when a process closes the device file. */ +static int device_release(struct inode *inode, struct file *file) +{ + /* We're now ready for our next caller */ + atomic_set(&already_open, CDEV_NOT_USED); + + /* Decrement the usage count, or else once you opened the file, you will + * never get rid of the module. + */ + module_put(THIS_MODULE); + + return SUCCESS; +} + +/* Called when a process, which already opened the dev file, attempts to + * read from it. + */ +static int last_writen_bytes; +static ssize_t device_read(struct file *filp, /* see include/linux/fs.h */ + char __user *buffer, /* buffer to fill with data */ + size_t length, /* length of the buffer */ + loff_t *offset) +{ + /* Number of bytes actually written to the buffer */ + int bytes_read = 0; + char *msg_ptr = msg; + + /* Actually put the data into the buffer */ + while (asee_buf_count > 0) { + if (last_writen_bytes >= asee_buf_size) { + last_writen_bytes = 0; + } + /* The buffer is in the user data segment, not the kernel + * segment so "*" assignment won't work. We have to use + * put_user which copies data from the kernel data segment to + * the user data segment. + */ + + put_user(*(msg_ptr + last_writen_bytes), buffer++); + // Try to clear the read + *(msg_ptr + last_writen_bytes) = '\0'; + last_writen_bytes++; + asee_buf_count--; + bytes_read++; + } + + *offset = last_writen_bytes; + + /* Most read functions return the number of bytes put into the buffer. */ + return bytes_read; +} + +/* Called when a process writes to dev file: echo "hi" > /dev/hello */ +static ssize_t device_write(struct file *filp, const char __user *buff, + size_t len, loff_t *off) +{ + int bytes_writen = 0; + + int current_bytes = last_writen_bytes; + + for (int cpt = 0; cpt < len; cpt++) { + if (current_bytes >= asee_buf_size) { + current_bytes = 0; + } + get_user(*(msg + current_bytes), buff + cpt); + current_bytes++; + bytes_writen++; + asee_buf_count++; + } + + last_writen_bytes = current_bytes; + *off = last_writen_bytes; + + return bytes_writen; +} + +module_init(pipebis_init); +module_exit(pipebis_exit); + +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/work/tp2/pipebis.mod.c b/work/tp2/pipebis.mod.c new file mode 100644 index 0000000000000000000000000000000000000000..b9e4454e83f21cc3d453c396c90caf765fec9035 --- /dev/null +++ b/work/tp2/pipebis.mod.c @@ -0,0 +1,65 @@ +#include <linux/module.h> +#define INCLUDE_VERMAGIC +#include <linux/build-salt.h> +#include <linux/elfnote-lto.h> +#include <linux/export-internal.h> +#include <linux/vermagic.h> +#include <linux/compiler.h> + +#ifdef CONFIG_UNWINDER_ORC +#include <asm/orc_header.h> +ORC_HEADER; +#endif + +BUILD_SALT; +BUILD_LTO_INFO; + +MODULE_INFO(vermagic, VERMAGIC_STRING); +MODULE_INFO(name, KBUILD_MODNAME); + +__visible struct module __this_module +__section(".gnu.linkonce.this_module") = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +#ifdef CONFIG_RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif + + + +static const struct modversion_info ____versions[] +__used __section("__versions") = { + { 0x6bc3fbc0, "__unregister_chrdev" }, + { 0xecc78457, "kobject_put" }, + { 0x73895700, "__register_chrdev" }, + { 0x122c3a7e, "_printk" }, + { 0xeb233a45, "__kmalloc" }, + { 0xfb890f0b, "class_create" }, + { 0x41b15bc9, "device_create" }, + { 0xa6ef1646, "kernel_kobj" }, + { 0x10bd90f2, "kobject_create_and_add" }, + { 0xa3efd5d1, "sysfs_create_file_ns" }, + { 0xbcab6ee6, "sscanf" }, + { 0x37a0cba, "kfree" }, + { 0xbdfb6dbb, "__fentry__" }, + { 0x5b8239ca, "__x86_return_thunk" }, + { 0xc3aaf0a9, "__put_user_1" }, + { 0x167e7f9d, "__get_user_1" }, + { 0x3c3ff9fd, "sprintf" }, + { 0xab632ed, "module_put" }, + { 0x47143bb3, "try_module_get" }, + { 0xf23bcaeb, "device_destroy" }, + { 0xfdfe3852, "class_destroy" }, + { 0x76800044, "module_layout" }, +}; + +MODULE_INFO(depends, ""); + + +MODULE_INFO(srcversion, "0407622983A4737B8D0E5C8");