Linux驱动虚拟地址和物理地址的映射(转)

摘要:
对于内核物理内存映射区的虚拟内存,使用virt_to_phys()和phys_to_virt()来实现物理地址和内核虚拟地址之间的互相转换。上述方法适用于常规内存,高端内存的虚拟地址与物理地址之间不存在如此简单的换算关系。为了保证驱动程序的跨平台的可移植性,我们应该使用Linux中特定的函数来访问I/O内存资源,而不应该通过指向核心虚地址的指针来访问。

原文地址:http://blog.chinaunix.net/uid-20792373-id-2979673.html

参考链接:

Linux 虚拟地址与物理地址的映射关系分析https://blog.csdn.net/ordeder/article/details/41630945

虚拟地址映射到物理地址的学习(linux篇)https://blog.csdn.net/chablin/article/details/79827226

linux--物理地址到虚拟地址映射,ioremap()函数https://blog.csdn.net/ngany/article/details/88928045?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

Linux下的虚拟地址映射详解(一)逻辑地址到线性地址的映射https://blog.csdn.net/qq_33225741/article/details/71982274?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

Linux驱动mmap内存映射https://www.cnblogs.com/wanghuaijun/p/7624564.html

Linux设备驱动之mmap设备操作https://www.cnblogs.com/wanghuaijun/p/7624564.html

Linux 字符设备驱动—— ioremap() 函数解析https://www.cnblogs.com/kazuki/p/9341414.html

一般情况下,Linux系统中,进程的4GB内存空间被划分成为两个部分——用户空间和内核空间,大小分别为0~3G,3~4G。

用户进程通常情况下,只能访问用户空间的虚拟地址,不能访问到内核空间。

每个进程的用户空间都是完全独立、互不相干的,用户进程各自有不同的页表。而内核空间是由内核负责映射,它并不会跟着进程改变,是固定的。内核空间地址有自己对应的页表,内核的虚拟空间独立于其他程序。

3~4G之间的内核空间中,从低地址到高地址依次为:物理内存映射区—隔离带—vmalloc虚拟内存分配区—隔离带—高端内存映射区—专用页面映射区—保留区。

Linux驱动虚拟地址和物理地址的映射(转)第1张

【内核空间内存动态申请】

主要包括三个函数:kmalloc(), __get_free_pages, vmalloc。

kmalloc(), __get_free_pages申请的内存位于物理地址映射区,而且在物理上也是连续的,它们与真实的物理地址只有一个固定的偏移,因此存在较简单的转换关系。而vmalloc申请的内存位于vmalloc虚拟内存分配区(这些区都是以线性地址为度量),它在虚拟内存空间给出一块连续的内存区,实质上,这片连续的虚拟内存在物理内存中并不一定连续,而vmalloc申请的虚拟内存和物理内存之间也没有简单的换算关系。

因为vmalloc申请的在虚拟内存空间连续的内存区在物理内存中并不一定连续,可以想象为了完成vmalloc,新的页表需要被建立,因此,调用vmalloc来分配少量内存是不妥的。

一般来讲,kmalloc用来分配小于128K的内存,而更大的内存块需要用vmalloc来实现。

【虚拟地址与物理地址关系】

对于内核物理内存映射区的虚拟内存(用kmalloc(), __get_free_pages申请的),使用virt_to_phys()和phys_to_virt()来实现物理地址和内核虚拟地址之间的互相转换。它实际上,仅仅做了3G的地址移位。

上述方法适用于常规内存(内核物理内存映射区),高端内存的虚拟地址与物理地址之间不存在如此简单的换算关系。因为它涉及到了分离物理页的页表控制机制。

【ioremap】

在ARM中,设备的寄存器或者存储块的这部分空间属于内存空间的一部分,我们称之为IO内存。

在内核中访问IO内存之前,我们只有IO内存的物理地址,这样是无法通过软件直接访问的,需要首先用ioremap()函数将设备所处的物理地址映射到内核虚拟地址空间(3GB~4GB)。然后,才能根据映射所得到的内核虚拟地址范围,通过访问指令访问这些IO内存资源。

在将I/O内存资源的物理地址映射成核心虚地址后,理论上讲我们就可以象读写RAM那样直接读写I/O内存资源了。为了保证驱动程序的跨平台的可移植性,我们应该使用Linux中特定的函数来访问I/O内存资源,而不应该通过指向核心虚地址的指针来访问。

【mmap】

