一文说清mmap内存映射底层原理(以LCD中的Framebuffer为例)

news2025/1/11 5:48:54

一文说清mmap内存映射底层原理

【目录】
  一、宏观解释内存映射
  二、进程虚拟地址空间
  三、虚拟内存区域描述符
  四、内存映射的实现
  五、mmap在Framebuffer中的应用

前几天的一场面试中,面试官问:为什么可以通过mmap直接操作LCD?
当时回答的不大好,刚学习的时候没有在意底层的逻辑,所以这几天对于mmap内存映射机制进行了较为深入的学习,这里分享出来一些个人的学习记录,如果有不恰当的地方还请各位帮忙指出


一、宏观解释内存映射

  • 虚拟地址空间

每个进程都有虚拟地址空间,且进程和进程之间的地址是独立的

进程看到的都是操作系统虚拟出来的地址空间,但是虚拟地址最终还是要映射在实际的物理内存地址上进行操作的

  • 内存映射

通过mmap将文件或设备使用到的物理地址映射到进程的虚拟地址空间,通过返回的指针即可直接操作到物理地址上的数据

底层是通过页表来实现虚拟地址 --> 物理地址的映射,每个进程都有自己的页表,来管理地址的映射

谁来使用页表呢?MMU(内存管理单元),它来做地址的转换


二、进程虚拟地址空间

  • 每个进程都有4G的虚拟地址空间,其中3G用户空间1G内核空间
  • 内核空间是每个进程共享的,用户空间是独立
    PS:用户态切换到内核态,就是指访问的进程地址从用户空间切换到了的内核空间,系统调用相关数据信息存储在内核空间中
    在这里插入图片描述

咱们借助大模型来看一看,进程的虚拟地址中的 “内核空间” 映射到了哪里
在这里插入图片描述

  • 所以总结出每个进程的虚拟地址空间的内核空间都被映射到了同一块物理内存上,并且通过MMU内存管理单元来管理

    换句话说就是所有进程的虚拟地址空间中的内核空间都是共享的
    在这里插入图片描述

  • 更详细的进程虚拟地址空间示意图(如有侵权,联系删)
    在这里插入图片描述


三、虚拟内存区域描述符

  • task_struct(进程描述符)

    首先,我们的系统是如何管理和调度进程的呢,其实是通过一个结构体:task_struct (进程描述符)

    每个进程都有一个 task_struct 结构体,结构体中包含了:进程状态、进程ID、进程组ID、内存指针、上下文数据等等

    PS:了解更多关于task_struct的信息,可以参考Linux内核源码中的sched.h文件

    struct task_struct {
        volatile long state;	/* -1 unrunnable, 0 runnable, >0 stopped */
        ...
        pid_t pid;
        ...
    	struct mm_struct *mm;  //描述一个进程的整个虚拟地址空间
    	...
    }
    
  • mm_struct (内存描述符)

    该结构体描述了整个进程的虚拟地址空间,通过 vm_area_struct 结构体来管理,以双链表方式

    且保存了当前进程虚拟地址空间的一些信息,比如

    1. pdg:当前进程页表基地址
    2. mmap_base:映射区域基地址
    3. start_code、end_code:代码段的起止地址
    4. start_data、end_data:数据段的起止地址
    5. 等等
    struct mm_struct{
    	struct vm_area_struct *mmap; //list of VMAs: 每个VMA表示一个虚拟地址区域 
        pgd_t   *pgd;                // 当前进程的页表基址
        unsigned long mmap_base;		/* base of mmap area */
        unsigned long start_code, end_code, start_data, end_data;
        ...
    }	
    
  • vm_area_struct (虚拟内存区域描述符)

    该结构体描述了进程某一段虚拟地址空间,其中包括 vm_start(起始虚拟地址)、vm_end(终止虚拟地址)、vm_next(下一段虚拟地址空间)、vm_prev(上一段虚拟地址空间)

    struct vm_area_struct {
    	/* The first cache line has the info for VMA tree walking. */
    	unsigned long vm_start;		/* Our start address within vm_mm:vm_mm内的起始地址 */
    	unsigned long vm_end;		/* The first byte after our end addresswithin vm_mm:在vm_mm内结束地址之后的第一个字节的地址*/
    	/* linked list of VM areas per task, sorted by address */
    	struct vm_area_struct *vm_next, *vm_prev;
        ...
    }
    
  • 示意图(如有侵权,联系删)

在这里插入图片描述


四、内存映射的实现

在进程创建的时候,要申请16K的空间,把用户页表内核页表创建好,然后通过MMU(内存管理单元) 来将进程对虚拟地址的操作落实到真实的物理地址上

  • 通过用户页表来管理我们进程的虚拟地址空间中的用户空间

