利用/dev/mem和mmap读写linux内存的通用C代码及原理

#define MMAP_MEM_PAGEALIGN   (4*1024-1)
typedef struct
{
  unsigned int memAddr;
  unsigned int memSize;
  unsigned int mmapMemAddr;
  unsigned int mmapMemSize;  
  unsigned int memOffset;

  int    memDevFd;
  volatile unsigned int *pMemVirtAddr;
  
} MMapCtrl;
MMapCtrl gMMapCtrl;
int32 common_MMap(uint32_t physAddr, uint32_t memSize , uint32_t *pMemVirtAddr){
    gMMapCtrl.memDevFd = open("/dev/mem",O_RDWR|O_SYNC);
    if(gMMapCtrl.memDevFd < 0)
    {
      printf(" ERROR: /dev/mem open failed !!!\n");
      return -1;
    }

    gMMapCtrl.memOffset   = physAddr & MMAP_MEM_PAGEALIGN;

    gMMapCtrl.mmapMemAddr = physAddr - gMMapCtrl.memOffset;

    gMMapCtrl.mmapMemSize = memSize + gMMapCtrl.memOffset;

    gMMapCtrl.pMemVirtAddr = mmap(	
           (void	*)gMMapCtrl.mmapMemAddr,
           gMMapCtrl.mmapMemSize,
           PROT_READ|PROT_WRITE|PROT_EXEC,MAP_SHARED,
           gMMapCtrl.memDevFd,
           gMMapCtrl.mmapMemAddr
           );

   if (gMMapCtrl.pMemVirtAddr==NULL)
   {
     printf(" ERROR: mmap() failed !!!\n");
     return -1;
   }
    *pMemVirtAddr = (UInt32)((UInt32)gMMapCtrl.pMemVirtAddr + gMMapCtrl.memOffset);

    return 0;
}

Int32 common_unmapMem()
{
    if(gMMapCtrl.pMemVirtAddr)
      munmap((void*)gMMapCtrl.pMemVirtAddr, gMMapCtrl.mmapMemSize);
      
    if(gMMapCtrl.memDevFd >= 0)
      close(gMMapCtrl.memDevFd);
      
    return 0;
}

    linux 内核为用户提供了一个/dev/mem的驱动程序,使用户直接访问系统物理内存成为可能,上面的片段代码就是利用mmap和/dev/mem建立起直接读写系统物理内存的渠道。搞过嵌入式开发的人应该熟悉上面的代码,利用/dev/mem和mmap导出系统物理地址,免去了用户虚拟地址到内核逻辑地址的繁琐拷贝,提升效率。

1、简单介绍下dev/mem

    /dev/mem是linux下的一个字符设备,源文件是kernel/drivers/char/mem.c,有兴趣的可以下载内核源码看看,这个设备文件是专门用来读写物理地址用的。里面的内容是所有物理内存的地址以及内容信息。通常只有root用户对其有读写权限。源引网络资源对/dev/mem是这么评价的“/dev/mem是个好玩的东西,你竟然可以直接访问物理内存,这在linux下简直太神奇了,就想一个小偷想偷银行,可是发现银行戒备森严,正在小偷苦无对策的时候,突然发现银行有个后门,而且这个后门直通银行的金库。”

2、mmap驱动实现时注意事项

    曾经在写某板卡的pcie驱动时,需要mmap出映射到pcie总线地址的对应的物理内存地址,代码就不贴了,说下出的问题。在驱动加载上后,调用mmap出现了下面的错误,具体什么原因还是没搞清楚,没时间仔细研究了,工作不等人啊。

dspc868x_pcie_ep 0000:04:00.0: vma->vm_start: 0x4024a000
dspc868x_pcie_ep 0000:04:00.0: vma->vm_end: 0x4024b000
dspc868x_pcie_ep 0000:04:00.0: vma->vm_pgoff: 0x20000
dspc868x_pcie_ep 0000:04:00.0: Mapping 0x1000 bytes from address 0x20000000 success

Unhandled fault: Precise External Abort on non-linefetch (0x1018) at 0x4024a000

参考了别人写的其他设备驱动程序,在我的驱动实现mmap代码中添加如下的选项,禁止高速缓存选项,上面的错误就解决了。有对这部分特别熟悉的欢迎与我交流,指导下,谢谢。
vma->vm_flags |= VM_WRITE; 
vma->vm_flags |= VM_RESERVED; 
vma->vm_page_prot = (__pgprot(pgprot_val(pgprot_noncached(vma->vm_page_prot)) | (L_PTE_WRITE|L_PTE_DIRTY))); 




 






  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值