卸载驱动报错:“Unable to handle kernel paging request at virtual address bf018000 ..........”

编写一个BMA150驱动程序,简单介绍下BMA150的特征。
BMA150是一款三轴重力加速度传感器能够感知到加速度的变化,比如晃动、跌落、上升、下降等各种移动变化都能被BMA150转化为电信号,用户直接从寄存器读取坐标即可。BMA150可以测量配置+/-2g +/-4g +/-8g范围的加速度,同时也可测量温度。BMA150提供给用户spi/i2c接口。
整个驱动程序,使用普通I/O模拟I2C协议,读取X,Y,Z加速度之。为了方便移植,特别采用了基于platform总线设计了整个驱动程序。
编写完成,通过开发板调试能正常采集数据,但是当要结束活动的时候,卸载驱动程序,坏了,一堆错误信息。

先贴出错误信息:

 

[root@xiaofeng 02_bma150]#lsmod
bma150_driver 3479 0 - Live 0xbf01a000
bma150_device 965 0 - Live 0xbf014000
s5pv210_gpio 4186 0 - Live 0xbf00d000
[root@xiaofeng 02_bma150]#rmmod bma150_device
Unable to handle kernel paging request at virtual address bf018000
pgd = df4c8000
[bf018000] *pgd=4f493011, *pte=00000000, *ppte=00000000
Internal error: Oops: 80000007 [#1] PREEMPT
last sysfs file: /sys/bus/platform/drivers/mybma150/uevent
Modules linked in: bma150_driver bma150_device(-) s5pv210_gpio g_file_storage
CPU: 0    Not tainted  (2.6.35.7 #7)
PC is at 0xbf018000
LR is at sys_delete_module+0x1e0/0x254
pc : [<bf018000>]    lr : [<c00daef0>]    psr: a0000013
sp : df4eff38  ip : df4eff08  fp : df4effa4
r10: 00000000  r9 : df4ee000  r8 : c008e1e8
r7 : df4eff3c  r6 : 00000880  r5 : bf0141c8  r4 : 00000000
r3 : bf017000  r2 : df4eff08  r1 : df4eff3c  r0 : c07f147c
Flags: NzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
Control: 10c5387d  Table: 4f4c8019  DAC: 00000015
      
LR: 0xc00dae70:
ae70  1a000018 e1a00005 ebfff21a e3500000 0a000014 e59f00cc e1a0300d e3c34d7f
ae90  eb136b11 e3c4403f e594200c e3a03002 e5823000 e1a00005 ebfff20e e2502000
aeb0  0a000001 eb136846 eafffff6 e1a0100d e3c13d7f e3c3303f e59f0088 e593300c
aed0  e5832000 eb136ddc e59f0078 eb136afe e5953114 e3530000 0a000000 e12fff33
aef0  e1a02005 e3a01002 e59f005c e3a04000 ebffc63f ebffcc10 e285100c e3a0203d
af10  e59f0048 eb06f122 e1a00005 ebfff83f ea000008 e3e04001 ea000000 e3e0400f
af30  e59f0020 eb136ae8 ea000002 e3e04000 ea000000 e3e0400d e1a00004 e24bd01c
af50  e89da8f0 c085c98c c07f147c c07f14bc c085c990 e1a0c00d e92dd800 e24cb004
    
//.................省略部分错误信息.................
     
R9: 0xdf4edf80:
df80  fffdfe7f ffffdfef ffffffff fffffaff ffffdfff ffffffdf ffffffff ffffffff
dfa0  fbffffff ffffffdf ffffffff fbffdfdf ffffffff ffffefff bfffffbf ffffffff
dfc0  fffffffe fffffafe ffffffbf ffff6fff ffffdfff feffdbef ffffbfdf bfffffdf
dfe0  ffffffff ffffffff ffdffbff ffffffff ffffff5e fffffe5f ffffffff ffffffff
e000  00000000 00000002 00000000 dfd8aa80 c07ef5c8 00000000 00000017 00000000
e020  00000000 00000000 00000000 00000000 00000000 00000000 00000000 df4effb0
e040  c008e0c8 00000000 00000000 00000000 00000000 00000000 00010000 00000000
e060  001f24a0 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Process rmmod (pid: 133, stack limit = 0xdf4ee2f0)
Stack: (0xdf4eff38 to 0xdf4f0000)
ff20:                                                       df415600 31616d62


在上面的错误信息中,除了前几行很那总结出什么有用的信息,理不出头绪。那就先看看<bma150.device.c>部分代码吧。

 

 

 

 

#include <linux/init.h> 
#include <linux/module.h>
#include <linux/kernel.h>
#include <mach/gpio.h>
#include <linux/platform_device.h>
  
#define DEMO_DEBUG
  
#ifdef  DEMO_DEBUG
    #define dem_dbg(fmt, arg...)        printk(KERN_WARNING fmt, ##arg)
#else
    #define dem_dbg(fmt, arg...)        printk(KERN_DEBUG fmt, ##arg)
#endif
  
static void  bma150_device_release(struct device *dev)
{
    dem_dbg("in BMA150_Device release\n");
}
  
static struct resource bma150_resource[]={
    // I2C2_SDA
    [0] = {
        .start = S5PV210_GPD1(4),
        .end = S5PV210_GPD1(4),
        .flags = IORESOURCE_IO
    },
    // I2C2_SCL
    [1] = {
        .start = S5PV210_GPD1(5),
        .end = S5PV210_GPD1(5),
        .flags = IORESOURCE_IO
    }
};
  
// 定义platform_device资源
static struct platform_device bma150_device = {
    .name = "mybma150",
    .resource = bma150_resource,
    .num_resources = ARRAY_SIZE(bma150_resource),
    .dev = {
        .release = bma150_device_release
    }
};
  
static int __init bma150_device_init(void)
{
    int retval = 0;
  
    // 注册platform device到platform_bus
    retval = platform_device_register(&bma150_device);
    if (retval){
        printk("platform_device_register failed\n");
        goto out;
    }
      
    return 0;
out:
    return retval;
}
  
static void __init bma150_device_exit(void)
{
    // 注销platform device
    platform_device_unregister(&bma150_device);
}
  
  
module_init(bma150_device_init);
module_exit(bma150_device_exit);
  
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("xiaofeng");


检查了多次,没有发现有什么问题,但是问题依然存在。
坚信“程序是不会骗人的”,也是历经一番波折才发现问题所在。
注意61行代码
static void __init bma150_device_exit(void)
这是驱动注销函数,但是在第一行中使用了 __init 这个初始化宏,这个才是问题根本所在,正确的是使用 __exit 。

分析问题原因:
内核使用了大量不同的宏来标记具有不同作用的函数和数据结构。如宏 __init 、__exit 等。这些宏在include/linux/init.h 头文件中定义。编译器通过这些宏可以把代码优化放到合适的内存位置,以减少内存占用和提高内核效率。
由于使用了错误初始化宏,导致注销函数被优化到的别的段上,依旧是用 rmmod 命令卸载驱动时候,内核还是去约定的内存地址上调用注销函数,必然产生错误的内存访问。

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值