在这里插入图片描述
操作mmap返回指针的流程示意图:

  • 使用mmap映射物理内存到进程的虚拟内存
  • 会自动更新页表,添加新的虚拟内存到物理内存的映射页表项
  • 当操作mmap返回的指针时,CPU能看到的是进程的虚拟地址,CPU获取到虚拟地址
  • MMU通过该进程的用户空间页表查询到该虚拟地址对应的真实物理地址,然后告诉给CPU
  • CPU无需切换到内核态,直接操作对应的物理地址上的数据

在这里插入图片描述


五、mmap在Framebuffer中的应用

内存映射的实现就不多赘述,mmap在Framebuffer中的应用主要是将LCD驱动申Framebuffer物理内存映射到进程的虚拟内存中,

对mmap返回指针赋值,就会直接将数据写到Framebuffer的物理内存中(看完上面的内容,应该就理解为什么可以直接修改到物理内存了)

另外对于ARM处理来说,内部已经集成了一个LCD控制器,且控制器内部有DMA,可以无需CPU干涉,直接将Framebuffer数据读取,并写入到LCD屏幕上,这样就可以实时显示画面了。

当然,在初始化LCD控制器时需要指定Framebuffer的物理地址和其他读取时的其他属性(比如像素格式是RGB888还是RGB565等,屏幕的尺寸信息等等)
不然LCD控制器也不知道该去哪里读取数据,也不知道该如何使用这些数据。
在这里插入图片描述


参考资料

【Linux驱动mmap内存映射】https://www.cnblogs.com/wanghuaijun/p/7624564.html

【用户进程的页表】https://www.bilibili.com/video/BV1CK411Z7pA

【如何理解虚拟地址空间】https://www.zhihu.com/question/290504400

【进程虚拟地址空间的分布详解 https://blog.csdn.net/Arlingtonroad/article/details/107148527

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

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

相关文章

上海亚商投顾:沪指放量反弹 医药、AI概念股集体走强

上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 一.市场情绪 三大指数早间震荡反弹,午后集体拉升涨超1%,深成指一度涨超1.5%,随后涨幅略…

CSP 202104-1 灰度直方图

答题 就是记录每个数出现的次数&#xff0c;用C的map就行 #include<iostream> #include<map> using namespace std; int main(){map<int,int>h;int n,m,L,a;cin>>n>>m>>L;for(int i0;i<L;i){h[i]0;}while(n--){for(int i0;i<m;i){…

django configparser.NoSectionError: No section: ‘Samples

django configparser.NoSectionError: No section: Samples 背景&#xff1a;Windows下的Django项目&#xff0c;重新部署至Linux ubuntu20中。 samples_white_list eval(config.get(‘Samples’, ‘samples_white_list’)) File “/home/hhl/anaconda3/envs/django/lib/pytho…

Python + Jmeter 实现自动化性能压测

Step01: Python脚本开发 文件路径&#xff1a;D://wl//testproject//Fone-grpc//project1//test_client.py Python 脚本作用&#xff1a; 1.通过 grpc 调用底层 c 的接口&#xff0c;做数据库的数据插入与查询操作&#xff0c;然后将返回的结果进行拼接与输出。 2.代码里面…

optimizer和loss.backward()相关函数

optimizer.zero_grad() # 梯度清零(一定要先进行梯度清零&#xff0c;这样tensor里面的grad就不会累加) loss.backward()是用来求导的 optimizer.step()一般来说根据求来的导数进行梯度下降算法来更新参数 上面的顺序步骤不能变

Idea启动报错start failed闪退, RestfulToolkit-fix插件问题

前一天下班时还在正常使用的Idea&#xff0c;早上再次启动就报错闪退&#xff0c;报错信息非常的快的闪退也没有看清楚。做过的唯一更改就是前一天安装了 RestfulToolkit-fix 插件。 1、先查看报错的日志 在Idea安装路径的bin/ idea.bat文件中末尾处添加pause语句 保存后双击…

Python绘图系统16:动态更新tkinter组件

文章目录 前情提要源代码模式输入序列源码 Python绘图系统&#xff1a; &#x1f4c8;从0开始的3D绘图系统&#x1f4c9;一套3D坐标&#xff0c;多个函数&#x1f4ca;散点图、极坐标和子图自定义控件&#xff1a;极坐标&#x1f4c9;绘图风格&#x1f4c9;风格控件图表类型和…

软件产品(确认)有效性测试的作用和流程

一、基本概述 软件确认测试又称有效性测试&#xff0c;是在模拟的环境下&#xff0c;运用黑盒测试的方法&#xff0c;验证被测软件是否满足需求规格说明书列出的需求。任务是验证软件的功能和性能及其他特性是否与用户的要求一致。对软件的功能和性能要求在软件需求规格说明书…

数据清洗浅谈与理解

