mmap方法实现物理内存到用户虚拟地址的映射
来源:互联网 发布:淘宝微淘评论怎么匿名 编辑:程序博客网 时间:2024/05/16 08:57
内核空间内存管理:
物理内存被划分成struct page来进行管理。然后把所有page划分成不同的struct zone,Linux中使用了三种zone:
ZONE_DMA;
ZONE_NORMAL;
ZONE_HIGHMEM;
内核中获取内核虚拟内存有三种途径:
获取页:
如果你需要用到struct page,则:
struct page *alloc_pages(gfp_mask, order);
struct page *alloc_page(gfp_mask);
void *page_address(struct page *page);
第一个页的内核虚拟地址 = page_address(alloc_page(GFP_KERNEL, 3));--分配8个页
第一个页的内核虚拟地址 = page_address(alloc_page(GFP_KERNEL));--分配一个页
如果用不到struct page,则:
unsigned long __get_free_pages(gfp_mask, order);
unsigned long __get_free_page(gfp_mask);
kmalloc:
分配以字节为单位的一块内核内存,且分配的内存物理上连续。返回内核虚拟地址。
vmalloc:
分配以字节为单位的一块内核内存,但分配的内存物理上不连续。返回内核虚拟地址。
4 slab分配器
其实就是kmalloc() 分配连续的内核虚拟地址,用于小内存分配。
__get_free_page() 分配连续的内核虚拟地址,用于整页分配。
前者基于slab,两者最终都使用__alloc_page()来返回物理页的page结构。其实他们都是在“物理内存映射区”进行内存分配,其内核虚拟地址与物理地址仅相差一个常量。
这种内核虚拟地址和vmalloc分配(经过页表映射)的内核虚拟地址不一样,也称为逻辑地址。他们与物理地址之间的转换也很简单:
/include/asm/memory.h(page.h中包含了memory.h)
#define __pa(x)
static inline unsigned long virt_to_phys(void *x){
#define __virt_to_phys(x)
都是通过__virt_to_phys()和__phys_to_virt()两个宏的简单实现。
另外还有:
#define page_to_pfn(page)
#define virt_to_page(kaddr) 等其他一些地址转换函数。
用户空间直接访问设备内存:
内存映射mmap()可以提供给 用户程序 直接访问 设备内存 的能力。
映射一个设备就是通过建立页表,将用户空间的一段虚拟内存空间和设备内存关联起来。但是并不是所有设备都能够进行mmap映射。比如串口和其他面向流的设备就不行,并且mmap还有一个限制:必须以PAGE_SIZE为单位进行映射。
mmap方法是file_operations结构的一部分,用户空间系统调用原型为:
mmap (cadaar_t addr, size_t len, int prot, int flags, int fd, off_t offset)
但是文件操作声明如下:
int (*mmap) (struct file *filp, struct vm_area_struct *vma)
注:vm_area_struct 是描述进程地址空间的基本管理单元。vma中就需要包含用于访问设备虚拟地址的信息,因此大量工作是在内核中完成的。
实现mmap主要就是为用户虚拟地址建立到物理地址的页表,并将vma->vm_ops替换为一系列的新操作就可以了。
两种建立页表的方法:
一次全部建立:
int remap_pfn_range(struct vm_area_struct *vma, unsigned long virt_addr, unsigned long pfn, unsigned long size, pgprot_t prot);
int io_remap_page_range(struct vm_area_struct *vma, unsigned long virt_addr, unsigned long phys_addr, unsigned long size, pgprot_t prot);
这两个函数的功能是负责为一段物理地址创建新的页表。前者在pfn指向实际系统的RAM的时候使用,后者在phys_addr指向IO内存的时候使用。
(1) remao_pfn_range限制:只能访问保留页/超出物理内存的物理页。
因此这个函数不允许重映射常规地址。因为常规地址受内存管理单元的管理,可能会出现被换出内存等不安全现象。remap_pfn_range也无法处理RAM:基于内存的设备无法简单地实现mmap,因为其设备内存是通用的RAM,而不是IO内存。但是对于任何需要将RAM映射到用户空间的驱动程序来说可以通过nopage来达到目的。
(2) 但是这个函数可以映射设备IO内存(包括高端PCI缓冲区和ISA内存等)/ 内存中的保留页,如x86系统中的64k-1M的范围,如果想把kmalloc等申请的常规地址映射到用户空间,使用mem_map_reserve()把相应的内存设置为保留即可。不过对于常规内存还是建议使用nopage。
(3) 访问常规内存具体方法如下:
(1) kmalloc(),get_free_pages()等分配的页面,需要先设备为保留页,然后用virt_to_phys()函数只是得到其物理地址,然后 >> PAGE_SHIFT转换为页帧号。
(2) 通过vmalloc分配的,同上,不同的是要用vmalloc_to_pfn。
(3) 用kmalloc,get_free_pages,vmalloc分配的物理内存页面最好还是不要用remap_pfn_page方法,建议使用VMA的nopage方法。
(4) 对于这样设备内存,最好对vma调用pgprot_nocached(vma->vm_page_prot)后传给remap_pfn_range,防止处理器缓存。
(b) ioremap与io_remap_page_rage:
前者是将“IO内存资源”映射到内核虚拟地址空间;而后者是将”IO内存资源“映射到用户空间。
remap_pfn_range参数介绍:
参数vma是内核根据用户的请求自己填写的;
参数addr表示内存映射开始处的虚拟地址,因此,该函数为addr~addr+size之间的虚拟地址构造页表。
参数pfn(Page Fram Number)是虚拟地址应该映射到的物理地址的页面号,实际上就是物理地址右移PAGE_SHIFT位。如果PAGE_SHIFT为4kb,则PAGE_SHIFT为12,因为PAGE_SHIFT等于1<<PAGE_SHIFT。
参数prot是新页所要求的保护属性。
2 每次建立一页:
struct
(1)
(2)
注:其中
总结:总之在驱动程序中最常规的用法是:使用remap_pfn_range函数映射内存中的保留页(如X86系统中的640KB~1MB区域)和设备IO内存。而使用nopage函数来映射RAM。
原文地址:http://blog.sina.com.cn/s/blog_6a1928130100rsg9.html
- mmap方法实现物理内存到用户虚拟地址的映射
- mmap方法实现物理内存到用户虚拟地址的映射
- 【原】mmap方法实现物理内存…
- mmap方法将文件映射到内存
- 【C语言】【unix c】使用mmap将物理地址映射到进程的虚拟地址空间
- 设备地址映射到用户空间(mmap)
- mmap内存映射/dev/mem到用户空间
- mmap内存映射/dev/mem到用户空间 + kernel config
- 物理内存映射---------mmap和munmap详解
- 为何要把物理内存地址映射到内核空间?
- 虚拟地址到物理地址的映射
- 虚拟地址到物理地址的映射
- 虚拟字符驱动,申请n页内存,使用mmap映射到应用程序空间,用户就可以直接访问不需要任何同步机制
- 内核页表中是否存前896M的物理内存和虚拟地址之间的映射关系
- 【C语言】【unix c】使用mmap将文件映射到进程的虚拟地址空间,然后对内存的操作直接反应到文件中
- mmap将物理地址映射到用户空间
- linux中使用内存映射(mmap)操作文件的方法
- Windows下的分页模式- 页目录和页表从物理内存到虚拟映射求值
- POJ 3752 字母旋转游戏
- android学习笔记---53_采用网页设计软件界面,以及使用android系统内置的浏览器,利用js调用java方法
- Zookeeper -- 管理分布式环境中的数据
- 共享池的改进与ORA-04031的变化
- 关于EPOLL的ET与LT工作模式及其他细节
- mmap方法实现物理内存到用户虚拟地址的映射
- poj 1269 Intersecting Lines 计算几何 直线求交点
- IronJacamar 1.1.0.Beta5 发布
- C++ Prime学习过程中的细节摘记(三)
- rpm打包学习
- 使用PPRevealSideViewController创建抽屉式导航
- Ubuntu命令学习:bash中变量内容的删除、替代与替换
- 蛇形填数
- 黑马韩前成linux从入门到精通の轻松搞定负载均衡