LinuxGod.net
Linux大神网——精选每一篇高品质的技术干货
  1. 首页
  2. 开源快讯
  3. 正文

3.3.mmap完成物理地址映射到用户虚拟地址空间上文件对应硬件外设

2022年12月4日 708点热度

3.3.mmap地址映射方法

明确:mmap就是完成物理地址映射到用户虚拟地址用的

明确:用户3G虚拟地址空间划分:

0x00000000-------------------------------------------------------0xBFFFFFFF

代码段 数据段 BSS段 堆区 MMAP虚拟内存区 栈区

---->

1.回顾mmap系统调用函数

函数原型:

void *mmap(void *addr, size_t length,

int prot, int flags,

int fd, off_t offset);

函数功能:将物理地址空间映射到用户虚拟内存空间上

将物理地址映射到用户虚拟地址

老王课程这么讲:将文件映射到用户虚拟地址空间上

文件对应硬件外设,外设通过物理地址访问

linux系统不允许访问物理地址,利用mmap映射不得了

参数:

addr:给NULLlinux 驱动通知应用层,让linux内核帮你在用户虚拟内存区域找一块

空间内存用来映射物理地址

length:让linux内核帮你找的空闲用户虚拟内存的大小

切记:大小必须是页面大小(4KB)的整数倍

prot:描述内核帮你找的空闲用户虚拟内存的访问权限

一般指定为:PROT_READ|PROT_WRITE

flags:其余属性,一般指定为:MAP_SHARED

fd:硬件外设

linux 驱动通知应用层_开发linux应用--用gtk+和gdk开发linux图形用_dz全站弹出层通知

offset:偏移量,一般给0

返回值:linux内核将空闲的用户虚拟内存的首地址进行返回

这个起始用户虚拟地址同样也是4KB整数倍

参考代码:

void *addr;

int fd = open("a.txt", O_RDWR);

addr = mmap(NULL, 0x1000, PROT_READ|PROT_WRITE,

MAP_SHARED, fd, 0);

说明:将文件a.txt映射到以addr起始的用户虚拟内存上

将来访问映射的用户虚拟内存就是访问文件

//向映射的用户虚拟内存拷贝字符串数据

本质是向文件a.txt写入数据

memcpy(addr, "hello,world", 12);

2.了解mmap系统调用函数所做的工作:

2.1.应用程序调用mmap,首先跑到C库的mmap函数定义

2.2.C库的mmap函数作两件事:

1.保存mmap系统调用号到r7寄存器

2.调用swi/svc指令触发软中断异常

2.3.一旦触发软中断异常,CPU核立马处理软中断异常

2.4.最后进程跑到内核空间继续运行,跑到软中断异常的入口地址

运行,做如下事情:

1.调用软中断异常处理函数,而此函数做两件事:

1.从r7寄存器中取出mmap系统调用号

2.以mmap系统调用号为下标在内核的系统调用表中

找到mmap对应的内核函数sys_mmap,而内核的

sys_mmap做三件事:

1.内核的sys_mmap首先在当前进程的3G虚拟地址空间中

找一块空闲的用户虚拟内存,将来用于和物理地址

做映射

2.一旦找到空闲的用户虚拟内存,并且用户mmap本身

也给用户虚拟内存指定了一堆的属性(大小,权限等)

所以内核用struct vm_area_struct数据结构定义

初始化一个对象来描述空闲的用户虚拟内存的属性

struct vm_area_struct {

unsigned long vm_start; //空间用户虚拟内存的起始地址

//等于mmap的返回值addr

unsigned long vm_end; //结束地址=vm_start+大小

pgprot_t vm_page_prot; //等于mmap传递的PROT_READ|PROT_READ|PROT_WRITE

unsigned long vm_flags; //等于mmap传递的MAP_SHARED

unsigned long vm_pgoff; //等于mmap传递的0

...

};

3.最后内核的sys_mmap调用底层驱动的mmap接口

并且内核sys_mmap将第2步创建的对象的地址

也传递给底层驱动的mmap接口

3.底层驱动mmap执行完毕,进程返回,至此mmap调用结束

3.对应的底层驱动的mmap接口

struct file_operations {

int (*mmap) (struct file *file,

struct vm_area_struct *vma);

dz全站弹出层通知_linux 驱动通知应用层_开发linux应用--用gtk+和gdk开发linux图形用

};

