Я делаю простой простой символьный драйвер, который, как предполагается, записывает на мое символьное устройство «/ dev / coffee_bean», и при чтении он должен отображать строку «Привет!» в консоли. Я читаю с устройства через «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);
2
Dr.Knowitall 13 Мар 2012 в 04:01

3 ответа

Лучший ответ

Глядя на полный код, который вы разместили сейчас, я не вижу очевидной причины сбоя. То, что вы делаете, делается в других драйверах.

Просто некоторые наблюдения.

Проверки ошибок очень мало. Это вас укусит, потому что успешное выполнение следующего обычно зависит от успешного выполнения предыдущего в качестве предварительного условия.

Кроме того, когда вы дойдете до того, что функция чтения вызывается без сбоев, вы обнаружите, что она ничего не производит, потому что вы возвращаете 0 и не перемещаете смещение! Большинство программ интерпретируют нулевой возврат как конец файла.

Вы должны соблюдать размер переданного буфера, иначе вы испортите пространство пользователя. Программа cat может не выполнять read(fd, buf, 5); (обратите внимание, что 5 меньше, чем 10 байтов, которые вы копируете в пространство пользователя), но что-то может.

Между прочим, copy_to_user и copy_from_user - это функции, которые вы также должны проверить на сбой и вернуть -EFAULT в пространство пользователя, сообщая вызывающему приложению, что оно прошло в плохой области.

Для отладки сбоя существует два традиционных подхода. Один из них - добавить больше операторов printk. В блоке кода, где нет ветвей и печать не буферизуется, если один оператор печати производит вывод до сбоя, а другой - нет, сбой происходит где-то между ними.

Другой метод заключается в интерпретации аварийного дампа: машинные регистры, байты, окружающие указатель инструкции, трассировка вызовов и т. Д. Если у вас есть эта информация о сбое, вы обычно можете точно определить место сбоя, посмотрев на машинный код и значения регистров, вы можете догадаться, что делают переменные C и структуры данных.

Удачи.

2
Kaz 13 Мар 2012 в 03:43

Что-то может пойти не так, прежде чем будет достигнута dev_read. Вы видели свое сообщение KERN_ALERT на консоли?

Очевидно, что это еще не все, что есть в вашем исходном коде, потому что модуль инициализирован, символьное устройство зарегистрировано, и есть другие функции, такие как процедура открытия. Почему вы думаете, что ошибка в dev_read только потому, что чтение с устройства приводит к сбою машины?

sizeof(my_string) равно sizeof(char *), что равно 4 или 8. Вы берете размер указателя. Если вы используете 64-битное ядро, вы получите Hi there без ! в лучшем случае, если отладите его достаточно хорошо, чтобы зайти так далеко. :)

Т.е. очевидно, что вам могут пригодиться учебники по основам C, например, о различиях между массивами и указателями.

3
Kaz 13 Мар 2012 в 00:27

Не можете сказать, просто взглянув на код. вы можете сделать себе одолжение для проверки ошибок. Во всех местах, где условия не могут быть выполнены, вы можете использовать KERN_ERR для вывода ошибок, и вы можете добавить goto OUT (где OUT: return -1), чтобы шансы на сбой будут минимальны. Это определенно может сказать вам, где это неправильно. Также сначала создайте только функцию записи и проверьте, правильно ли она работает, а затем начните создавать функцию dev_read.

1
mannukaushikece 22 Сен 2014 в 17:10