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

海口网站建设过程机票网站建设公司

海口网站建设过程,机票网站建设公司,国内旅游网站排行榜,温州百度推广公司嵌入式Linux应用开发-基础知识-第十九章驱动程序基石⑤ 第十九章 驱动程序基石⑤19.9 mmap19.9.1 内存映射现象与数据结构19.9.2 ARM架构内存映射简介19.9.2.1 一级页表映射过程19.9.2.2 二级页表映射过程 19.9.3 怎么给APP新建一块内存映射19.9.3.1 mmap调用过程19.9.3.2 cach… 嵌入式Linux应用开发-基础知识-第十九章驱动程序基石⑤ 第十九章 驱动程序基石⑤19.9 mmap19.9.1 内存映射现象与数据结构19.9.2 ARM架构内存映射简介19.9.2.1 一级页表映射过程19.9.2.2 二级页表映射过程 19.9.3 怎么给APP新建一块内存映射19.9.3.1 mmap调用过程19.9.3.2 cache和 buffer19.9.3.3 驱动程序要做的事 19.9.4 编程19.9.4.119.9.4.2 驱动编程19.9.4.3 上机测试 第十九章 驱动程序基石⑤ 19.9 mmap 应用程序和驱动程序之间传递数据时可以通过 read、write函数进行。这涉及在用户态 buffer和内核态 buffer之间传数据如下图所示 应用程序不能直接读写驱动程序中的 buffer需要在用户态 buffer和内核态 buffer之间进行一次数据拷贝。这种方式在数据量比较小时没什么问题但是数据量比较大时效率就太低了。比如更新 LCD显示时如果每次都让 APP传递一帧数据给内核假设 LCD采用 102460032bpp的格式一帧数据就有102460032/82.3MB左右这无法忍受。 改进的方法就是让程序可以直接读写驱动程序中的 buffer这可以通过 mmap实现(memory map)把内核的 buffer映射到用户态让 APP在用户态直接读写。 19.9.1 内存映射现象与数据结构 假设有这样的程序名为 test.c #include stdio.h #include unistd.h #include stdlib.h int a; int main(int argc, char **argv) { if (argc ! 2) { printf(Usage: %s number\n, argv[0]); return -1; } a strtol(argv[1], NULL, 0); printf(as address 0x%lx, as value %d\n, a, a); while (1) { sleep(10); } return 0; } 在 PC上如下编译(必须静态编译) gcc -o test test.c -staitc 分别执行 test程序 2次最后执行 ps可以看到这 2个程序同时存在这 2个程序里 a变量的地址相同但是值不同。如下图 观察到这些现象 ① 2个程序同时运行它们的变量 a的地址都是一样的0x6bc3a0 ② 2个程序同时运行它们的变量 a的值是不一样的一个是 12另一个是 123。 疑问来了 ① 这 2个程序同时在内存中运行它们的值不一样所以变量 a的地址肯定不同 ② 但是打印出来的变量 a的地址却是一样的。 怎么回事 这里要引入虚拟地址的概念CPU发出的地址是虚拟地址它经过 MMU(Memory Manage Unit内存管理单元)映射到物理地址上对于不同进程的同一个虚拟地址MMU会把它们映射到不同的物理地址。如下图 当前运行的是 app1时MMU会把 CPU发出的虚拟地址 addr映射为物理地址 paddr1用 paddr1去访问内存。 当前运行的是 app2时MMU会把 CPU发出的虚拟地址 addr映射为物理地址 paddr2用 paddr2去访问内存。 MMU负责把虚拟地址映射为物理地址虚拟地址映射到哪个物理地址去 可以执行 ps命令查看进程 ID然后执行“cat /proc/325/maps”得到映射关系。 每一个 APP在内核里都有一个 tast_struct这个结构体中保存有内存信息mm_struct。而虚拟地址、物理地址的映射关系保存在页目录表中如下图所示 解析如下 ① 每个 APP在内核中都有一个 task_struct结构体它用来描述一个进程 ② 每个 APP都要占据内存在 task_struct中用 mm_struct来管理进程占用的内存 内存有虚拟地址、物理地址mm_struct中用 mmap来描述虚拟地址用 pgd来描述对应的物理地址。 注意pgdPage Global Directory页目录。 ③ 每个 APP都有一系列的 VMAvirtual memory 比如 APP含有代码段、数据段、BSS段、栈等等还有共享库。这些单元会保存在内存里它们的地址空间不同权限不同(代码段是只读的可运行的、数据段可读可写)内核用一系列的vm_area_struct来描述它们。 vm_area_struct中的 vm_start、vm_end是虚拟地址。 ④ vm_area_struct中虚拟地址如何映射到物理地址去 每一个 APP的虚拟地址可能相同物理地址不相同这些对应关系保存在 pgd中。 19.9.2 ARM架构内存映射简介 ARM架构支持一级页表映射也就是说 MMU根据 CPU发来的虚拟地址可以找到第 1个页表从第 1个页表里就可以知道这个虚拟地址对应的物理地址。一级页表里地址映射的最小单位是 1M。 ARM架构还支持二级页表映射也就是说 MMU根据 CPU发来的虚拟地址先找到第 1个页表从第 1个页表里就可以知道第 2级页表在哪里再取出第 2级页表从第 2个页表里才能确定这个虚拟地址对应的物理地址。二级页表地址映射的最小单位有 4K、1KLinux使用 4K。 一级页表项里的内容决定了它是指向一块物理内存还是指问二级页表如下图 19.9.2.1 一级页表映射过程 一线页表中每一个表项用来设置 1M的空间对于 32位的系统虚拟地址空间有 4G4G/1M4096。所以一级页表要映射整个 4G空间的话需要 4096个页表项。 第 0个页表项用来表示虚拟地址第 0个 1M(虚拟地址为 00x1FFFFF)对应哪一块物理内存并且有一些权限设置 第 1个页表项用来表示虚拟地址第 1个 1M(虚拟地址为 0x1000000x2FFFFF)对应哪一块物理内存并且有一些权限设置 依次类推。 使用一级页表时先在内存里设置好各个页表项然后把页表基地址告诉 MMU就可以启动 MMU了。 以下图为例介绍地址映射过程 ① CPU发出虚拟地址 vaddr假设为 0x12345678 ② MMU根据 vaddr[31:20]找到一级页表项 虚拟地址 0x12345678是虚拟地址空间里第 0x123个 1M所以找到页表里第 0x123项根据此项内容知道它是一个段页表项。 段内偏移是 0x45678。 ③ 从这个表项里取出物理基地址Section Base Address假设是 0x81000000 ④ 物理基地址加上段内偏移得到0x81045678 所以 CPU要访问虚拟地址 0x12345678时实际上访问的是 0x81045678的物理地址 19.9.2.2 二级页表映射过程 首先设置好一级页表、二级页表并且把一级页表的首地址告诉 MMU。 以下图为例介绍地址映射过程 ① CPU发出虚拟地址 vaddr假设为 0x12345678 ② MMU根据 vaddr[31:20]找到一级页表项 虚拟地址 0x12345678是虚拟地址空间里第 0x123个 1M所以找到页表里第 0x123项。根据此项内容知道它是一个二级页表项。 ③ 从这个表项里取出地址假设是 address这表示的是二级页表项的物理地址 ④ vaddr[19:12]表示的是二级页表项中的索引 index即 0x45在二级页表项中找到第 0x45项 ⑤ 二级页表项格式如下 里面含有这 4K或 1K物理空间的基地址 page base addr假设是 0x81889000 它跟 vaddr[11:0]组合得到物理地址0x81889000 0x678 0x81889678。 所以 CPU要访问虚拟地址 0x12345678时实际上访问的是 0x81889678的物理地址 19.9.3 怎么给APP新建一块内存映射 19.9.3.1 mmap调用过程 从上面内存映射的过程可以知道要给 APP新开劈一块虚拟内存并且让它指向某块内核 buffer我们要做这些事 ① 得到一个 vm_area_struct它表示 APP的一块虚拟内存空间 很幸运APP调用 mmap系统函数时内核就帮我们构造了一个 vm_area_stuct结构体。里面含有虚拟地址的地址范围、权限。 ② 确定物理地址 你想映射某个内核 buffer你需要得到它的物理地址这得由你提供。 ③ 给 vm_area_struct和物理地址建立映射关系 也很幸运内核提供有相关函数。 APP里调用 mmap时导致的内核相关函数调用过程如下 19.9.3.2 cache和 buffer 本小节参考 ARM的 cache和写缓冲器write buffer https://blog.csdn.net/gameit/article/details/13169445 使用 mmap时需要有 cache、buffer的知识。下图是 CPU和内存之间的关系有 cache、buffer(写缓冲器)。Cache是一块高速内存写缓冲器相当于一个 FIFO可以把多个写操作集合起来一次写入内存。 程序运行时有“局部性原理”这又分为时间局部性、空间局部性。 ① 时间局部性 在某个时间点访问了存储器的特定位置很可能在一小段时间里会反复地访问这个位置。 ② 空间局部性 访问了存储器的特定位置很可能在不久的将来访问它附近的位置。 而 CPU的速度非常快内存的速度相对来说很慢。CPU要读写比较慢的内存时怎样可以加快速度根据“局部性原理”可以引入 cache。 ① 读取内存 addr处的数据时 先看看 cache中有没有 addr的数据如果有就直接从 cache里返回数据这被称为 cache命中。 如果 cache中没有 addr的数据则从内存里把数据读入注意它不是仅仅读入一个数据而是读入一行数据(cache line)。 而 CPU很可能会再次用到这个 addr的数据或是会用到它附近的数据这时就可以快速地从 cache中获得数据。 ② 写数据 CPU要写数据时可以直接写内存这很慢也可以先把数据写入 cache这很快。 但是 cache中的数据终究是要写入内存的啊这有 2种写策略 a. 写通(write through) 数据要同时写入 cache和内存所以 cache和内存中的数据保持一致但是它的效率很低。能改进吗可以使用“写缓冲器”cache大哥你把数据给我就可以了我来慢慢写保证帮你写完。 有些写缓冲器有“写合并”的功能比如 CPU执行了 4条写指令写第 0、1、2、3个字节每次写 1字节写缓冲器会把这 4个写操作合并成一个写操作写 word。对于内存来说这没什么差别但是对于硬件寄存器这就有可能导致问题。 所以对于寄存器操作不会启动 buffer功能对于内存操作比如 LCD的显存可以启用 buffer功能。 b. 写回(write back) 新数据只是写入 cache不会立刻写入内存cache和内存中的数据并不一致。 新数据写入 cache时这一行 cache被标为“脏”(dirty)当 cache不够用时才需要把脏的数据写入内存。 使用写回功能可以大幅提高效率。但是要注意 cache和内存中的数据很可能不一致。这在很多时间要小心处理比如 CPU产生了新数据DMA把数据从内存搬到网卡这时候就要 CPU执行命令先把新数据从cache刷到内存。反过来也是一样的DMA从网卡得过了新数据存在内存里CPU读数据之前先把 cache中的数据丢弃。 是否使用 cache、是否使用 buffer就有 4种组合(Linux内核文件 arch\arm\include\asm\pgtable-2level.h) 上面 4种组合对应下表中的各项一一对应(下表来自 s3c2410芯片手册高架构的 cache、buffer更复杂但是这些基础知识没变) 第 1种是不使用 cache也不使用 buffer读写时都直达硬件这适合寄存器的读写。 第 2种是不使用 cache但是使用 buffer写数据时会用 buffer进行优化可能会有“写合并”这适合显存的操作。因为对显存很少有读操作基本都是写操作而写操作即使被“合并”也没有关系。 第 3种是使用 cache不使用 buffer就是“write through”适用于只读设备在读数据时用 cache加速基本不需要写。 第 4种是既使用 cache又使用 buffer适合一般的内存读写。 19.9.3.3 驱动程序要做的事 驱动程序要做的事情有 3点 ① 确定物理地址 ② 确定属性是否使用 cache、buffer ③ 建立映射关系 参考 Linux源文件示例代码如下 还有一个更简单的函数 19.9.4 编程 使用 GIT命令载后本节源码位于这个目录下 01_all_series_quickstart\ 05_嵌入式 Linux驱动开发基础知识\source\ 07_mmap 目的我们在驱动程序中申请一个 8K的 buffer让 APP通过 mmap能直接访问。 19.9.4.1 APP编程 APP怎么写open驱动、bufmmap(……)映射内存直接读写 buf就可以了代码如下 22 /* 1. 打开文件 */ 23 fd open(/dev/hello, O_RDWR); 24 if (fd -1) 25 { 26 printf(can not open file /dev/hello\n); 27 return -1; 28 } 29 30 /* 2. mmap 31 * MAP_SHARED : 多个 APP都调用 mmap映射同一块内存时, 对内存的修改大家都可以看到。 32 * 就是说多个 APP、驱动程序实际上访问的都是同一块内存 33 * MAP_PRIVATE : 创建一个 copy on write的私有映射。 34 * 当 APP对该内存进行修改时其他程序是看不到这些修改的。 35 * 就是当 APP写内存时, 内核会先创建一个拷贝给这个 APP, 36 * 这个拷贝是这个 APP私有的, 其他 APP、驱动无法访问。 37 */ 38 buf mmap(NULL, 1024*8, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 39 if (buf MAP_FAILED) 40 { 41 printf(can not mmap file /dev/hello\n); 42 return -1; 43 } 最难理解的是 mmap函数 MAP_SHARED、MAP_PRIVATE参数。使用 MAP_PRIVATE映射时在没有发生写操作时APP、驱动访问的都是同一块内存当 APP发起写操作时就会触发“copy on write”即内核会先创建该内存块的拷贝APP的写操作在这个新内存块上进行这个新内存块是 APP私有的别的 APP、驱动看不到。 仅用 MAP_SHARED参数时多个 APP、驱动读、写时操作的都是同一个内存块“共享”。 MAP_PRIVATE映射是很有用的Linux中多个 APP都会使用同一个动态库在没有写操作之前大家都使用内存中唯一一份代码。当 APP1发起写操作时内核会为它复制一份代码再执行写操作APP1就有了专享的、私有的动态库在里面做的修改只会影响到 APP1。其他程序仍然共享原先的、未修改的代码。 有了这些知识后下面的代码就容易理解了请看代码中的注释 44 45 printf(mmap address 0x%x\n, buf); 46 printf(buf origin data %s\n, buf); /* old */ 47 48 /* 3. write */ 49 strcpy(buf, new); 50 51 /* 4. read compare */ 52 /* 对于 MAP_SHARED映射: str new 53 * 对于 MAP_PRIVATE映射: str old 54 */ 55 read(fd, str, 1024); 56 if (strcmp(buf, str) 0) 57 { 58 /* 对于 MAP_SHARED映射APP写的数据驱动可见 59 * APP和驱动访问的是同一个内存块 60 */ 61 printf(compare ok!\n); 62 } 63 else 64 { 65 /* 对于 MAP_PRIVATE映射APP写数据时, 是写入另一个内存块(是原内存块的拷贝) 66 */ 67 printf(compare err!\n); 68 printf(str %s!\n, str); /* old */ 69 printf(buf %s!\n, buf); /* new */ 70 } 执行测试程序后查看到它的进程号 PID执行这样的命令查看这个程序的内存使用情况 cat /proc/PIC/maps 19.9.4.2 驱动编程 驱动程序要做什么 ① 分配一块 8K的内存 使用哪一个函数分配内存 我们应该使用 kmalloc或 kzalloc这样得到的内存物理地址是连续的在 mmap时后 APP才可以使用同一个基地址去访问这块内存。(如果物理地址不连续就要执行多次 mmap了)。 ② 提供 mmap函数 关键在于 mmap函数代码如下 要注意的是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。 APP调用 mmap后会导致驱动程序的 mmap函数被调用最终 APP的虚拟地址和驱动程序中的物理地址就建立了映射关系。APP可以直接访问驱动程序的 buffer。 19.9.4.3 上机测试 在 Ubuntu中编译好驱动、测试程序放到开发板。 在开发板上安装驱动、执行测试程序。
http://www.w-s-a.com/news/284702/

