我正在做一个简单的字符驱动程序,假设要写入我的字符设备“/ dev / coffee_bean”,读取时应该显示string“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);
看看你已经发布的完整的代码,我没有看到任何明显的原因导致崩溃。 你正在做的事情是在其他司机完成的。
只是一些观察。
有很少的错误检查。 这会咬你,因为下一件事的成功执行通常取决于成功执行前一件事情的先决条件。
另外,当你确定读取函数没有任何崩溃的时候,你会发现它不会产生任何东西,因为你返回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位内核,那么在没有!
当你有足够的调试到这么远。 🙂
也就是说,显然你可能从C的基础教程中获益,就像数组和指针之间的区别。
不能通过查看代码来判断。你可以自己帮忙检查错误。在条件可能失败的地方,你可以使用KERN_ERR打印错误,你可以添加goto OUT(OUT:return -1),这样崩溃的可能性很小,这个可以肯定地告诉你错在哪里。也是先创建一个写函数,然后检查它是否工作正常,然后开始开发dev_read函数。