[转载]Linux驱动mmap内存映射
原文地址:https://www.cnblogs.com/wanghuaijun/p/7624564.html
mmap在linux哪里?
什么是mmap?
上图说了,mmap是操作这些设备的一种方法,所谓操作设备,比如IO端口(点亮一个LED)、LCD控制器、磁盘控制器,实际上就是往设备的物理地址读写数据。
但是,由于应用程序不能直接操作设备硬件地址,所以操作系统提供了这样的一种机制——内存映射,把设备地址映射到进程虚拟地址,mmap就是实现内存映射的接口。
操作设备还有很多方法,如ioctl、ioremap
mmap的好处是,mmap把设备内存映射到虚拟内存,则用户操作虚拟内存相当于直接操作设备了,省去了用户空间到内核空间的复制过程,相对IO操作来说,增加了数据的吞吐量。
什么是内存映射?
既然mmap是实现内存映射的接口,那么内存映射是什么呢?看下图
每个进程都有独立的进程地址空间,通过页表和MMU,可将虚拟地址转换为物理地址,每个进程都有独立的页表数据,这可解释为什么两个不同进程相同的虚拟地址,却对应不同的物理地址。
什么是虚拟地址空间?
每个进程都有4G的虚拟地址空间,其中3G用户空间,1G内核空间(linux),每个进程共享内核空间,独立的用户空间,下图形象地表达了这点
驱动程序运行在内核空间,所以驱动程序是面向所有进程的。
用户空间切换到内核空间有两种方法:
(1)系统调用,即软中断
(2)硬件中断
虚拟地址空间里面是什么?
了解了什么是虚拟地址空间,那么虚拟地址空间里面装的是什么?看下图
虚拟空间装的大概是上面那些数据了,内存映射大概就是把设备地址映射到上图的红色段了,暂且称其为“内存映射段”,至于映射到哪个地址,是由操作系统分配的,操作系统会把进程空间划分为三个部分:
(1)未分配的,即进程还未使用的地址
(2)缓存的,缓存在ram中的页
(3)未缓存的,没有缓存在ram中
操作系统会在未分配的地址空间分配一段虚拟地址,用来和设备地址建立映射,至于怎么建立映射,后面再揭晓。
现在大概明白了“内存映射”是什么了,那么内核是怎么管理这些地址空间的呢?任何复杂的理论最终也是通过各种数据结构体现出来的,而这里这个数据结构就是进程描述符。从内核看,进程是分配系统资源(CPU、内存)的载体,为了管理进程,内核必须对每个进程所做的事情进行清楚的描述,这就是进程描述符,内核用task_struct结构体来表示进程,并且维护一个该结构体链表来管理所有进程。该结构体包含一些进程状态、调度信息等上千个成员,我们这里主要关注进程描述符里面的内存描述符(struct mm_struct mm)
内存描述符
具体的结构,请参考下图
现在已经知道了内存映射是把设备地址映射到进程空间地址(注意:并不是所有内存映射都是映射到进程地址空间的,ioremap是映射到内核虚拟空间的,mmap是映射到进程虚拟地址的),实质上是分配了一个vm_area_struct结构体加入到进程的地址空间,也就是说,把设备地址映射到这个结构体,映射过程就是驱动程序要做的事了。
内存映射的实现
以字符设备驱动为例,一般对字符设备的操作都如下框图
而内存映射的主要任务就是实现内核空间中的mmap()函数,先来了解一下字符设备驱动程序的框架
以下是mmap_driver.c的源代码
下面是测试代码test_mmap.c
下面是makefile文件
下面命令演示一下驱动程序的编译、安装、测试过程(注:其他用户在mknod之后还需要chmod改变权限)
# make //编译驱动 # insmod mmap_driver.ko //安装驱动 # mknod /dev/mmap_driver c //创建设备文件 # gcc test_mmap.c -o test.o //编译应用程序 # ./test.o //运行应用程序来测试驱动程序
拓展:
关于这个过程,涉及一些术语
(1)设备文件:linux中对硬件虚拟成设备文件,对普通文件的各种操作均适用于设备文件
(2)索引节点:linux使用索引节点来记录文件信息(如文件长度、创建修改时间),它存储在磁盘中,读入内存后就是一个inode结构体,文件系统维护了一个索引节点的数组,每个元素都和文件或者目录一一对应。
(3)主设备号:如上面的999,表示设备的类型,比如该设备是lcd还是usb等
(4)次设备号:如上面的0,表示该类设备上的不同设备
(5)文件(普通文件或设备文件)的三个结构
①文件操作:struct file_operations
②文件对象:struct file
③文件索引节点:struct inode
关于驱动程序中内存映射的实现,先了解一下open和close的流程
(1)设备驱动open流程
①应用程序调用open("/dev/mmap_driver", O_RDWR);
②Open就会通过VFS找到该设备的索引节点(inode),mknod的时候会根据设备号把驱动程序的file_operations结构填充到索引节点中(关于mknod /dev/mmap_driver c 999 0,这条指令创建了设备文件,在安装驱动(insmod)的时候,会运行驱动程序的初始化程序(module_init),在初始化程序中,会注册它的主设备号到系统中(cdev_add),如果mknod时的主设备号999在系统中不存在,即和注册的主设备号不同,则上面的指令会执行失败,就创建不了设备文件)
③然后根据设备文件的索引节点中的file_operations中的open指针,就调用驱动的open方法了。
④生成一个文件对象files_struct结构,系统维护一个files_struct的链表,表示系统中所有打开的文件
⑤返回文件描述符fd,把fd加入到进程的文件描述符表中
(2)设备驱动close流程
应用程序调用close(fd),最终可调用驱动的close,为什么根据一个简单的int型fd就可以找到驱动的close函数?这就和上面说的三个结构(struct file_operations、struct file、struct inode)息息相关了,假如fd = 3
(3)设备驱动mmap流程
由open和close得知,同理,应用程序调用mmap最终也会调用到驱动程序中mmap方法
①应用程序test.mmap.c中mmap函数
void* mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
addr:映射后虚拟地址的起始地址,通常为NULL,内核自动分配
length:映射区的大小
prot:页面访问权限(PROT_READ、PROT_WRITE、PROT_EXEC、PROT_NONE)
flags:参考网络资料
fd:文件描述符
offset:文件映射开始偏移量
②驱动程序的mmap_driver.c中mmap函数
上面说了,mmap的主要工作是把设备地址映射到进程虚拟地址,也即是一个vm_area_struct的结构体,这里说的映射,是一个很悬的东西,那它在程序中的表现是什么呢?——页表,没错,就是页表,映射就是要建立页表。进程地址空间就可以通过页表(软件)和MMU(硬件)映射到设备地址上了
virt_to_phys(buf),buf是在open时申请的地址,这里使用virt_to_phys把buf转换成物理地址,是模拟了一个硬件设备,即把虚拟设备映射到虚拟地址,在实际中可以直接使用物理地址。
总结
①从以上看到,内核各个模块错综复杂、相互交叉
②单纯一个小小驱动模块,就涉及了进程管理(进程地址空间)、内存管理(页表与页帧映射)、虚拟文件系统(structfile、structinode)
③并不是所有设备驱动都可以使用mmap来映射,比如像串口和其他面向流的设备,并且必须按照页大小进行映射。
[转载]Linux驱动mmap内存映射的更多相关文章
- Linux驱动mmap内存映射
mmap在linux哪里? 什么是mmap? 上图说了,mmap是操作这些设备的一种方法,所谓操作设备,比如IO端口(点亮一个LED).LCD控制器.磁盘控制器,实际上就是往设备的物理地址读写数据. ...
- Linux驱动之内存映射
本文参考了http://www.cnblogs.com/geneil/archive/2011/12/08/2281222.html.本文作为学习总结,将主要过程简要描述. 很多驱动实现某些功能都要通 ...
- linux mmap 内存映射【转】
转自:http://blog.csdn.net/xyyangkun/article/details/7830313 [-] mmap vs readwritelseek mmap vs malloc ...
- linux mmap 内存映射
mmap() vs read()/write()/lseek() 通过strace统计系统调用的时候,经常可以看到mmap()与mmap2().系统调用mmap()可以将某文件映射至内存(进程空间), ...
- mmap内存映射
http://blog.csdn.net/kongdefei5000/article/details/70183119 内存映射是个很有用,也很有意思的思想.我们都知道操作系统分为用户态和内核态,用户 ...
- 【转】Python之mmap内存映射模块(大文本处理)说明
[转]Python之mmap内存映射模块(大文本处理)说明 背景: 通常在UNIX下面处理文本文件的方法是sed.awk等shell命令,对于处理大文件受CPU,IO等因素影响,对服务器也有一定的压力 ...
- sendfile“零拷贝”和mmap内存映射
在学习sendfille之前,我们先来了解一下浏览器访问页面时,后台服务器的大致工作流程. 下图是从用户访问某个页面到页面的显示这几秒钟的时间当中,在后台的整个工作过程. 如上图,黑色箭头所示的过程, ...
- Linux驱动设计——内存与IO访问
名词解释 内存空间与IO空间 内存空间是计算机系统里面非系统内存区域的地址空间,现在的通用X86体系提供32位地址,寻址4G字节的内存空间,但一般的计算机只安装256M字节或者更少的内存,剩下的高位内 ...
- linux编程之内存映射
一.概述 内存映射是在调用进程的虚拟地址空间创建一个新的内存映射. 内存映射分为2种: 1.文件映射 ...
随机推荐
- CSS样式--移动划过超链接鼠标变手型详解
用css控制鼠标样式的语法如下:<span style="cursor:*">文本或其它页面元素</span>把 * 换成如下15个效果的一种: 下面是对这 ...
- hdu 6059 Kanade's trio(字典树)
Kanade's trio Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)T ...
- 性能优化 - 查看 webpack 打包后所有的依赖关系(webpack 可视化工具)
查看 webpack 打包后所有组件与组件间的依赖关系,针对多余的包文件过大, 剔除首次影响加载的效率问题进行剔除修改,本次采用的是 ==webpack-bundle-analyzer(可视化视图查看 ...
- myeclipes快捷键
package com.Test02;//alt+shift+s+s 自动创建toString()//ctrl+ shift+ o 自动导包//* alt+ shift +s+o 有参构造//* a ...
- Python基础学习----字符串的常用方法
# Python字符串 # 大多数的语言定义字符串是双引号,Python既可以双引号,也可以单引号.但使用也有区别 # 单双引号的使用 My_name="bai-boy" Demo ...
- python 中 property 属性的讲解及应用
Python中property属性的功能是:property属性内部进行一系列的逻辑计算,最终将计算结果返回 property属性的有两种方式: 1. 装饰器 即:在方法上应用装饰器 2. 类属性 即 ...
- 简单的cookie盗取
此文需要有一定的javascript\html\php方面的只是作为基础 直接上代码: #用于抓取盗窃来的cookie的php文件,此文件需置于攻击者的服务器上,这里包含了两种写法:Method1和M ...
- ETL学习整理 PostgreSQL
ETL分别是“Extract”.“ Transform” .“Load”三个单词的首字母缩写也就是“抽取”.“转换”.“装载”,但我们日常往往简称其为数据抽取. ETL是BI/DW(商务智能/数据仓库 ...
- 微信测试帐号如何设置URL和Token,以及相关验证的原理
首先说明,本帮助文档是利用javaweb的Servlet来进行“接口配置信息配置信息”认证的. 在学习微信公众号开发的时候,读到填写服务器配置的帮助部分,总是不能理解为啥按照他的步骤做总是设置失败(吐 ...
- Jenkins自动构建VS的代码20150607
1. 安装Jenkins Ø 双击安装即可,如果需要,可以配置环境变量(一般没设置) Ø 在浏览器中输入:http://localhost:8080/打开jekins,及完成jenkins安装 Ø 如 ...