当前位置: 首页 > news >正文

Linux驱动学习day12(mmap)

mmap

应用程序不能直读写驱动程序中的内容,如果需要应用程序读写,一般使用copy_to_user/copy_from_user这些内核提供的函数,在传输数据大的时候,使用这种方式就不太可行,比如更新LCD ,假设LCD采用1024*600*32bpp格式,那么每一帧就有1024*600*32/8 = 2.3MB。为了改进上述不足,可以通过mmap实现让应用程序直接修改驱动程序的buf,提高效率。

 

根据代码运行结果来看,两个值不相同,说明这两个代码运行于不同的物理内存中,打印出来的地址是CPU看见的虚拟内存,也就是说运行第一个代码的时候vaddr会映射到paddr1,运行第二个代码的时候vaddr会映射到paddr2上。MMU负责将CPU发出的虚拟地址转化为应用程序的物理地址,对于不同的程序来说,转换的方式不同。 不同的物理地址可以映射到相同的虚拟地址,同理不同的虚拟地址也可以映射到相同的物理地址,这便是应用程序和驱动程序访问同一块内存的原理。

mmap的原理 

在内核中,每一个APP都有一个task_struct结构体来表示,mm_struct用来描述进程所使用的内存,既描述虚拟地址,也描述虚拟地址如何映射到物理地址。mm_struct中含有两个成员,mmap是一个链表,链表项为vm_area_struct结构体,每一个链表项代表一块虚拟内存,虚拟内存使用pgd(页目录表)将虚拟地址映射到物理地址。

 页目录表如何将虚拟地址映射到物理地址

一级页表映射过程(1M vaddr->1M paddr)

假设虚拟地址是0x12345678 , 会根据高12位去页表中找到0x123页表项,取出内容,看使用一级页表。页表中存放物理地址,假设是0x81000000。这就可以知道从0x12300000开始的1M虚拟地址对应0x81000000开始1M物理地址。

所以vaddr :0x12345678对应的paddr:0x81045678

使用一级页表来映射太浪费内存了,所以可以使用二级页表来映射内存块。

 二级页表映射过程

二级页表映射的内存可以是1K也可以是4K,Linux系统使用4K.

假设vaddr:0x12345678 , 首先要先一级页表的基地址发给MMU,启动MMU,CPU发送0x12345678给MMU,MMU使用高12位找到对应一级页表的0x123页表项,发现是二级页表,得到二级页表。根据45这8位,找到二级页表第0x45项,得到4K空间的基地址base。所以最终虚拟地址0x12345678-->物理地址:base + 0x678。

驱动程序需要做 

 

1、APP得到 vaddr   内核会自动够着vm_area_struct结构体 应用程序调用mmap(); 

2、得到 paddr   我们需要确定物理地址

我们只需要实现驱动的mmap函数,设置属性:cache,buffer,给vm_area_struct和物理地址建立映射。

3、map : vaddr->paddr 内核函数

cache和buf 

 cache也是块内存,速度块,价格高。程序运行时有“局部性原理”,分为空间局部性和时间局部性。时间局部性:访问一块地址,在很小的一段时间内会多次访问这个地址;空间局部性:访问一个地址时,很小一段时间内会多次访问到该地址附近的地址。

使用mmap时,需要考虑是否使用cache和buf,因为cache里面的值和主存中的值不一致,cpu先写入cache,并不会立即从cache写入主存。

不使用cache和buf的情况

1、register 2、framebuffer(显存) 3、DMA

对于一般的变量和RAM可以使用cache。

使用buffer要注意:buffer写合并(比如,想分四次写入东西,但是使用buf之后会被合并成1个word的写操作),所以buf的功能在写寄存器的时候也不应该使用。

mmap编程

使用mmap共享内存,在驱动代码中主要添加一个.mmap的实现。该函数中获取物理地址,设置mmap属性,物理地址到虚拟地址的映射。

