简单的字符驱动崩溃

时间:2012-03-13 00:01:17

标签: c linux kernel driver device

我正在创建一个简单的字符驱动程序,假设要写入我的char设备“/ dev / coffee_bean”,当读取时,它应显示字符串“Hi There!”在控制台中。我通过“cat / dev / coffee_bean”从设备读取,而我的系统崩溃并重置。贝娄是我的源代码。谢谢你的帮助。

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/semaphore.h>
MODULE_LICENSE("Dual BSD/GPL");

#define DEVICE_NAME "coffee_grinds"
#define COUNT 4
#define FIRST_MINOR 0
#define CONST_QUANTUM 4000
#define CONST_QSET 4000

int test;

module_param(test, int, S_IRUGO);

struct my_char_structure{
    struct cdev my_cdev;
    struct semaphore sem;
    unsigned int access_key;
    unsigned long size;
};

static dev_t dev_num;

int dev_open(struct inode *in_node, struct file *filp){
    struct my_char_structure *my_dev;

    my_dev = container_of(in_node->i_cdev, struct my_char_structure, my_cdev);
    filp->private_data = my_dev;
    return 0;
}

int dev_release(struct inode *inode, struct file *filp){
    return 0;
}

ssize_t dev_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){
    struct my_char_structure *my_dev = filp->private_data;
    ssize_t retval = -ENOMEM; /* value used in "goto out" statements */
    char *my_string;
    int counting;
    printk(KERN_ALERT "Write was accessed, Lol");
    if (down_interruptible(&my_dev->sem))
        return -ERESTARTSYS;
    my_string = kmalloc(count,GFP_KERNEL);
    counting = copy_from_user(my_string,buff,count);
    printk(KERN_ALERT "You wrote %s",my_string);
    kfree(my_string);
    up(&my_dev->sem);

    printk(KERN_ALERT "We wrote %d bytes",counting);
        return retval;
    // Here is some experimental code
}

    ssize_t dev_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){
        struct my_char_structure *my_dev = filp->private_data;
        ssize_t retval = 0;
        char *my_string;

        printk(KERN_ALERT "Read was accessed Lol");

        if (down_interruptible(&my_dev->sem))
            return -ERESTARTSYS;
        my_string = "Hi there!";
        copy_to_user(buff,my_string,10);
        up(&my_dev->sem);
        return retval;

    }

struct file_operations fops = {
    .owner  = THIS_MODULE,
    .read   = dev_read,
    .write  = dev_write,
    .open   = dev_open,
    .release= dev_release,
};

int start_mod(void){
    //Because we are dealing with a fictitious device, I want
    //the driver to create my two devices with arbitrarly 
    //assigned major numbers.
    static struct my_char_structure Dev;
    static struct my_char_structure *my_dev = &Dev;
    int err;

    alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME);

    sema_init(&(my_dev->sem),1);

    cdev_init(&(my_dev->my_cdev), &fops);
    my_dev->my_cdev.owner = THIS_MODULE;
    my_dev->my_cdev.ops = &fops;// fops is my file operations struct

    err = cdev_add(&my_dev->my_cdev, dev_num, COUNT);
    if(err)
        printk(KERN_ALERT "There was an error %d.",err);
    printk(KERN_ALERT " insmod to major number %d",MAJOR(dev_num));

    return 0;   
}

void end_mod(void){

    unregister_chrdev_region(dev_num, COUNT);

}

module_init(start_mod);
module_exit(end_mod);

3 个答案:

答案 0 :(得分:3)

在达到dev_read之前,事情可能会出错。您是否在控制台上看到了KERN_ALERT消息?

显然,并非所有源代码都存在,因为模块已初始化,字符设备已注册,并且还有其他功能,如打开例程。是什么让你认为这个错误出现在dev_read只是因为从设备上读取会导致机器崩溃?

sizeof(my_string)sizeof(char *),即4或8.您正在使用指针的大小。如果您使用的是64位内核,那么当您已经调试好到足够远的时候,最多只能获得Hi there ! {{1}}。 :)

即。很明显,您可能会受益于C基础知识中的教程,例如数组和指针之间的差异。

答案 1 :(得分:2)

查看您现在发布的完整代码,我没有看到任何明显的崩溃原因。你正在做的事情是在其他驱动程序中完成的。

只是一些观察。

检查错误很少。这会咬你,因为下一件事的成功执行通常取决于成功执行前一件事作为前提条件。

此外,当你确实调到read函数而没有任何崩溃时,你会发现它没有产生任何东西,因为你返回0并且不移动偏移量!大多数程序会将零回报解释为文件结尾。

您必须遵守传入的缓冲区大小,否则会损坏用户空间。 cat程序可能不会执行read(fd, buf, 5);(请注意,5小于您要复制到用户空间的10个字节),但可能会有一些。

顺便说一句,copy_to_usercopy_from_user是您必须测试失败的函数,并将-EFAULT返回给用户空间,告诉调用它在坏区域中传递的应用程序。 / p>

要调试崩溃,有两种传统方法。一种是添加更多的printk语句。在没有分支的代码块中,并且没有缓冲打印,如果一个print语句在崩溃之前产生输出而另一个没有,则崩溃就在它们之间。

另一种技术是解释崩溃转储:机器寄存器,指令指针周围的字节,调用跟踪等。如果您从崩溃中获得了该信息,您通常可以查明崩溃的位置并查看机器代码和寄存器的值,你可以猜出C变量和数据结构正在做什么。

祝你好运。

答案 2 :(得分:1)

无法通过查看代码来判断。你可以自己帮忙检查错误。在条件ca失败的所有地方你可以使用KERN_ERR打印错误,你可以添加转到OUT(其中OUT:返回-1)因此,崩溃的可能性很小。这绝对可以告诉你哪里出错了。首先只创建写入函数并检查它是否正常工作然后开始创建dev_read函数。