linux驱动之mmap地址映射

news2024/12/28 18:11:29

应用场景

首先在linux中应用程序无法是直接访问驱动程序的数据的, 需要通过 copy_to_user 和 copy_from_user才能实现数据传输, 那么数据量大了以后如LCD的数据, 那么就会有很长的耗时, 为了解决这一问题, 引入mmap, 将底层物理地址映射出来, 让应用程序得以直接读写这一块内存. mmap的使用说白了, 很简单:
1, 有块虚拟地址
2, 找到要用的那块物理地址
3, 建立映射

内核应用程序开辟的虚拟地址

内核将每个进程都作为一个task_struct结构体存在一个双向循环链表中, 结构体在 include/linux/sched.h中定义. 其中有个struct mm_struct *mm成员, 记录着这个进程的虚拟地址的信息.duan0
在mm_struct中, struct vm_area_struct mmap 链表保存了每一块应用程序虚拟地址(堆空间, 栈空间, bss区, data常量空间, text代码0段)的起始位置和结束位置. 当然虚拟地址不可能是凭空产生, 自然是要有一块相应的物理地址来对应, 这一块物理地址就保存在pgd_t * pgd* 这个成员变量中叫做页目录表, pgd成员记录了对应的物理地址, 也记录了如何映射

进程启动时虚拟地址内核已经帮我们做好了, 当一段程序运行时,便开辟了一块4G虚拟地址(在32位系统中), 在linux中可以在 /proc/进程号/maps 来查看这个进程用到的虚拟地址

页表

将虚拟地址的某一段转换成物理地址的话, 就需要在页表pgd中添加一个页表项.
页表项的内容是个32位的数据, 如下图
在这里插入图片描述
ARM架构内存映射:
RM架构支持一级页表映射,也就是说MMU根据CPU发来的虚拟地址可以找到第1个页表,从第1个页表里就可以知道这个虚拟地址对应的物理地址。一级页表里地址映射的最小单位是1M。
ARM架构还支持二级页表映射,也就是说MMU根据CPU发来的虚拟地址先找到第1个页表,从第1个页表里就可以知道第2级页表在哪里;再取出第2级页表,从第2个页表里才能确定这个虚拟地址对应的物理地址。二级页表地址映射的最小单位有4K、1K,Linux使用4K

一级页表映射过程
一线页表中每一个表项用来设置1M的空间,对于32位的系统,虚拟地址空间有4G,4G/1M=4096。所以一级页表要映射整个4G空间的话,需要4096个页表项。
第0个页表项用来表示虚拟地址第0个1M(虚拟地址为0~0xFFFFF)对应哪一块物理内存,并且有一些权限设置;
第1个页表项用来表示虚拟地址第1个1M(虚拟地址为0x100000~0x1FFFFF)对应哪一块物理内存,并且有一些权限设置;

使用一级页表时
① CPU发出虚拟地址vaddr,假设为0x12345678
② MMU根据vaddr[31:20]找到一级页表项:
在[1:0]发现是个一级页表
虚拟地址0x12345678是虚拟地址空间里第0x123个1M,所以找到页表里第0x123项,根据此项内容知道它是一个段页表项。
段内偏移是0x45678。
③ 从这个表项里取出物理基地址:Section Base Address,假设是0x81000000
④ 物理基地址加上段内偏移得到:0x81045678
所以CPU要访问虚拟地址0x12345678时,实际上访问的是0x81045678的物理地址
二级页表映射过程
① CPU发出虚拟地址vaddr,假设为0x12345678
② MMU根据vaddr[31:20]找到一级页表项:
虚拟地址0x12345678是虚拟地址空间里第0x123个1M,所以找到页表里第0x123项。根据此项的[1:0]内容知道它是一个二级页表项。
③ 从这个表项里取出地址,假设是address,这表示的是二级页表项的物理地址;
④ vaddr[19:12]表示的是二级页表项中的索引index即0x45,在二级页表项中找到第0x45项;
⑤二级页表项格式如下:
在这里插入图片描述
里面含有这4K或1K物理空间的基地址page base addr,假设是0x81889000:
它跟vaddr[11:0]组合得到物理地址:0x81889000 + 0x678 = 0x81889678。
所以CPU要访问虚拟地址0x12345678时,实际上访问的是0x81889678的物理地址

给APP新建一块内存映射

① 得到一个vm_area_struct,它表示APP的一块虚拟内存空间;
很幸运,APP调用mmap系统函数时,内核就帮我们构造了一个vm_area_stuct结构体。里面含有虚拟地址的地址范围、权限。
② 确定物理地址:
你想映射某个内核buffer,你需要得到它的物理地址,这得由你提供。
③ 给vm_area_struct和物理地址建立映射关系:
也很幸运,内核提供有相关函数。
APP里调用mmap时,导致的内核相关函数调用过程如下:在这里插入图片描述
cache和buffer映射属性如何选择:
是否使用cache、是否使用buffer,就有4种组合(Linux内核文件arch\arm\include\asm\pgtable-2level.h):在这里插入图片描述
第1种是不使用cache也不使用buffer,读写时都直达硬件,这适合寄存器的读写。
第2种是不使用cache但是使用buffer,写数据时会用buffer进行优化,可能会有“写合并”,这适合显存的操作。因为对显存很少有读操作,基本都是写操作,而写操作即使被“合并”也没有关系。
第3种是使用cache不使用buffer,就是“write through”,适用于只读设备:在读数据时用cache加速,基本不需要写。
第4种是既使用cache又使用buffer,适合一般的内存读写。

