MMU如何通过虚拟地址找到物理地址-下

news2024/11/25 1:26:44

接着上文:MMU如何通过虚拟地址找到物理地址?

5,虚拟内存到物理内存的推导 本文只介绍最普遍的64位地址,四级页表,每个页表4k的这种情况。

linux内核将一个进程的内存映射表建立好之后,在该进程被调度运行的时候,会将PGD的物理地址放置到MMU的页表基地址寄存器中,在X86_64架构下,该寄存器为CR3,ARM64架构下,该寄存器为ttbr0_el1和ttbr1_el1,接下来的寻址过程中,就不需要linux来干预了,MMU会通过PGD-PUD-PMD-PTE-PAGE-OFFSET这个过程,根据虚拟地址,找到其对应的物理地址。那么这个过程是怎样的呢?

1)我们首先来拆分一下虚拟地址,以“filemap-addr:0x7fc3d3e4c000为例”,0x7fc3d3e4c000被分为5个部分,其中  0-11bit为页内偏移地址,根据页基地址+偏移量找到对应的物理内存; 12-20bit为PTE的索引,该索引可以找到物理内存页面的基地址; 21-29bit为PMD的索引,该索引可以找到PTE的页基地址; 30-38bit为PUG的索引,该索引可以找到PMD的页基地址; 39-47bit为PGD的索引,该索引可以找到PUD的页基地址。首先我们使用命令bc来得到0x7fc3d3e4c000的二进制:

我们将该地址按上述规则拆分一下:PGD索引:11111111,需要左移12bit,得到11111111000,即0x7f8 PUD索引:100001111,需要左移12bit,得到100001111000,即0x878 PMD索引:010011111,需要左移12bit,得到010011111000,0x4f8 PTE索引:001001100,需要左移12bit,得到001001100000,即0x260

注意,PGD,PUD.PMD,PTE的索引都要左移12bit,可以看出来PGD的索引7f8,pud的索引878,PMD的索引4f8,PTE的索引260,都能和vtop给的信息对应上。

我们再使用rd命令直接从内存中读取信息看一下:

从这个过程中,我们可以看到MMU有两个数据信息,即PGD的基地址47de000和虚拟地址0x7fc3d3e4c000,MMU通过PGD+0x7f8找到PUD的地址5f7c000,通过PUD+878得到PMD的地址0x5f66000,通过PMD+4f8得到PTE的地址0x5f64000,通过PTE+260得到物理页面的地址28ba000,本例没有页内偏移量,索引0x7fc3d3e4c000对应的物理地址就是28ba000。2)g-addr:0x4c82f0 转换成二进制

获取索引:

可以看出PGD和PUD的索引为0,PMD索引为0x10,PTE的索引为0x640,都能和vtop给的信息对应上。

在得到页面的基地址0x1f4ed000后,再加上该变量在页内的偏移量之后0x2f0,得到该变量的物理地址0x1f4ed2f0。使用rd命令直接从内存中读取信息看一下

最后再看一下该变量的值:

与代码中赋值相同。

3)stack-addr:0x7ffe03a8ef1c 转换成二进制

获取索引

可以看出来PGD的索引7f8,pud的索引fc0,PMD的索引0e8,PTE的索引470,都能和vtop给的信息对应上。

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linuxc/c++高级开发【直播公开课】

零声白金VIP体验卡:零声白金VIP体验卡(含基础架构/高性能存储/golang/QT/音视频/Linux内核)

在得到页面的基地址0x2940000后,再加上该变量在页内的偏移量之后0xf1c,得到该变量的物理地址2940f1c。使用rd命令直接从内存中读取信息看一下:

4)heap-addr:0x11226f0 最后,我们再看一下堆内变量0x11226f0,先转换成二进制:

获取索引:

可以看出PGD和PUD的索引为0,PMD索引为0x40,PTE的索引为0x910,都能和vtop给的信息对应上。

在得到页面的基地址28b9000后,再加上该变量在页内的偏移量之后0x6f0,得到该变量的物理地址28b96f0。使用rd命令直接从内存中读取信息看一下

最后再看一下物理内存中的值:

与代码中赋值相符。6,内存映射 我们在查阅内存映射关系的资料的时候,通常会找到一个这样一个图:

这个图很清楚的表示了PGD,PUD,PMD和PTE的关系,下面我们把本例中涉及到的地址数据填充进去,效果看起来会更直观和清晰。

7,总结