1.前言 今天和老同学交流了翻技术&#xff0c;准确的说是争执与讨论&#xff0c;谈到了数据清洗&#xff0c;特此记录一下对清洗的理解&#xff0c;分享与学习 2.数据清洗 下图出自小D课堂&#xff0c;本人也为小D课堂的忠实粉丝 类比现实去理解 ODS &#xff1a;未处理的…

【MapStruct】对象转换

【MapStruct】对象转换 【一】MapStruct带来的改变【二】MapStruct 入门【1】添加依赖【2】po类【3】dto类【4】创建转换接口【5】测试方法【6】运行效果【7】查看编译的class 【三】MapStruct优点分析【1】性能高【2】使用简单【3】代码独立【4】易于 debug 【四】MapStruct使…

【python 多线程】初体验+单线程下载器+多线程并行下载器+ 多进程下载器 以及线程和进程的切换成本比较

前置知识&#xff1a; ref&#xff1a;https://www.osgeo.cn/pillow/reference/ImageFile.html ref&#xff1a;https://blog.csdn.net/weixin_67510296/article/details/125207042 1.多线程初体验 主线程的id和进程的id是一个 查看进程pid下有多少个线程 ps -T -p pid(bas…

《追逐胜利:编程之路上的三子棋游戏实践》

文章目录 前言一、三子棋游戏规则二、步骤详解1.游戏菜单的实现2.棋盘的实现2.1 初始化棋盘2.2 打印棋盘 3.游戏逻辑实现3.1 玩家下棋3.2 电脑下棋 4.判断输赢4.1 win函数实现 5.完整代码 总结 前言 大家好&#xff01;我是艾老虎尤&#xff01;今天我很高兴来和大家分享我最近…

【linux基础(五)】Linux中的开发工具(上)---yum和vim

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:Linux从入门到开通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学更多操作系统知识   &#x1f51d;&#x1f51d; Linux中的开发工具 1. 前言2.…

CMD 命令和 ENTRYPOINT 命令的区别

目录 CMD 命令CMD-shell 形式1. 创建 Dockerfile12. 构建和运行新镜像3. 覆盖 CMD4. 添加命令选项 CMD-exec形式1. 创建Dockerfile2、构建和运行新镜像2.覆盖 CMD和添加命令选项 ENTRYPOINT 命令ENTRYPOINT-shell1. 创建Dockerfile3、构建和运行新镜像2. 覆盖 ENTRYPOINT 和 添…

华为云云耀云服务器L实例评测|了解配置和管理L型云服务器

华为云云耀云服务器L实例配置和管理教程 华为云云耀云服务器L实例的介绍概述特点优势与弹性云服务器&#xff08;ECS&#xff09;的对比 注册和创建L型云服务器注册华为云账号创建L型云服务器实例配置实例参数配置其他参数尝试登录 远程登录 L实例查看公网ip通过本地shell远程连…

QT Pyside2 Designer 的基本使用

文章目录 前言PySide2PySide2 Designer 一、安装PySide2、PyQt5二、使用designer.exe2.1 工具的大致介绍2.2 创建一个新的UI2.3 UI文件另存为/保存(CtrlS)2.4 使用python操作UI文件 总结 前言 PySide2 QT PySide2 是一个用于 Python 编程语言的开源框架&#xff0c;它提供了与…

【建站教程】使用阿里云服务器怎么搭建网站?

使用阿里云服务器快速搭建网站教程&#xff0c;先为云服务器安装宝塔面板&#xff0c;然后在宝塔面板上新建站点&#xff0c;阿里云服务器网以搭建WordPress网站博客为例&#xff0c;阿小云来详细说下从阿里云服务器CPU内存配置选择、Web环境、域名解析到网站上线全流程&#x…

(10)(10.9) 术语表(一)

文章目录 前言 1 2.4Ghz 2 AGL 3 AHRS 4 APM 5 AMA 6 Arduino 7 APM (AutoPilot Mega) 8 ATC 9 Copter 10 Plane 11 Rover 12 BEC 13 Bootloader 14 COA 15 DCM 16 Eagle file 17 ESC 18 Firmware 19 FPV 20 FTDI 前言 &#xff01;Note 术语表未编入索…

C++零碎记录(十二)

22. 菱形继承 22.1 菱形继承简介 ① 菱形继承概念&#xff1a; 1. 两个派生类继承同一个基类 2. 又有某个类同时继承两个派生类 3. 这种继承被称为菱形继承 ② 羊继承了动物的数据&#xff0c;驼同样继承了动物的数据&#xff0c;当草泥马使用数据是&#xff0c;就会产生二义…

重构:在新底座之上让应用重生

应用重构正在开启一条云原生时代的新赛道。 数字化发展到今天&#xff0c;企业面临的挑战不仅来自技术层面&#xff0c;更来自认知层面。新架构、新应用正在重新定义数字生产力&#xff0c;重塑商业模式与市场核心竞争力。对金融行业来说&#xff0c;也是如此&#xff0c;一场…