• 内核模块 ioremap Segmentation fault 问题


    1.问题发现

    我学习内核驱动编程,练习最简单的led驱动。看教程的写法是,参考至https://blog.csdn.net/zqixiao_09/article/details/50850708

    以下为伪代码:

    #define  GPX2CON    0x11000c40  
    #define  GPX2DAT    0x11000c44  
    #define  GPX1CON    0x11000c20  
    #define  GPX1DAT    0x11000c24  
    #define  GPF3CON    0x114001e0  
    #define  GPF3DAT    0x114001e4  
      
    static int *pgpx2con  ;  
    static int *pgpx2dat;  
      
    static int *pgpx1con  ;  
    static int *pgpx1dat;  
      
    static int *pgpf3con  ;  
    static int *pgpf3dat;  
    
    /*****************************************/
        pgpx2con = ioremap(GPX2CON,4);  
        pgpx2dat = ioremap(GPX2DAT,4);  
      
        pgpx1con = ioremap(GPX1CON,4);  
        pgpx1dat =ioremap(GPX1DAT,4);  
      
        pgpf3con  = ioremap(GPF3CON,4);  
        pgpf3dat =ioremap(GPF3DAT,4);  
      
        writel((readl(pgpx2con)& ~(0xf<<28)) |(0x1<<28),pgpx2con) ;  
        writel((readl(pgpx1con)& ~(0xf<<0)) |(0x1<<0),pgpx1con) ;     
        writel((readl(pgpf3con)& ~(0xff<<16)) |(0x11<<16),pgpf3con) ;    

    以下是我模仿他写的内核模块:

    led.c:

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/io.h>
    
    
    #define PB_CFG 0x01c20824 //PB口控制寄存器
    #define PB_DAT 0x01c20834 //PB口数据寄存器
    
     uint8_t *PBcfg;
     uint8_t *PBdat;
    static int __init myled_init(void)
    {
    
        PBcfg = ioremap(PB_CFG, 4); //映射到物理地址
        PBdat = ioremap(PB_DAT, 4);
    
        //配置io口为输出模式   //先左移12位取反得 FFFF0FFF 相与 再或上 0x1<<12  ioread32就是调用readl
        iowrite32((ioread32(PBcfg) & ~(7 << 16)) | (1 << 16), PBcfg); //PB4 设定out
        iowrite32((ioread32(PBcfg) & ~(7 << 20)) | (1 << 20), PBcfg); //PB5 设定out
        
        iowrite32(ioread32(PB_DAT) &(~(1<<4)),PBdat);//置低开灯
        iowrite32(ioread32(PB_DAT) &(~(1<<5)),PBdat);//置低开灯
    
        printk("myled_init ...
    ");
        return 0;
    }
    
    static void __exit myled_exit(void)
    {
        iowrite32(ioread32(PB_DAT) | (1<<4),PBdat);//置高关灯
        iowrite32(ioread32(PB_DAT) | (1<<5),PBdat);//置高关灯
        iounmap(PBdat);
        iounmap(PBcfg);
        printk("myled_exit ...
    ");
    }
    
    module_init(myled_init);
    module_exit(myled_exit);
    
    MODULE_LICENSE("GPL");

    具体思路是:

    将两个外设地址,分别映射到不同的内存,并将内存地址赋值给Pbdat,Pbcfg。 然后再对两个地址进行读写操作。

    但是这个模块只要运行就会出现:

    #insmod led.ko
    Segmentation fault

    2.问题解决

    我换了一种写法,如下:

    ledq.c

    #include <linux/init.h>
    #include <linux/module.h>
    #include <linux/io.h>
    
    // status-led 接在PG15
    
    #define BADDR 0x01c20800
    #define PB_CFG1_OFF 0x24 //PG组IO口的功能配置寄存器1对基地址偏移为0XDC
    #define PB_DATA_OFF 0x34 //PG组IO口的数据寄存器对基地址偏移为0xE8
    
    //static volatile unsigned long *vaddr; //不可用
    //int *vaddr; // 不可用
    //unsigned int *vaddr;//不可用
    
    unsigned char *vaddr;//可用
    
    static int __init myled_init(void)
    {
        vaddr = ioremap(BADDR, SZ_4K);//映射到物理地址
        //printk(KERN_INFO "vaddr=%ld",*vaddr);
        //配置io口为输出模式   //先左移16位取反得 FFFF0FFF 相与 再或上 0x1<<16  ioread32就是调用readl
        iowrite32((ioread32(vaddr + PB_CFG1_OFF) & ~(7 << 16)) | (1 << 16), vaddr + PB_CFG1_OFF); //PB4 设定out
        iowrite32((ioread32(vaddr + PB_CFG1_OFF) & ~(7 << 20)) | (1 << 20), vaddr + PB_CFG1_OFF); //PB5 设定out
    
        iowrite32(ioread32(vaddr + PB_DATA_OFF) & (~(1 << 4)), vaddr + PB_DATA_OFF); //置低开灯
        iowrite32(ioread32(vaddr + PB_DATA_OFF) & (~(1 << 5)), vaddr + PB_DATA_OFF); //置低开灯
    
        printk(KERN_INFO "myled_init ...
    ");
        return 0;
    }
    
    static void __exit myled_exit(void)
    {
        printk(KERN_INFO "myled_exit ...
    ");
        iowrite32(ioread32(vaddr + PB_DATA_OFF) | (1 << 4), vaddr + PB_DATA_OFF); //置高关灯
        iowrite32(ioread32(vaddr + PB_DATA_OFF) | (1 << 5), vaddr + PB_DATA_OFF); //置高关灯
        // iowrite32(ioread32(PB_DAT) | (0x1<<5),PBdat);
        iounmap(vaddr);
    }
    
    module_init(myled_init);
    module_exit(myled_exit);
    
    MODULE_LICENSE("GPL");

    具体思路:

    直接将大片物理地址映射到内存中,然后根据地址偏移量寻找地址并且对其进行操作。

  • 相关阅读:
    218. The Skyline Problem (LeetCode)
    并发编程-读书笔记
    Lock Free (无锁并发)
    最近公共祖先 LCA 递归非递归
    Node.js 开发指南-读书笔记
    [paper reading] C-MIL: Continuation Multiple Instance Learning for Weakly Supervised Object Detection CVPR2019
    开发者必备,超实用的PHP代码片段!
    二级菜单联动效果
    页面js框架
    我的java mvc
  • 原文地址:https://www.cnblogs.com/ZQQH/p/8631749.html
Copyright © 2020-2023  润新知