总结起来,一个变量的寻址过程就是,在编译或运行时被分配虚拟地址和物理内存,内核为该虚拟地址和物理内存的地址以该进程的PGD表为基础,建立映射关系,并将PGD的物理地址交给MMU,MMU根据映射关系通过虚拟地址找到物理地址,并按照程序的要求读写其中的内容。

1)编译和链接 在本例中有四种类型的变量: filemap-addr:0x7fc3d3e4c000 内存映射文件虚拟地址  g-addr:0x4c82f0 全局变量虚拟地址  stack-addr:0x7ffe03a8ef1c 栈内变量虚拟地址  heap-addr:0x11226f0 堆内变量虚拟地址 其中内存映射文件的虚拟地址是内核执行mmap的时候分配的,栈和堆都是在进程创建的时候分配的物理内存并指定了虚拟内存地址,栈内变量和堆内变量的虚拟地址就是堆栈的虚拟地址加上偏移量获得。全局变量的地址是在编译链接的过程中指定的,本例的全局变量没有初始化,所以放在a.out的bss区,bss区的起始虚拟地址为00000000004c82a0:

全局变量g的虚拟地址为:

2)内存页表的建立 在进程创建的时候,内核会为a.out的每个section分配物理内存,堆栈也要分配物理内存,同时根据为进程创建物理内存和虚拟内存的映射关系。最后,把PGD的物理地址放到MMU的页表基地址寄存器中,剩下的事儿交给MMU。可以理解为从虚拟内存到物理内存的转换的逆过程。

3)MMU进行地址转换 从虚拟内存到物理内存的转换是mmu通过页表映射来实现的,无需操作系统干预,本文所讲的寻址过程是最基础的虚拟地址到物理地址的转换过程,但MMU还会利用tlb来优化地址转换的效率,这个不在本文讨论的范围内。

8,其他 本文只介绍了最简单的4级页表,4k页面的映射关系和寻址过程,其实,内核的内存管理还有更复杂的映射,比如使用5级页表,或者每个映射单位为2M或1G的内存块,这些映射方法的索引级数和各级索引所占的bit位都有所不同。

原文作者:Jeff Labs

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

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

相关文章

