技术分享 LINUX 查看内容

内存映射:mmap与ioremap

老高 | 发布于 2023-11-16 15:53| 浏览()| 评论() | 收藏() | 点赞() | 打印

摘要: 对于提供了MMU(存储管理器,辅助操作系统进行内存管理,提供虚实地址转换等硬件支持)的处理器而言,Linux提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB。

  对于提供了MMU(存储管理器,辅助操作系统进行内存管理,提供虚实地址转换等硬件支持)的处理器而言,Linux提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB。

  进程的4GB内存空间被人为的分为两个部分--用户空间与内核空间。用户空间地址分布从0到3GB(PAGE_OFFSET,在0x86中它等于0xC0000000),3GB到4GB为内核空间。

  1.不管是在用户空间还是在内核空间,软件一律不能去直接访问设备的物理地址;
  2.在内核驱动中如果要访问设备的物理地址,需要利用ioremap将设备的物理地址映射到内核虚拟地址上(动态内存映射区),以后驱动程序访问这个内核虚拟地址就是在间接得访问设备的物理地址(MMU,TLB,TTW)
  3.如果用户要访问硬件设备,不能直接访问,也不能在用户空间访问,只能通过系统调用(open,close,read,write,ioctl)来访问映射好的内核虚拟地址,通过这种间接的访问来访问硬件设备,但是如果涉及到数据的拷贝,还需要借助4个内存拷贝函数!

  1.应用程序通过read,write,ioctl来访问硬件设备,它们都要经过两次的数据拷贝,一次是用户空间和内核空间的数据拷贝,另外一次是内核空间和硬件之间的数据拷贝,如果设备拷贝的数据量比较小,那么read,write,ioctl的两次数据拷贝的过程对系统的影响几乎可以忽略不计,如果设备的数据量非常大,例如显卡(独立),LCD屏幕(显存共享主存),摄像头,声卡这类设备涉及的数据量比较庞大,如果还是用read,write,ioctl进行访问设备数据,无形对系统的性能影响非常大。
  2.用户访问设备,最终其实涉及的用户和硬件,而read,write,ioctl本身会牵扯到内核,所以这些函数涉及2次的数据拷贝,用户要直接去访问硬件设备,只需要将硬件设备的物理地址信息映射到用户的虚拟地址空间即可,一旦完毕,不会在牵扯到内核空间,以后用户直接访问用户的虚拟地址就是在访问设备硬件,由2次的数据拷贝的转换为一次的数据拷贝。未使用mmap,应用程序只能通过系统调用(read,write,ioctl)内核函数,内核函数获得硬件数据,应用程序再从内核函数获取数据;使用mmap后,用户程序可以直接访问映射后的虚拟地址获得硬件数据。

mmap:将硬件物理地址映射到用户虚拟地址空间,应用程序可以直接访问映射后的地址。由2次数据拷贝变成1次数据拷贝!mmap用于在用户程序中映射整个设备的物理地址。
ioremap:是将物理地址转换为内核虚拟地址,内核可以直接访问映射后的地址。ioremap用于在内核程序中映射设备的一个物理寄存器。


mmap是将设备内存线性地址映射到用户地址空间,用于大片数据比如音视频存储空间。
最后,我们要特别强调驱动程序中mmap函数的实现方法。用mmap映射一个设备,意味着使用户空间的一段地址关联到设备内存上,这使得只要程序在分配的地址范围内进行读取或者写入,实际上就是对设备的访问。

linux的线程只能访问虚拟地址,不管是不是内核,ioremap应用,比如有个寄存器地址是0xe8000000你要用ioremap映射后,才能访问地址0xe8000000。这两个地址是不同的,mmu会帮你搞定,对你是透明的

1、ioremap函数定义  

 ioremap宏定义在asm/io.h内:

#define ioremap(cookie,size)           __ioremap(cookie,size,0)

__ioremap函数原型为(arm/mm/ioremap.c):

void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags);

参数:

phys_addr:要映射的起始的IO地址

size:要映射的空间的大小

flags:要映射的IO空间和权限有关的标志

该函数返回映射后的内核虚拟地址(3G-4G). 接着便可以通过读写该返回的内核虚拟地址去访问之这段I/O内存资源。

发表评论(对文章涉及的知识点还有疑问,可以在这里留言,老高看到后会及时回复的。)

表情