zoukankan      html  css  js  c++  java
  • 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
    ");
    13         key_dev->event.code  = KEY_ENTER;
    14         key_dev->event.value = 0;
    15     }else{
    16         printk("key3 down
    ");
    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
    ");
    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

  • 相关阅读:
    AI CV 会议2018
    ubuntu 更改默认亮度
    ubuntu安装latex
    过滤文件代码 python
    ubuntu安装pycharm桌面快捷方式
    Ubuntu 14.04 鼠标消失解决方案
    ffmpeg常用命令
    FFMPEG 在ubuntu下的安装与使用
    pragma once
    chrono--高精度计时
  • 原文地址:https://www.cnblogs.com/y4247464/p/12384454.html
Copyright © 2011-2022 走看看