用mmap映射一个设备,意味着使用户空间的一段地址关联到设备内存上,这使得只要程序在分配的地址范围内进行读取或者写入,实际上就是对设备的访问。这种数据传输是直接的,不需要用到内核空间作为数据转移的中间站。

remap_page_range函数的功能是构造用于映射一段物理地址的新页表,实现了内核空间与用户空间的映射。

在内核驱动程序的初始化阶段,通过ioremap()将物理地址映射到内核虚拟空间;在驱动程序的mmap系统调用中,使用remap_page_range()将该块ROM映射到用户虚拟空间。这样内核空间和用户空间都能访问这段被映射后的虚拟地址。

Ioremap:

进程空间、内核空间、IO内存

其中,后面两个指的是同一段物理内存区域,只是一个为虚拟地址,一个为物理地址。进程空间和内核空间对应着不同的物理地址,它们之间的数据传递,是实际的数据的拷贝。

mmap:

进程空间、IO内存

其中,进程空间mmap得到的那段虚拟地址跟IO内存对应着同一段物理地址。这个过程没有额外的数据中转,读写都直接针对硬件的物理地址进行。

一般来讲,小数据量的传输用ioremap()就足够了,

【IO内存的一般访问方法】

1.首先是调用request_mem_region()申请资源,即告诉内核,本驱动正在使用这段物理内存,其他驱动不得访问它们。在设备驱动模块加载或open()函数中进行。

2.接着讲寄存器地址通过ioremap()映射到内核空间虚拟地址,之后就可以通过Linux设备访问编程接口访问这些设备的寄存器了。在设备驱动初始化、write(),read(),ioctl()函数中进行。

3.访问完成之后,应对ioremap()申请的虚拟地址进行释放,并释放release_mem_region()申请的IO内存资源。在设备驱动模块卸载或release()函数中进行。

免责声明:文章转载自《Linux驱动虚拟地址和物理地址的映射(转)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇iOS应用程序的跳转和URL Scheme的使用【Spark笔记】Windows10 本地搭建单机版Spark开发环境下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Linux中的LVM逻辑卷管理(转载)

这几天把自己的系统重做了一下,把自己电脑的硬盘分区做成了LVM(逻辑卷管理)类型的了。呵呵,以前老是会出现某一个分区的磁盘空间突然不足,然后就得放别的盘里。等东西放的多了用某一件东西时候就非常麻烦,都不知道自己的东西到底在哪个磁盘里面放着呢。。。这下好了,把硬盘做了LVM类型的磁盘就不用操这心了,现在先分少点,等以后不够用了,直接给不够用的磁盘往上加容量就...

linux 利用 cron 实现 程序开机启动/cron任务的多种实现方法/cron重启/cron日志开启

方法一、登录服务器,直接修改:crontab -e然后添加:@reboot [nohup] {命令} ...# 或者定时任务指令保存退出: ctrl + O ctrl + x方法二、指定用户进行修改:sudo crontab -u {username} -e然后添加:@reboot [nohup] {命令}...# 或者定时任务指令保存退出: ctrl...

linux每日命令(39):lsof命令

lsof(list open files)是一个列出当前系统打开文件的工具。在linux环境下,任何事物都以文件的形式存在,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。所以如传输控制协议 (TCP) 和用户数据报协议 (UDP) 套接字等,系统在后台都为该应用程序分配了一个文件描述符,无论这个文件的本质如何,该文件描述符为应用程序与基础操作系...

linux批量操作(一)

一、常用命令 1、关闭所有java进程命令:   ps -ef | grep java | grep -v grep | awk '{print $2}' | xargs kill -9 2、批量文本操作   替换字符串:sed -i 's/原字符串/新字符串/g' /home/1.txt   删除字符串:sed -i '/字符串/d' file   字符...

关于在Linux下的换行符 和windows下的换行符

linux系统下的换行符是 ,windows系统下的换行符是 。 分别在linux下和windows下创建文件linux.config和windows.config,写入几行内容。 通过打印文件的每一个字符的ASCII可以看出来, 的ascii为10, 的ascii为13。 在linux系统下修改windows.config输入换行,再打印可以发现输入的换...

linux资源使用配置文件 /etc/security/limits.conf和ulimit

  limits.conf文件实际上是linux PAM中pam_limits.so的配置文件,而且只针对于单个会话。   limits.conf的格式如下:   <domain>  <type>  <item>  <value>   domain有好几种格式,具体可以用man limits.conf来查看,...