接口功能:永远只能唯一做一件事:将已知的物理地址和已知的

用户虚拟地址做映射,类似:媒婆

由于用户虚拟地址在用户空间,所以将来访问操作

都是在应用程序完成,而不是在内核驱动完成

访问映射的用户虚拟地址就是在访问物理地址

file:跟fd亲戚关系

vma:指向内核sys_mmap创建的一个对象,此对象来描述空闲的

用户虚拟内存的各种属性,将来底层驱动mmap接口利用

此指针可以获取到用户虚拟内存的属性:

vma->vm_start //获取起始用户虚拟地址

vma->vm_end

vma->vm_flags

vma->vm_page_prot

...

问:底层驱动的mmap接口到底如何最终完成映射呢?

因为已知物理地址可以看手册获取到

已知的用户虚拟地址通过vma指针能够获取到

如何将两者关联在一起呢?

万事俱备只欠东风

答:只需调用以下函数完成关联映射:

int remap_pfn_range(struct vm_area_struct *vma,

unsigned long addr,

unsigned long pfn,

unsigned long size,

linux 驱动通知应用层_dz全站弹出层通知_开发linux应用--用gtk+和gdk开发linux图形用

pgprot_t prot);

函数功能:完成最终的地址映射

vma:传递内核sys_mmap创建的对象地址

也就是传递驱动mmap接口的第二个参数

addr:传递空闲的用户虚拟内存的首地址

也就是传递vma->vm_start

pfn:传递起始的物理地址>>12

切记:此物理地址大小必须是4KB(0x1000)整数倍

例如:

0xC001C000>>12:合法

0xC001C004>>12:不合法

size:传递映射的用户虚拟内存的大小

也就是传递:vma->vm_end - vma->vm_start

prot:传递用户虚拟内存的访问权限

也就是传递:vma->vm_page_prot

案例:利用mmap实现开关灯操作

参考代码:day09/1.0

dz全站弹出层通知_开发linux应用--用gtk+和gdk开发linux图形用_linux 驱动通知应用层

linux 驱动通知应用层_开发linux应用--用gtk+和gdk开发linux图形用_dz全站弹出层通知

linux 驱动通知应用层_dz全站弹出层通知_开发linux应用--用gtk+和gdk开发linux图形用

4.世纪大PK:read,write,ioctl和mmap对比

什么时候用:read,write,ioctl

什么时候用: mmap

4.1.read,write,ioctl数据操作流程

对设备读操作:read,ioctl

开发linux应用--用gtk+和gdk开发linux图形用_linux 驱动通知应用层_dz全站弹出层通知

数据流:硬件寄存器----->内核缓冲区------->用户缓冲区

gpio_get_value copy_to_user

对设备写操作:write,ioctl

数据流:用户缓冲区----->内核缓冲区------->硬件寄存器

copy_from_user gpio_set_value

结论:read,writelinux 驱动通知应用层,ioctl数据操作势必要经过两次数据拷贝:

用户-内核->硬件

硬件->内核->用户

4.2.mmap数据操作流程:

对设备读操作: 应用程序直接以指针形式读取寄存器

data = *gpiocout;

对设备写操作: 应用程序直接以指针的形式写入寄存器

