mmap设备操作

mmap系统调用如下:

void* mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

addr:指定映射的起始地址,通常设置为NULL,由系统指定;

length:映射到内存的文件长度;

prot:映射区的保护方式,可以是PROT_EXEC,PROT_READ,PROT_WRITE;

flags:映射区的特性,可以是MAP_SHARED,MAP_PRIVATE;

fd:由open返回的文件描述符,表示要映射的文件;

offset:文件开始处的偏移量,必须是分页大小的整数倍,通常为0,表示从文件头开始映射;

内存映射函数mmap:负责把文件内容映射到进程的虚拟地址空间中,映射之后,通过对这段内存的读取和修改,来实现对文件的读取和修改,而不需要再调用read,write等函数。

(文件在open之后直接mmap映射,然后用指针操作即可)

 

munmap系统调用如下:

int munmap(void *start,size_t length);

取消参数start所指向的映射内存,参数length表示欲取消映射的内存的大小;

(close之前要先调用munmap解除映射)

 

代码实例:

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <string.h>

#include <sys/mman.h>

 

int main(int argc, char** argv)

{

        int fd = 0;

        char *start =NULL;

        charbuffer[100] = {0};

 

        fd =open("testfile", O_RDWR);

 

        start =mmap(NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

 

        strcpy(buffer,start);

       printf("buffer = %s\n", buffer);

 

        strcpy(start,"now buffer is not null!");

 

        munmap(start,100);

 

        close(fd);

 

        return 0;

}

执行结果:

mmap设备操作_第1张图片

(mmap系统调用不会影响原来文件的长度)


虚拟内存区域

虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址范围。

一个进程的内存映像由下面几部分组成:程序代码,数据,BSS,栈区域,以及内存映射的区域。

(每个进程都有自己独立的虚拟地址空间)

进程的虚拟内存区域可以通过/proc/pid/maps查看:

mmap设备操作_第2张图片

每一行的域为:

start-end perm offset major:minor inode

start:该区域的起始虚拟地址;

end:该区域的结束虚拟地址;

perm:读写和执行权限,表示对这个区域,允许进程做什么,这个域的最后一个字符要么是p表示私有的,要么是s表示共享的;

offset:被映射部分在文件中的起始地址;

major、minor:主次设备号;

inode:索引节点;

 

Linux内核中,使用结构vm_area_struct(<linux/mm_types.h>)来描述虚拟内存区域:

 struct vm_area_struct
{
struct mm_struct * vm_mm;/* The address space we belong to. */
unsigned long vm_start;/* Our start address within vm_mm. */
unsigned long vm_end;/* The first byte after our end address within vm_mm. */

/* linked list of VM areas per task, sorted by address */
struct vm_area_struct *vm_next;

pgprot_t vm_page_prot;/* Access permissions of this VMA. */
unsigned long vm_flags;/* Flags, see mm.h. */

...

};


映射一个设备是指把用户空间的一段地址关联到设备内存(设备的物理地址)上,用户空间的地址会由系统提供,设备内存的地址通过查询可以获得,因此我们只需要关心“物理地址与虚拟地址如何关联”?

建立虚拟地址到物理地址的页表。

那么又是“如何建立页表”?

方法有两种:

1、 使用remap_pfn_range一次建立所有页表;

2、 使用nopageVMA方法每次建立一个页表;

 

int remap_pfn_range(struct vm_area_struct *vma, unsigned longaddr,

                  unsigned long pfn, unsigned long size,pgprot_t prot)

remap_pfn_range - remap kernel memory to userspace;

vma: user vma to map to,虚拟内存区域指针;

addr: target user address to start at,虚拟地址的起始值;

pfn: physical address of kernel memory,要映射的物理地址所在的物理页帧号,可将物理地址>>PAGE_SHIFT得到;

size: size of map area,要映射的区域的大小;

prot: page protection flags for this mapping,VMA的保护属性;



你可能感兴趣的:(mmap设备操作)