mmap设备方法笔记
2011-10-03 22:17
190 查看
mmap系统调用(功能)
void * mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)参数:
addr | 指定映射的起始地址(通常不指定)通常为NULL,由系统指定 |
length | 映射到内存的文件长度 |
prot | 映射区的保护方式: PROT_EXEC:映射区可被执行 PROT_READ:映射区可被读取 PROTWRITE:映射区可被写入 |
flags | 映射区的特性: MAP_SHARED:写入映射区的内容最后要写入文件 MAP_PRIVATE:最后不会写入文件 |
fd | 由open返回的文件描述符,代表要映射的文件 |
offset | 以文件开始处的偏移量,必须是分布大小的整数倍,通常为0,表示从文件头开始映射 |
返回 | 会返回起始地址,本来mmap是指向内存地址的指针 |
图中 左边的是进程的虚拟空间,右边的是文件。
解除映射
函数原型:int munmap(void *start, size_t length)
功能:取消参数start所指向的映射内存,参数length表示要取消的内存大小
返回值:解除成功返回0,否则返回-1,错误原因存于errno中。
#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]; char *buf; /*打开文件*/ fd = open("/dev/memdev0",O_RDWR); buf = (char *)malloc(100); memset(buf, 0, 100); start=mmap(NULL,100,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); /* 读出数据 */ strcpy(buf,start); sleep (1); printf("buf 1 = %s\n",buf); /* 写入数据 */ strcpy(start,"Buf Is Not Null!"); memset(buf, 0, 100); strcpy(buf,start); sleep (1); printf("buf 2 = %s\n",buf); munmap(start,100); /*解除映射*/ free(buf); close(fd); return 0; }
注意:当写入时,mmap不会影响文件的长度!
虚拟内存区域
虚拟内存区域是进程的虚拟地址空间中的一个同质区间,即具有同样特性的连续地址范围。一个进程的内存映象由下面几部分组分:程序代码、数据、BSS和栈区域,以及内存映射的区域。通过/proc/pid/maps可以看到
VM_AREA_STRUCT
Linux内核使用结构vm_area_struct来描述虚拟内存区其中几个主要成员如下:
unsigned long vm_start
虚拟内存区域起始地址
unsigned long vm_end
虚拟内存区域结束地址
unsigned long vm_flags
该区域的标记:如VM_IO
VM_RESERVED
mmap设备操作
映射一个设备是指 把用户空间的一段地址关联到设备内存上当程序读写这段用户空间的地址时,它实际上是在访问设备。
步骤
1)找到用户空间的地址(内核自动帮你做好)
2)找到设备的物理地址(查看芯片手册)
3)关联 (通过页式管理)
mmap设备方法所需要做的就是建立虚拟地址到物理地址的页表
int (*mmap)(struct file * , struct vm_area-strcut *)
↓
内核帮我找的
mmap如何完成页表的建立?
方法有二:
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 | 要映射的物理地址所在的物理页帧号(物理地址的序列号),可将物理地址>>PGE_SHIFT得到,即右移12位,相当于除以4k(2^12) |
prot | VMA的保护属性 |
static int memdev_mmap(struct file*filp, struct vm_area_struct *vma) { struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/ /*设置保护属性*/ 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, vma->vm_end - vma->vm_start, vma->vm_page_prot))//关联,建立页表 return -EAGAIN; return 0; }
相关文章推荐
- [RK3288][Android6.0] 调试笔记 --- 测试I2C设备正常传输方法【转】
- Mmap设备方法---那些年我们一起玩嵌入式驱动
- 【Linux笔记】CentOS下找不到eth0设备的解决方法
- [RK3288][Android6.0] 调试笔记 --- 测试I2C设备正常传输方法
- j2me学习笔记【2】——利用Display类的isColor()方法获取设备是否支持彩色的信息
- Linux内核驱动--mmap设备方法【原创】
- 字符设备驱动另一种写法—mmap方法操作LED
- mmap设备方法
- 高级字符设备驱动-Poll设备方法笔记
- mmap设备操作-内存映射,把文件映射到内存中(国嵌笔记)
- linux设备驱动学习笔记--内核调试方法之printk
- Linux内核笔记 - 内核编译错误及解决方法记录
- 【C#学习笔记】各种定义方法的例子
- 关于敏捷开发方法(Agile Software Development)的阅读笔记
- 【笔记】模电--lesson07 放大电路分析方法II
- IOS 学习笔记(6) 控件 文本域(UITextField)的使用方法
- Python学习笔记 --- 对文本编码进行转换方法2
- [转]“无法停止‘通用卷’设备的处理方法
- LaTex学习笔记(1)——LaTeX文档插入图片的几种常用方法
- 《暗时间》的笔记-学习习惯(三):阅读方法