Я делаю простой простой символьный драйвер, который, как предполагается, записывает на мое символьное устройство «/ 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);
3 ответа
Глядя на полный код, который вы разместили сейчас, я не вижу очевидной причины сбоя. То, что вы делаете, делается в других драйверах.
Просто некоторые наблюдения.
Проверки ошибок очень мало. Это вас укусит, потому что успешное выполнение следующего обычно зависит от успешного выполнения предыдущего в качестве предварительного условия.
Кроме того, когда вы дойдете до того, что функция чтения вызывается без сбоев, вы обнаружите, что она ничего не производит, потому что вы возвращаете 0
и не перемещаете смещение! Большинство программ интерпретируют нулевой возврат как конец файла.
Вы должны соблюдать размер переданного буфера, иначе вы испортите пространство пользователя. Программа cat
может не выполнять read(fd, buf, 5);
(обратите внимание, что 5 меньше, чем 10 байтов, которые вы копируете в пространство пользователя), но что-то может.
Между прочим, copy_to_user
и copy_from_user
- это функции, которые вы также должны проверить на сбой и вернуть -EFAULT
в пространство пользователя, сообщая вызывающему приложению, что оно прошло в плохой области.
Для отладки сбоя существует два традиционных подхода. Один из них - добавить больше операторов printk. В блоке кода, где нет ветвей и печать не буферизуется, если один оператор печати производит вывод до сбоя, а другой - нет, сбой происходит где-то между ними.
Другой метод заключается в интерпретации аварийного дампа: машинные регистры, байты, окружающие указатель инструкции, трассировка вызовов и т. Д. Если у вас есть эта информация о сбое, вы обычно можете точно определить место сбоя, посмотрев на машинный код и значения регистров, вы можете догадаться, что делают переменные C и структуры данных.
Удачи.
Что-то может пойти не так, прежде чем будет достигнута dev_read
. Вы видели свое сообщение KERN_ALERT
на консоли?
Очевидно, что это еще не все, что есть в вашем исходном коде, потому что модуль инициализирован, символьное устройство зарегистрировано, и есть другие функции, такие как процедура открытия. Почему вы думаете, что ошибка в dev_read
только потому, что чтение с устройства приводит к сбою машины?
sizeof(my_string)
равно sizeof(char *)
, что равно 4 или 8. Вы берете размер указателя. Если вы используете 64-битное ядро, вы получите Hi there
без !
в лучшем случае, если отладите его достаточно хорошо, чтобы зайти так далеко. :)
Т.е. очевидно, что вам могут пригодиться учебники по основам C, например, о различиях между массивами и указателями.
Не можете сказать, просто взглянув на код. вы можете сделать себе одолжение для проверки ошибок. Во всех местах, где условия не могут быть выполнены, вы можете использовать KERN_ERR для вывода ошибок, и вы можете добавить goto OUT (где OUT: return -1), чтобы шансы на сбой будут минимальны. Это определенно может сказать вам, где это неправильно. Также сначала создайте только функцию записи и проверьте, правильно ли она работает, а затем начните создавать функцию dev_read.
Похожие вопросы
Новые вопросы
c
C - это язык программирования общего назначения, используемый для системного программирования (ОС и встраиваемых), библиотек, игр и кроссплатформенности. Этот тег следует использовать с общими вопросами, касающимися языка C, как это определено в стандарте ISO 9899 (последняя версия 9899: 2018, если не указано иное, а также для запросов, специфичных для версии, с c89, c99, c11 и т. Д.). C отличается от C ++ и не должен сочетаться с тэгом C ++ без разумной причины.