驱动程序要做的事

驱动程序要做的事情有3点:
① 确定物理地址
② 确定属性:是否使用cache、buffer
③ 建立映射关系
编码:
App

fd = open("/dev/hello", O_RDWR);
      /* 2. mmap
       * MAP_SHARED  : 多个APP都调用mmap映射同一块内存时, 对内存的修改大家都可以看到。
       *               就是说多个APP、驱动程序实际上访问的都是同一块内存
       * MAP_PRIVATE : 创建一个copy on write的私有映射。
       *               当APP对该内存进行修改时,其他程序是看不到这些修改的。
       *               就是当APP写内存时, 内核会先创建一个拷贝给这个APP,
       *               这个拷贝是这个APP私有的, 其他APP、驱动无法访问。
       */
      buf =  mmap(NULL, 1024*8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if (buf == MAP_FAILED)
      {
              printf("can not mmap file /dev/hello\n");
              return -1;
      }
      mmap函数MAP_SHARED、MAP_PRIVATE参数。使用MAP_PRIVATE映射时,
      在没有发生写操作时,APP、驱动访问的都是同一块内存;当APP发起写操作时,
      就会触发“copy on write”,即内核会先创建该内存块的拷贝,
      APP的写操作在这个新内存块上进行,这个新内存块是APP私有的,
      别的APP、驱动看不到。
	仅用MAP_SHARED参数时,
	多个APP、驱动读、写时,操作的都是同一个内存块,“共享”。
	printf("mmap address = 0x%x\n", buf);
    printf("buf origin data = %s\n", buf); /* old */

	/* 3. write */
    strcpy(buf, "new");
 	read(fd, str, 1024);
    if (strcmp(buf, str) == 0)
    {
            /* 对于MAP_SHARED映射,APP写的数据驱动可见
             * APP和驱动访问的是同一个内存块
            */
            printf("compare ok!\n");
     }

驱动程序:
分配内存的函数:

kmalloc 分配到的内存物理地址是连续的
kzalloc 分配到的内存物理地址是连续的,内容清0
vmalloc 分配到的内存物理地址不保证是连续的
vzalloc 分配到的内存物理地址不保证是连续的,内容清0
提供mmap函数

static int _drv_mmap(struct file *file, struct vm_area_struct *vma)
{
//获得物理地址
	unsigned long phy = virt_to_phys(bernel_buf);
得到物理地址, kernel_buf是内核使用的虚拟地址用kmalloc分配
//设置属性:cache, buffer
	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
设置属性, 不使用 cache 使用buffer
映射
	if(remap_pfn_range(vma, vma->vm_start, phy>>PAGE_SHIFT,
		vma->vm_end - vma->vm_start, vma->vm_page_prot)){
		printk("mmap remap_pfn_range failed\n");
		return -ENOBUFS;
	}
	return 0;
}

remap_pfn_range中,pfn的意思是“Page Frame Number”
在Linux中,整个物理地址空间可以分为第0页、第1页、第2页,诸如此类,这就是pfn。
假设每页大小是4K,那么给定物理地址phy,它的pfn = phy / 4096 = phy >> 12。内核的page一般是4K,但是也可以配置内核修改page的大小。所以为了通用,pfn = phy >> PAGE_SHIFT。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/14218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux进程控制(下)--->进程程序替换

文章目录什么是进程程序替换为什么要进行进程程序替换怎么进行进程程序替换execlexecvexeclpexecvpexecleexecvpe使用c的可执行程序调用一个python脚本如何理解进程程序替换进程程序替换接口的返回值从进程独立性体会程序替换什么是进程程序替换 在讲进程程序替换之前&#xf…

[附源码]java毕业设计兰州市邮政公司新邮预订户管理信息系统

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

计算机毕业设计springboot+vue+elementUI在线漫画周边销售购物交流系统

项目介绍 任何系统都要遵循系统设计的基本流程,本系统也不例外,同样需要经过市场进行调研,漫画需求进行分析,概要设计,系统详细设计,测试和编码等步骤,设计并实现了“漫画之家”系统 。系统选用…

web前端设计与开发期末作品_期末大作业-疫情

Web前端开发技术 描述 网页设计题材,DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业,击疫情致敬逆行者感人类题材 | 致敬逆行者网页设计作品 | 大学生抗疫感动专题网页设计作业模板 | 等网站的设计与制作 | HTML期末大学生网页设计作业 HTML&#xff1a…

大一学生Web课程设计 红酒美食主题网页制作(HTML+CSS+JavaScript)

Web前端开发技术 描述 网页设计题材,DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 茶文化网站 | 中华传统文化题材 | 京剧文化水墨风书画 | 中国民间年画文化艺术网站 | HTML期末大学生网页设计作业 HTML:结构 CSS:样式 在操作方面上运…

通用后台管理系统前端界面Ⅵ——首页、登录页、404页面

登录页 1、为了方便起见,先将element-ui的使用改为全局引入的方式。修改main.js文件如下: import Vue from vue import App from ./App.vue import ElementUI from element-ui import element-ui/lib/theme-chalk/index.css //这个是局部引入&#xff0…

idea创建javaweb项目步骤超详细(2022最新版本)

目录 前言: 一、新建文件 1.在idea里面点击文件-新建-项目 2.新建项目-更改名称为自己想要的项目名称-创建 3.右键自己建立的项目-添加框架支持 4.勾选Web应用程序-确定 5.建立成功界面 二、配置tomcat 6.点击添加配置文件 7.点击这个 8.选择这个tomcat的本…

数据分析利器:XGBoost算法最佳解析

XGBoost是一种经典的集成式提升算法框架,具有训练效率高、预测效果好、可控参数多、使用方便等特性,是大数据分析领域的一柄利器。在实际业务中,XGBoost经常被运用于用户行为预判、用户标签预测、用户信用评分等项目中。XGBoost算法框架涉及到…

javaWeb项目基于tomcat运行部署后访问方案总结

javaWeb项目基于tomcat运行部署后访问方案总结 1.需求背景 最近接到一个老项目,这个是一个前后没有分离的java+jsp项目,所以前后端的代码是在一个项目里面的,因此在这个项目上开发就需要面临第一个问题:启动运行项目。简介:Java Web,是用Java技术来解决相关web互联网领域…

字符串的算法题目-字符串

题目一: 描述 对于一个长度为 n 字符串,我们需要对它做一些变形。 首先这个字符串中包含着一些空格,就像"Hello World"一样,然后我们要做的是把这个字符串中由空格隔开的单词反序,同时反转每个字符的大小写…

【Java】数组中值得说的那些事

文章目录前言一、数组的创建及初始化🌳1、数组的创建🌳2、数组的初始化🍑(1)动态初始化🍑(2)静态初始化二、数组的使用🌳1、数组中元素访问🌳2、遍历数组&…

力扣LeatCode算法题-两数之和(二)

力扣算法题第二题,两数相加算法题: 要求: //给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 //如果,我们将这两个数…

企业使用有线和5G主备双链路上网配置案例

场景介绍 典型的企业分支通常还是采用有线链路作为主链路,例如以太链路、MPLS专线等。为了提升分支站点的可靠性,企业一般都会部署两条上行链路,一条为主链路,一条为备链路。如果两条上行链路都采用有线,成本会比较高&…

JVM StringTable

文章目录学习资料StringTableString的基本特性String的内存分配StringTable为什么要调整?String的基本操作字符串拼接操作拼接操作与append操作的效率对比intern()的使用学习资料 【尚硅谷宋红康JVM全套教程(详解java虚拟机)】 【阿里巴巴Ja…

prometheus exporter 监控主机

前提要求部署Grafana 前言 有许多库和服务器可以帮助将第三方系统中的现有指标导出为Prometheus指标。在无法直接使用Prometheus度量(例如,HAProxy或Linux系统统计数据)对给定系统进行检测的情况下,这是非常有用的。 node-exporter Linux操作系统采集&…

【Hack The Box】windows练习-- Scrambled

HTB 学习笔记 【Hack The Box】windows练习-- Scrambled 🔥系列专栏:Hack The Box 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 📆首发时间:🌴2022年11月17日🌴 &…

第2-3-5章 删除附件的接口开发-文件存储服务系统-nginx/fastDFS/minio/阿里云oss/七牛云oss

文章目录5.4 接口开发-根据id删除附件5.4.1 接口文档5.4.2 代码实现5.4.3 接口测试5.4.4 测试ALI和FAST_DFS以及MINIO上传和删除的接口5.4.4.1 阿里云OSS上传和删除5.4.4.2 FastDFS上传和删除5.4.4.3 Minio上传和删除5.5 接口开发-根据业务类型/业务id删除附件5.5.1 接口文档5.…

[附源码]SSM计算机毕业设计成都团结石材城商家协作系统JAVA

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

力扣(LeetCode)6. Z 字形变换(C++)

数学构造 ZZZ 字形变换类似情报加密。找规律解密,就能得到构造的方法。 第 000 行相邻的数,取 n4n4n4 如上图,观察第 000 行和第 333 行 相邻的数,组成等差数列,公差 d62n−2d62n-2d62n−2 2n−22n-22n−2 是说 &…

【小程序】微信小程序云开发笔记详细教程(建议收藏)

1- 前言 1.1 微信云开发是什么? 微信云开发是微信团队联合腾讯云推出的专业的小程序开发服务。 开发者可以使用云开发快速开发小程序、小游戏、公众号网页等,并且原生打通微信开放能力。 开发者无需搭建服务器,可免鉴权直接使用平台提供的…