mmap函数
void *mmap(void *addr,size_t len, int prot, int flags, int fd, off_t offset)
int munmao(void *start, size_t length)
addr: 指定映射的起始地址,通常为NULL,由系统指定
len : 文件中映射到内存的长度
port:
PORT_EXEC:映射区可被执行;
PORT_READ:映射区可被读取;
PORT_WRITE:映射区可被写入;
flags:
MAP_SHARED:写入映射区的数据会复制回文件,且允许其他映射该文件的进程共享
MAP_PRIVATE:对映射区的写入操作会产生一个映射区的复制(copy-on-write),
对此区域的修改不会写回原文件。
offset:
映射文件中的偏移量

#include <stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> #include<sys/mman.h> int main() { int fd; char *start; char buf[100]; /* open the device */ fd = open("testfile",O_RDWR); start=mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); /* read the data */ strcpy(buf,start); printf("buf = %s/n",buf); /* write data */ strcpy(start,"Buf Is Not Null!"); munmap(start,100); /* unmap */ close(fd); return 0; }
虚拟内存区域
虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址范围。一个进程的内存映象由下面几部分组成:程序代码、数据、BSS和栈区域,以及内存映射的区域。
一个进程的内存区域可以通过查看:cat /proc/pid/maps 08048000-0804f000 r-xp 00000000 08:01 573748 /sbin/rpc.statd #text 0804f000-08050000 rw-p 00007000 08:01 573748 /sbin/rpc.statd #data 08050000-08055000 rwxp 00000000 00:00 0 #bss 040000000-40015000 r-xp 00000000 08:01 933965 /lib/ld2.3.2.so #text 40015000-40016000 rw-p 00014000 08:01 933965 /lib/ld-2.3.2.so #data
Linux内核使用结构vm_area_struct(<linux/mm_types.h>)来描述虚拟内存区域,其中几个主要成员如下:
1)unsigned long vm_start 虚拟内存区域起始地址
2)unsigned long vm_end 虚拟内存区域结束地址
3)unsigned long vm_flags 该区域的标记。如:VM_IO和VM_RESERVED。VM_IO将该VMA标记为内存映射的IO区域,VM_IO会阻止系统将该区域包含在进程的存放转存(core dump )中,VM_RESERVED标志内存区域不能被换出
mmap设备操作
映射一个设备是指把用户空间(虚拟地址)的一段地址关联到设备内存(物理地址)上。当程序读写这段用户空间的地址时,它实际上是在访问设备。
mmap方法是file_oprations结构的成员,在mmap系统调用发出时被调用。在此之前,内核已经完成了很多工作。mmap设备方法所需要做的就是建立虚拟地址到物理地址的页表。
int (*mmap) (struct file *, struct vm_area_struct *)
页表的建立
两种方法:
1)使用remap_pfn_range一次建立所有页表;
2)使用nopage VMA方法每次建立一个页表。
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,unsigned long pfn, unsigned long size, pgprot_t prot) vma: 虚拟内存区域指针 virt_addr: 虚拟地址的起始值 pfn: 要映射的物理地址所在的物理页帧号,可将物理地址>>PAGE_SHIFT得到。 size: 要映射的区域的大小。 prot: VMA的保护属性。
实例
int memdev_mmap(struct file*filp, struct vm_area_struct *vma) { 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, size, vma->vm_page_prot)) return -EAGAIN; return 0; }
memdev.源码
#ifndef _MEMDEV_H_ #define _MEMDEV_H_ #ifndef MEMDEV_MAJOR #define MEMDEV_MAJOR 0 /*预设的mem的主设备号*/ #endif #ifndef MEMDEV_NR_DEVS #define MEMDEV_NR_DEVS 2 /*设备数*/ #endif #ifndef MEMDEV_SIZE #define MEMDEV_SIZE 4096 #endif /*mem设备描述结构体*/ struct mem_dev { char *data; unsigned long size; }; #endif /* _MEMDEV_H_ *

浙公网安备 33010602011771号