diff options
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | debug.c | 22 | ||||
-rw-r--r-- | debug.h | 8 | ||||
-rwxr-xr-x | hello_load.sh (renamed from load.sh) | 2 | ||||
-rw-r--r-- | main.c | 149 | ||||
-rw-r--r-- | main.h | 28 |
6 files changed, 181 insertions, 39 deletions
@@ -1,4 +1,7 @@ -#ccflags-y += -g +# causes weird file size, smaller than stripped? +ifeq ($(DEBUG),) + ccflags-y += -g +endif # Makfile assignments: # := value at right is expanded and assigned at declaration time @@ -13,11 +16,13 @@ hello-y += main.o debug.o # .ko module to be created obj-m := hello.o +KERNELDIR ?= /lib/modules/$(shell uname -r)/build + # '-C' changes the dir # '-M' causes the the kernel's toplevel Makefile to move back into this dir # before trying to build 'modules' target all: - make -C /lib/modules/$(shell uname -r)/build KCPPFLAGS="-I$(CURDIR)" M=$(PWD) modules + make -C $(KERNELDIR) KCPPFLAGS="-I$(CURDIR)" M=$(PWD) modules clean: - make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean + make -C $(KERNELDIR) M=$(PWD) clean @@ -10,6 +10,8 @@ #include <linux/types.h> #include <linux/errno.h> +#include <linux/uaccess.h> + #include <debug.h> #include <main.h> @@ -24,7 +26,7 @@ char kernel_buff[BUFF_LEN] = {'f','o','o','b','a','r','\0'}; int fileprv = 1; /* hmm */ /* struct file, an abstract open file, not on disk, which would be a an inode */ -static ssize_t debugfs_read(struct file *fp, char __user /* userspace */ *ubuff, size_t c, loff_t *pos) +static ssize_t hello_hello_debugfs_read(struct file *fp, char __user /* userspace */ *ubuff, size_t c, loff_t *pos) { /** * simple_read_from_buffer - copy data from the buffer to user space @@ -43,7 +45,7 @@ static ssize_t debugfs_read(struct file *fp, char __user /* userspace */ *ubuff, return simple_read_from_buffer(ubuff, c, pos, kernel_buff, BUFF_LEN); } -static ssize_t debugfs_write(struct file *fp, const char __user *ubuff, size_t c, loff_t *pos) +static ssize_t hello_debugfs_write(struct file *fp, const char __user *ubuff, size_t c, loff_t *pos) { /** * simple_write_to_buffer - copy data from user space to the buffer @@ -64,14 +66,20 @@ static ssize_t debugfs_write(struct file *fp, const char __user *ubuff, size_t c return (-EINVAL); return simple_write_to_buffer(kernel_buff, BUFF_LEN, pos, ubuff, c); + +#if 0 + printk(KERN_INFO "count %lu, offset %u", c, *pos); + copy_from_user(kernel_buff + *pos, ubuff, c); + return c; +#endif } -int debug_init(struct dentry **dir, struct dentry **file) +int hello_debugfs_init(struct dentry **dir, struct dentry **file) { /* func ptrs that perform various operations on the device, in this case char device, well not even */ struct file_operations fops = { - .read = debugfs_read, - .write = debugfs_write + .read = hello_hello_debugfs_read, + .write = hello_debugfs_write }; /* omitted fields are initialized to NULL */ @@ -82,12 +90,12 @@ int debug_init(struct dentry **dir, struct dentry **file) /* regular file, read by user/group/other, write by user */ *file = debugfs_create_file("magic", S_IFREG | S_IRUGO | S_IWUSR, *dir, &fileprv, &fops); if (!*file) - printk("debugfs: error creating file\n"); + printk(KERN_WARNING "[hello] debugfs: error creating file\n"); return 0; } -int debug_destroy(struct dentry *dir, struct dentry *file) +int hello_debugfs_destroy(struct dentry *dir, struct dentry *file) { if (file) debugfs_remove(file); @@ -1,10 +1,10 @@ -#ifndef _DEBUG_H_ -#define _DEBUG_H_ +#ifndef _HELLODEBUG_H_ +#define _HELLODEBUG_H_ struct dentry; -int debug_init(struct dentry **, struct dentry **); -int debug_destroy(struct dentry *, struct dentry *); +int hello_debugfs_init(struct dentry **, struct dentry **); +int hello_debugfs_destroy(struct dentry *, struct dentry *); #endif @@ -1,7 +1,7 @@ #!/bin/bash MODULE=hello -DEVICE=skull +DEVICE=helloc MODE=664 # invoke insmod with all arguments and use a pathname @@ -3,48 +3,155 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> -/* used for kmalloc */ -#include <linux/slab.h> +#include <linux/slab.h> /* used for kmalloc */ #include <linux/fs.h> +#include <linux/cdev.h> +#include <asm/uaccess.h> /* copy_*_user */ +#include <main.h> #include <debug.h> -char *debugmsg = "Tesla coil is a hi freq transformer"; -struct dentry *debug_dir = NULL; -struct dentry *debug_file = NULL; +/* major and minor numbers for character device under /dev/ */ +int hello_major = HELLO_MAJOR; +int hello_minor = 0; -dev_t devnum; +char *magicstr = "Tesla coil is a hi freq transformer"; +char *hellomsg = "photon is the energy carrier particle for EM waves within light spectrum"; +struct dentry *debugfs_dir = NULL; +struct dentry *debugfs_file = NULL; + +struct hello_dev *hello_device; + +static int hello_create_debugfs(void) +{ + int ret = 0; + + /* modifies passed in ptrs */ + ret = hello_debugfs_init(&debugfs_dir, &debugfs_file); + if (ret) + printk(KERN_WARNING "[hello] debugfs might not have been mounted\n"); + + return ret; +} + +static ssize_t hello_read(struct file *filp, char __user *buff, size_t count, loff_t *f_pos) +{ + struct hello_dev *dev = filp->private_data; + + if (*f_pos + count > HELLO_KERNEL_BUFF_LEN) + count = HELLO_KERNEL_BUFF_LEN - *f_pos; + + if (count > 0) + { + copy_to_user(buff, dev->hello_buffer + *f_pos, count); + *f_pos += count; /* yes we have to keep track */ + return count; + } + + return 0; /* end of file, also in case of out of bound */ +} + +static ssize_t hello_write(struct file *filp, const char __user *buff, size_t count, loff_t *f_pos) +{ + struct hello_dev *dev = filp->private_data; + +#if 0 + /* we will truncate hello_buffer */ + copy_from_user(dev->hello_buffer + *f_pos, buff, count); + return count; +#endif + + return 0; +} + +/* there's a count in filp that gets incremented every time our char device gets opened, but note that + * this function does not get called multiple times, instead copies are made, think fork(), or just simple ptr? + */ +static int hello_open(struct inode *inode, struct file *filp) +{ + struct hello_dev *dev; + dev = container_of(inode->i_cdev, struct hello_dev, cdev); + filp->private_data = dev; /* our only chance to do that is here in open(), place to save our dev struct */ + + return 0; +} + +static int hello_release(struct inode *inode, struct file *filp) +{ + return 0; +} + +struct file_operations hello_fops = { + .owner = THIS_MODULE, + .read = hello_read, + .write = hello_write, + .open = hello_open, + .release = hello_release +}; /* __init is a hint that the func is only used at initialization time, then module * loader drops the function after module is loaded making its memory available for other uses */ static int __init hello_init(void) { - int err = 0; - char *msg = (char *) kmalloc_array(128, sizeof(char), GFP_KERNEL /* kernel ram */); + int ret = 0; + dev_t devnum = 0; + char *hellomsg_copy = NULL; - printk("module named hello inserted\n"); - strcpy(msg, "photon is the energy carrier particle for EM waves within light spectrum"); - printk("%s\n", msg); - kfree(msg); + printk("[hello] module inserted\n"); /* little hello msg below */ + hellomsg_copy = (char *) kmalloc_array(128, sizeof(char), GFP_KERNEL /* kernel ram */); + strcpy(hellomsg_copy, hellomsg); + printk(KERN_INFO "%s\n", hellomsg_copy); + kfree(hellomsg_copy); /* device numbers, major will be picked for us */ - err = alloc_chrdev_region(&devnum, 0 /* first minor */, 1, "skull"); - printk("major: %d, minor: %d\n", MAJOR(devnum), MINOR(devnum)); + if (hello_major) { + devnum = MKDEV(hello_major, hello_minor); + ret = register_chrdev_region(devnum, 1, "helloc"); /* last param name will be reflected in /proc/devices */ + } else { + ret = alloc_chrdev_region(&devnum, 0 /* first minor */, 1, "helloc"); + hello_major = MAJOR(devnum); + hello_minor = MINOR(devnum); + printk(KERN_INFO "[hello] major: %d, minor: %d\n", hello_major, hello_minor); + } + if (ret < 0) { + printk(KERN_WARNING "[hello] can't get the major %d number\n", hello_major); + return ret; + } - /* modifies passed in ptrs */ - err = debug_init(&debug_dir, &debug_file); - if (err) - printk("debugfs might not have been mounted\n"); + /* allocate hello device and set it up */ + hello_device = kmalloc(sizeof(struct hello_dev), GFP_KERNEL); + if (!hello_device) { + ret = -ENOMEM; + goto fail; + } + memset(hello_device, 0, sizeof(struct hello_dev)); + hello_device->devnum = devnum; + strcpy(hello_device->hello_buffer, "write to me\n"); + + /* setup char_dev structure */ + cdev_init(&hello_device->cdev, &hello_fops); + hello_device->cdev.owner = THIS_MODULE; + if ((ret = cdev_add(&hello_device->cdev, devnum, 1)) < 0) + { + printk(KERN_WARNING "[hello] failed to add char device\n"); + goto fail; + } + + hello_create_debugfs(); return 0; + + fail: + unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1); + return ret; } static void __exit hello_exit(void) { - unregister_chrdev_region(devnum, 1); - debug_destroy(debug_dir, debug_file); - printk("module named hello removed\n"); + unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1); + hello_debugfs_destroy(debugfs_dir, debugfs_file); + printk(KERN_INFO "[hello] module removed\n"); } module_init(hello_init); @@ -1,7 +1,29 @@ -#ifndef _MAIN_H_ -#define _MAIN_H_ +#ifndef _HELLOMAIN_H_ +#define _HELLOMAIN_H_ -extern char *debugmsg; +#include <linux/cdev.h> + +#ifndef HELLO_MAJOR +#define HELLO_MAJOR 0 /* let kernel choose, unless user really defined it */ +#endif + +#define HELLO_KERNEL_BUFF_LEN 1024 + +extern int hello_major; +extern int hello_minor; + +extern char *magicstr; + +struct hello_dev { + dev_t devnum; + struct cdev cdev; /* char device */ + /* for r/w operations */ + char hello_buffer[HELLO_KERNEL_BUFF_LEN]; + size_t buff_index; +}; + +/* function prototypes */ +int hello_debugfs(void); #endif |