相关文章:

  • 网站备案资料查询小型企业管理系统软件
  • 温州网站建设维护怎么做好网站开发、设计
  • 佛山 做网站公司有哪些网站排名忽然不见了
  • 广告网站建设最专业东莞大朗网站设计
  • 网站做流量的论坛贴吧分销商城系统源码
  • 新手建立网站的步骤网站建设费怎么入分录
  • 哪里建网站性价比高做网站赚取广告费
  • 邢台集团网站建设价格微信怎么做捐钱的网站
  • 做网站费用需要分摊吗装修公司一般多少钱一平方
  • 公司主页的网站格式wordpress自动推送给百度
  • 网站建设辶金手指排名十二wordpress 当数据库
  • 无锡手机网站建设服务苏州展厅设计企业
  • 无锡网站制作需要多少钱北京二次感染最新消息
  • 网站开发视频播放无画面杭州房产信息网官网
  • 网站开发 改进如何创建公众号平台
  • wordpress网站响应很慢只有asp网站代码可以重新编译吗
  • 哪个网站教做饭做的好wordpress热点文章
  • 可以做推广东西的网站重庆网站建设 重庆网站制作
  • 珠海网站建设培训学校wordpress去版权 合法
  • 建设食品商购网站学校网站设计实验报告
  • 建个网站多少钱沭阳奥体小区做网站的
  • 广州视频网站建站公司php网页设计作业代码
  • 成都公司网站设计如何制作网址最简单的方法
  • 温州 做网站福建住房城乡建设部网站
  • 网站自动化采集成都网站设计费用
  • 广东专业网站定制建设淘宝网站的人员组织结构
  • 网站改版seo无锡有多少家公司
  • h5美食制作网站模板下载wordpress大学百度云
  • 零陵做网站建立网站的公司平台
  • 某企业电子商务网站建设网站开发实验结论