Lock使用及效率分析(C#)

针对无Lock、Lock、ReadWriterLock、ReadWriterLockSlim四种方式,测试在连续写的情况下,读取的效率(原子操作Interlocked由于使用针对int,double等修改的地方特别多,而且使用范围受限,所以本文章没有测试) …

【高级交换技术】配置QinQ终结子接口接入VLL示例

简介 VLL是建立在MPLS技术上的点到点二层隧道技术,可以在MPLS骨干网上透明传输二层数据,从而使得位于不同物理位置的属于同一个VLAN的站点之间可以相互通信。 QinQ终结子接口接入VLL是指在报文通过VLL网络传输前,先由设备上的路由子接口对设…

【数据分享】2022年我国30米分辨率的坡向数据(免费获取)

地形数据,也叫DEM数据,是我们在各项研究中最常使用的数据之一。之前我们分享过2022年哥白尼30米分辨率的DEM高程数据,该数据被公认为是全球最佳的开源DEM数据之一,甚至没有之一(可查看之前的文章获悉详情)&…

Map中的那些事

Map中的那些事 Map中的那些事拓展时间复杂度O(1):常数级O(logn):对数级O(n):线性级O(nlog n):线性对数级O(n):平方级O(n):立方级O(2的n次方):指数级 hashMaphashMap基本知识哈希冲突的定义hashMap的实现原理hashMap有四个构造器 具体问题HashMap的内部数据结构HashMap允许空键空…

MySQL的各种锁

1. MySQL有遇到过死锁的问题吗?你是如何解决的? 死锁,就是两个或两个以上的线程在执行过程中,去争夺同一个共享资源导致互相等待的现象,在没有外部干预的情况下,线程会一直处于阻塞状态,无法往下…

自动化办公篇之python批量改名

#批量命名 import xlwings as xw app xw.App(visibleFalse,add_bookFalse) workbook app.books.open("测试表.xlsx") for sheet in workbook.sheets:sheet.namesheet.name.replace("彩印之","银河") workbook.save() app.quit()

一篇文章带你用动态规划解决打家劫舍问题

动态规划的解题步骤可以分为以下五步,大家先好好记住 1.创建dp数组以及明确dp数组下标的含义 2.制定递推公式 3.初始化 4.遍历顺序 5.验证结果 根据打家劫舍的题意:两个直接相连的房子在同一天晚上被打劫会触发警报 所以我们制定出核心策略——偷东…

Generalizable NeRF in ICCV‘23

文章目录 前置知识Generalizable《Enhancing NeRF akin to Enhancing LLMs: Generalizable NeRF Transformer with Mixture-of-View-Experts》《WaveNeRF: Wavelet-based Generalizable Neural Radiance Fields》NeO 360: Neural Fields for Sparse View Synthesis of Outdoor …

习题2.18

有点烦了,改个次序做题发博文。今天先发2.18 题目很简单 将列表反序。用clojure来写,还是有点不习惯。忽然想起来,以前面试遇到过面试题,要求用递归函数对数组反序。原来就是想考察这些内容。 因为源语言已经有提供reverse&#…

2023最新接口自动化测试面试题

1、get和post的区别? l http是上层请求协议,主要定义了服务端和客户端的交互规格,底层都是tcp/ip协议 l Get会把参数附在url之后,用?分割,&连接不同参数,Get获取资源,post会把…

Python安装和环境配置教程

进官网根据不同的操作系统,下载适合自己的编译环境(在百度里直接输入Python) 选择安装包(我选择的是3.8.0版本) python官方下载目录中有好多种安装方式,一般情况选择Windows x86-64 executable installer …

酒水茶叶经营小程序商城的作用是什么

酒水茶叶的用户群体非常广,其价格从低到高覆盖了很多人群,对酒厂茶商或经销商来说,在市场高需求的同时,其所遇经营难题也比较明显。 通过【雨科】平台搭建酒水茶叶商城,实现商品线上自营售卖,电脑手机端小程…

缩短从需求到上线的距离:集成多种工程实践的稳定框架 | 开源日报 No.55

zeromicro/go-zero Stars: 25.7k License: MIT go-zero 是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。 go-zero 包含极简的 API 定义和生成工具 goctl,可以根据定义的 api 文件一键生成…

【git】500 Whoops, something went wrong on our end.

在访问公的的git 时出现了500错误提示. 500 Whoops, something went wrong on our end. 哎呀,我们这边出了问题。 TMD 出了什么问题了???一脸懵逼。 登录git 服务器。 查看git的状态。 命令: gitlab-ctl statu…

【AI视野·今日Sound 声学论文速览 第二十四期】Thu, 12 Oct 2023

AI视野今日CS.Sound 声学论文速览 Thu, 12 Oct 2023 Totally 12 papers 👉上期速览✈更多精彩请移步主页 Daily Sound Papers Enhancing expressivity transfer in textless speech-to-speech translation Authors Jarod Duret LIA , Benjamin O Brien LIA , Yanni…

【C++】 局部对象,引用返回

1、new 关键字 会在堆内申请空间,如果仅仅是普通调用构造函数,不会在堆内开辟空间。 2、函数调用会形成栈帧,进行压栈操作,函数调用结束,会进行弹栈。 函数内的局部对象,会随着弹栈,而被销毁(…

关于github申请学生认证-卡在证明上传环节解决方案

在持有学信网英语翻译(30)某宝请人代注册(80) 通过github security log和聊天记录我大致猜想了下做法,前面的学校邮箱其实都好说主要是下面的那个上传照片的环节卡了我很久

生活空间中,餐桌该如何选择?福州中宅装饰,福州装修

餐桌设计 如何选择 不同的餐桌,定义不同的餐桌礼仪 在家的装修设计上, 很多人的关注点是这样的: 玄关收纳要强、客厅颜值要高、阳台功能要全、厨房要好用、卧室要舒适......餐厅、几把椅子一张长桌,够了吧。 餐厅说:“…

20.2 FMC驱动SDRAM的时序初始化实现及内存测试

继续上一篇的话题,写到SDRAM通过CubeMx配置后,在工程代码编写时直接引用的是我事先写好的时序初始化、内存测试文件,而未对其进行详细的解释,所以本篇文章就来娓娓道来。不多说,开始吧 SDRAM的初始化流程简述 SDRAM初…

在不同版本的linx编译erLang时出现./configure使用--prefix指定路径后,总在指定的另前多了/usr/local路径

昨天别的项目同事遇到一个编译遇到在不同linx版本下编译erLang的源码时,其中有一个版本的编译出现在./configure时加入---prefix指定编译后的安装目录,总会在指定的安装另前多了/usr/local的目录,导致无法源码安装到普通用户指定的目录 安装…