Debag —— 使用空指针,导致内核非法地址访问出错

实现按键驱动,板上加载驱动出错,Oops信息如下:

 

 可知,是因为使用了空指针,导致内核访问了非法地址,在源码中去看一下:

 1 ...
 2 //按键中断的处理函数
 3 irqreturn_t key_irq_handler(int irqno, void *devid)
 4 {
 5     printk("----------%s---------",__FUNCTION__);
 6 
 7     int value;
 8     //读取按键状态
 9     value = readl(key_dev->reg_base + 4) & (0x01<<2);
10     
11     if(value){
12         printk("key3 up\n");
13         key_dev->event.code  = KEY_ENTER;
14         key_dev->event.value = 0;
15     }else{
16         printk("key3 down\n");
17         key_dev->event.code  = KEY_ENTER;
18         key_dev->event.value = 1;
19     }
20     return IRQ_HANDLED;
21 }
22 
23 ...
24 
25 //驱动初始化函数
26 static int __init key_drv_init(void)
27 {
28     //获取到中断号
29     int ret;
30 
31     //1、设定全局设备对象并分配空间
32     key_dev = kzalloc(sizeof(struct key_desc), GFP_KERNEL);  //GFP_KERNEL表正常分配内存
33                           //kzalloc相比于kmalloc,不仅分配连续空间,还会将内存初始化清零
34 
35     //2、动态申请设备号
36     key_dev->dev_major = register_chrdev(0, "key_drv", &key_fops);
37 
38     //3、创建设备节点文件
39     key_dev->cls = class_create(THIS_MODULE, "key_cls");
40     key_dev->dev = device_create(key_dev->cls, NULL, MKDEV(key_dev->dev_major, 0), NULL, "key0");
41 
42     //4、硬件初始化 -- 地址映射或中断申请
43     key_dev->irqno = get_irqno_from_node();
44 
45     ret = request_irq(key_dev->irqno, key_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 
46         "key3_eint10", NULL);
47     if(ret != 0)
48     {
49         printk("request_irq error\n");
50         return ret;
51     }
52 
53     //a. 硬件如何获取数据
54     key_dev->reg_base = ioremap(GPXCON_REG,8);
55     
56     
57     return 0;
58 }
59 ...

  跟踪一下代码,会发现是在初始化函数中出错,在request_irq函数中,看参数设置是否正确,参数1:中断号,参数2:发生中断时,调用的回调函数,参数3:中断触发类型,参数4/5,分别是const char *name, 和void *dev,name通常为设备驱动名字,dev为void*指针,作为参数传递给回调函数,为dev_id中断名称,作为共享中断时的中断区别参数,这里我们设置为NULL。

参数设置基本上没问题,再看一下信息,报错信息说无法对虚拟地址0x00000004进行解引用即读值,进入key_irq_handler, 在读寄存器的函数readl中,对虚拟地址基地址进行偏移后在读出值进行与&操作,为什么报错信息说这个虚拟地址基地址为0,那就是说并没有地址映射成功,基地址是空的。返回初始化函数,看看ioremap函数,发现ioremap在request_irq函数之后,所以基地址没有与物理地址进行映射,将ioremap放到request_irq之前即可。

对注册中断服务函数的详细解析见:https://blog.csdn.net/wealoong/article/details/7566546

对Oops信息调试详解的文章见:https://blog.csdn.net/kangear/article/details/8217329

posted @ 2020-02-29 18:08  朱果果  阅读(568)  评论(0编辑  收藏  举报