mmap函数

来源:互联网 发布:大数据分析工具有哪些 编辑:程序博客网 时间:2024/05/21 09:57

1、系统调用mmap函数是将一个文件或者其他对象映射进内存。

函数原型:void* mmap(void* addr,size_t length,int prot,int flags,int fd,off_t offset);

其中addr指文件应映射到进程空间的起始地址,默认NULL由内核分配;lenth指映射的文件长度,prot指文件被映射为内存后的访问权限,一般有PROT_READ(可读) , PROT_WRITE (可写), PROT_EXEC (可执行), PROT_NONE(不可访问)这几个值。flags一般由几个值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,其中,MAP_SHARED , MAP_PRIVATE必选其一。fd是文件描述符,由open函数返回。offset指文件内的偏移量,通常为0表示从头开始映射。成功时返回映射区的指针,失败返回MAP_FAILED((void *)-1)

文件被映射到进程的内存空间后,进程要访问文件就可以通过对映射区指针的操作对文件进行操作而不用调用read(),write()函数。

mmap提供了可以让用户程序访问设备内存的机制,相比用户空间和内核之间拷贝数据要高效很多。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmap。

函数:int munmap( void * addr, size_t len );可以将映射进内存的文件解除映射同时写回磁盘中

函数:int msync ( void * addr , size_t len, int flags);可以实现映射内存的文件与磁盘中的一致性


2、设备驱动的mmap实现主要是将一个物理设备的可操作区域(设备空间)映射到一个进程的虚拟地址空间。这样就可以直接采用指针的方式像访问内存的方式访问设备。在驱动中的mmap实现主要是完成一件事,就是实际物理设备的操作区域到进程虚拟空间地址的映射过程。同时也需要保证这段映射的虚拟存储器区域不会被进程当做一般的空间使用,因此需要添加一系列的保护方

<span style="font-size:18px;"></pre><pre name="code" class="cpp">/*主要是建立虚拟地址到物理地址的页表关系,其他的过程又内核自己完成*/  static int mem_mmap(struct file* filp,struct vm_area_struct *vma)  {      /*间接的控制设备*/      struct mem_dev *dev = filp->private_data;            /*标记这段虚拟内存映射为IO区域,并阻止系统将该区域包含在进程的存放转存中*/      vma->vm_flags |= VM_IO;      /*标记这段区域不能被换出*/      vma->vm_flags |= VM_RESERVED;        /**/      if(remap_pfn_range(vma,/*虚拟内存区域*/          vma->vm_start, /*虚拟地址的起始地址*/          virt_to_phys(dev->data)>>PAGE_SHIFT, /*物理存储区的物理页号*/       dev->size,    /*映射区域大小*/                  vma->vm_page_prot /*虚拟区域保护属性*/              ))          return -EAGAIN;        return 0;  }  </span>

具体的实现分析如下:

vma->vm_flags |= VM_IO;
vma->vm_flags |= VM_RESERVED;

上面的两个保护机制就说明了被映射的这段区域具有映射IO的相似性,同时保证这段区域不能随便的换出。就是建立一个物理页与虚拟页之间的关联性。具体原理是虚拟页和物理页之间是以页表的方式关联起来,虚拟内存通常大于物理内存,在使用过程中虚拟页通过页表关联一切对应的物理页,当物理页不够时,会选择性的牺牲一些页,也就是将物理页与虚拟页之间切断,重现关联其他的虚拟页,保证物理内存够用。在设备驱动中应该具体的虚拟页和物理页之间的关系应该是长期的,应该保护起来,不能随便被别的虚拟页所替换。具体也可参看关于虚拟存储器的文章。

接下来就是建立物理页与虚拟页之间的关系,即采用函数remap_pfn_range(),具体的参数如下:

int remap_pfn_range(structvm_area_struct *vma, unsigned long addr,unsigned long pfn, unsigned long size, pgprot_t prot)

1、struct vm_area_struct是一个虚拟内存区域结构体,表示虚拟存储器中的一个内存区域。其中的元素vm_start是指虚拟存储器中的起始地址。
2、addr也就是虚拟存储器中的起始地址,通常可以选择addr = vma->vm_start。
3、pfn是指物理存储器的具体页号,通常通过物理地址得到对应的物理页号,具体采用virt_to_phys(dev->data)>>PAGE_SHIFT.首先将虚拟内存转换到物理内存,然后得到页号。>>PAGE_SHIFT通常为12,这是因为每一页的大小刚好是4K,这样右移12相当于除以4096,得到页号。
4、size区域大小
5、区域保护机制。
返回值,如果成功返回0,否则正数。

0 0
原创粉丝点击