*gpiocout &= ~(1 硬件

硬件->用户

4.3.终极结论:

1.如果用户对硬件操作访问的数据量比较小,read,write,ioctl

的两次数据拷贝对系统性能肯定有影响,但是这种影响几乎

可以忽略不计,如果操作的数据量比较大,两次数据拷贝

性能的影响是致命的,例如:摄像头linux更改ip地址,LCD显示屏,声卡等

2.如果访问操作的数据量比较大linux 发邮件,用read,write,ioctl势必

影响系统的性能,务必采用mmap,将两次数据拷贝变成一次

提供系统的性能效率

3.由于mmap在使用的时候,分配的用户虚拟内存必须是4KB的

整数倍,如果操作的数据量比较小,此时还用mmap

即使提高了系统的性能(几乎体会不到),反而是浪费了

宝贵的内存资源

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: mmap 内存映射 对象关系映射 空间数据 虚拟内存
最后更新:2022年12月4日

Linux大神网

每日更新,欢迎收藏♥ 不积跬步无以至千里,加油,共勉。

点赞
< 上一篇
下一篇 >

Linux大神网

每日更新,欢迎收藏♥
不积跬步无以至千里,加油,共勉。

最新 热点 随机
最新 热点 随机
【】原操作系统配备内核源代码,更不能进行内核模块实验 【Linux基础知识】与文件权限管理的Linux关系 linux/管理员管理员发布于5年前34(图) Linux和Unix操作系统之间有区别但也有联系?(一) Ubuntu系统如何升级和更新Linux内核版本?将推荐 Linux内核技术组成、组织和重要的数据结构等(组图) 【报错日志】一下升级linux内核的启动顺序为0 Linux终端窗口中输入mysql-V以显示MySQL版本信息sky 计算机操作系统全新版装系统盘点、理念与系统的优缺点 linux中常用的用户管理命令:1groups?列出当前用户所属 Linux下如何设置开机启动启动脚本?学算法 Linux中已经安装好了mysql命令 Linux系统用户系统上的三种类型的帐户的介绍 Linux下的开机启动设置方法是什么?脚本或服务 谷歌更新Linux内核构建的公共内核库:添加对kokoro作业的支持 linux下mysql中可以使用REVOKE语句来删除某个用户的权限 内核的角度来看,调用hotplug和通常的hotplug环境 Linux系统在开机的时候自动加载某些脚本或系统服务 如何在Linux上安装Diablo3操作系统Diablo3 RedHatLinux软件安装包软件后缀为.rpm最初
Linux5.12的推送请求不断涌入新开放的合并窗口预计4月底看到它的稳定版本go语言被称作互联网时代的c语言,用来开发嵌入式linux的理由腾讯云服务器上也搭建一套环境,安装成功自动启动个人笔记本安装Ubuntu20.04LTS下载地址启动第一步--加载BIOS当你打开计算机电源(组图)虚拟机安装Ubuntu操作系统-Ubuntu空间20G镜像下载指令中各个make-C~/linuxM=`pwd编译Linux启动过程中的几个部分内核的引导(图)如何在Linux上安装虚拟机的结果大多都是怎么安装的一个免费软件时间跟进的小白鼠是什么鬼?专题计算机是如何启动的?、内核操作系统的启动流程学习Linux最简单、最实用的环境就是虚拟机环境(上)基于命令修改文件的权限命令-ld1.Linux磁盘分区和目录Linux发行版本之间的差别很少?国内性价比很高的Linux虚拟主机系统安装的流程是什么?Linux下修改文件权限的权限与所有权的实现就显得很有必要linux到底难不难学呢?推荐可以查看Linux命令大全Linux中修改文件权限的命令、创建者所在组、所有人Linux的内核放在了哪里?/boot的启动目录一览阿里云>社区>主题地图S>查看存储推荐
手机上可以安装完整的Linux系统吗?/VNC 统信UOS为啥火?国产操作系统又该如何发展?(组图) linux到底难不难学呢?推荐可以查看Linux命令大全 《Linux命令全集》之Linux命令解释和例子 华为手机刷机软件V1.2.5官方版软件说明软件介绍 linux设备驱动开发详解–基于linux4.0内核设备树是一种描述硬件的数据结构 聊聊我们建站主机选择Windows还是Linux系统的问题(图) 什么是Windows系统MicrosoftWindows,linux系统和windows系统的区别 【干货】Linux下的线程是什么?(二) Linux用户来说意味着什么?简单来说,实际上意味着即白 网易云音乐2021旧版本:听歌必备小神器,多种热门音乐提供给你 审计Linux系统日志可以提供有关网络事件的重要信息(图) 如何不重新编译整个内核支持某个功能,对系统无影响编译 ubuntu如下系统的配置 Linux基础命令推荐书籍:《Linux就该这么学》 【1024】后端技术学习路线思维导图,看这一篇就够了! Linux用户与文件权限操作实例第1页/共15页任务要求 Linux下程序的存放目录和安装目录 0005编程精粹-Microsoft编写优质无错程序秘诀(bjchenxu) 一个免费软件时间跟进的小白鼠是什么鬼?专题
标签聚合
linux服务器 linux系统 电脑 命令模式 sudo 软件 unix 文件目录 shell 虚拟机
书籍
课程
技术群
技术干货大合集↓
  • 2023年2月 / 24篇
  • 2023年1月 / 161篇
  • 2022年12月 / 187篇
  • 2022年11月 / 76篇

COPYRIGHT © 2023 linuxgod.net ALL RIGHTS RESERVED.