static int hello_drv_mmap(struct file *filp, struct vm_area_struct *vma)
{/* get phys */unsigned long phys = virt_to_phys(kernel_buf);/* set ceche and buffer */vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);/* mmap */if(remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)){printk("mmap remap_pfn_range failed\n");return -ENOBUFS;}return 0;
}

用户态程序代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/mman.h>
/*  ./hello_test
*/int main(int argc , char* argv[])
{int fd = 0;int len =0;int ret;char *buf;char str[1024];fd = open("/dev/hello" , O_RDWR);if(fd < 0){printf("can not open file\n");return -1;}/* mmap */buf = mmap(NULL, 1024*8, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);if(buf == MAP_FAILED){printf("mmap err\n");close(fd);}printf("mmap address 0x%x\n" , buf);printf("buf : %s\n" , buf);/* write */strcpy(buf, "new");/* read */ret = read(fd , str , 1024);if(strcmp(buf, str) == 0){printf("mmap compare ok\n");}else{printf("mmap compare no\n");printf("str:%s\n" , str);printf("buf:%s\n" , buf);}while(1){sleep(10);}munmap(buf, 1024*8);close(fd);return 0;
}

当用户态程序设置mmap共享内存属性为MAP_SHARED时的运行结果。 

当 用户态程序设置mmap共享内存属性为MAP_PRIVATE时的运行结果。 

当为私有的时候,如果用户态对共享内存进行修改,会拷贝一份相同的东西,然后在另外一个地址上进行修改,这样如果read fd的时候,读到的是老的内存中的内容,而之前的buf则是新的数据。

验证了之前Linux系统编程的时候对mmap的说法:读共享,写独占。

这是之前学习Linux系统编程对mmap的理解:

Linux系统编程 day6 进程间通信mmap_mmap进程间-CSDN博客

今天的内容比较难啃,很多关于内核的信息,加油!驱动大全 

http://www.lqws.cn/news/590671.html

相关文章:

  • 道可云人工智能每日资讯|浦东启动人工智能创新应用竞赛
  • 业界优秀的零信任安全管理系统产品介绍
  • 从0开始学习R语言--Day35--核密度动态估计
  • ABB PPD 113 B03-23-100110 3 bhe 023584 r 2334 AC 800 pec控制系统
  • 腾讯 iOA 零信任产品:安全远程访问的革新者
  • ASP.NET代码审计 MVC架构 SQL注入漏洞
  • LINUX2.6设备注册与GPIO相关的API
  • 将N8N配置为服务【ubuntu】
  • 第4课:Flask请求与响应对象深度解析
  • 使用mavros启动多机SITL仿真
  • WPF学习笔记(17)样式Style
  • Coze(扣子):基础学习
  • 利用视觉-语言模型搭建机器人灵巧操作的支架
  • 【Docker基础】Docker数据卷:数据卷的作用与使用场景
  • 算法-每日一题(DAY12)最长和谐子序列
  • Salesforce Accountアクションボタン実装ガイド
  • 简单聊聊 Flutter 在鸿蒙上为什么可以 hotload ?
  • 飞算JavaAI—AI编程助手 | 编程领域的‘高科技指南针’,精准导航开发!
  • 具身多模态大模型在感知与交互方面的综述
  • sqlmap学习ing(2.[第一章 web入门]SQL注入-2(报错,时间,布尔))
  • rocketmq 之 阿里云转本地部署实践总结
  • Vue3 中 Excel 导出的性能优化与实战指南
  • 创建和连接Vue应用程序实例
  • 缓存系统-淘汰策略
  • 强化学习系列--dpo损失函数
  • 齿轮的齿厚极限偏差如何确定?一起学习一下
  • C++基础
  • 目前最火的agent方向-A2A快速实战构建(二): AutoGen模型集成指南:从OpenAI到本地部署的全场景LLM解决方案
  • 《Python 架构之美:三大设计模式实战指南》
  • 【FR801xH】富芮坤FR801xH之UART