JIURL文档-Linux的虚拟内存与分页机制(x86-64位)(一)

作者:JIURL

日期:2015年10月30日

 

分页机制


    Linux(x64CPU)使用基于分页机制的虚拟内存。每个进程有256TB(48位)的虚拟地址空间。基于分页机制,这256TB地址空间的一些部分 被映射了物理内存,一些部分什么也没有映射。程序中使用的都是256TB地址空间中的虚拟地址。而访问物理内存,需要使用物理地址。

   物 理地址(physical address):放在寻址总线上的地址。放在寻址总线上,如果是读,电路根据这个地址每位的值就将相应地址的物理内存中的数据放到数据总线中传输。如果 是写,电路根据这个地址每位的值就将相应地址的物理内存中放入数据总线上的内容。物理内存是以字节(8位)为单位编址与寻址的。

    虚拟地址(virtual address): 256TB虚拟地址空间中的地址,程序中使用的都是虚拟地址。

   如 果CPU相关寄存器中的分页标志位被设置,那么执行内存操作的机器指令时,CPU会自动根据相应转换结构(PML4,PDPT,PD,PT)中的信息,把 虚拟地址转换成物理地址,完成该指令。比如"mov eax,dword ptr[13FF3904Ch]",就是把地址13FF3904Ch处的值赋给寄存器的汇编代码,13FF3904Ch这个地址就是虚拟地址。CPU在执 行这行代码时,发现寄存器中的分页标志位已经被设定,就自动完成虚拟地址到物理地址的转换,使用物理地址取出值,完成指令。对于x86-64CPU 来说,寄存器CR0的第31位是分页标志位,为1表示使用分页,为0表示不使用分页。对于初始化之后的 Linux 我们通过qemu monitor 观察 CR0,发现第31位的值为1。表明Linux是使用分页的。有多个寄存器中的控制位与分页有关,具体细节可以参考Intel软件开发手册。

    x86-64 CPU的实际虚拟地址大小为48位(64位中的低48位,高16位不用于地址转换),可寻址256TB地址空间。x86-64 CPU的实际物理地址大小,不同的CPU不相同,但最大不超过52位。可以通过机器指令cpuid来查询该CPU的实际虚拟地址长度和实际物理地址长度。 例如,我查询了两台计算机,虚拟地址的大小两台计算机都为0x30(16进制30就是十进制48),物理地址的大小一台计算机为0x24(16进制24就 是十进制36,36位可寻址64GB),另一台计算机为0x27(16进制27就是十进制39,39位可寻址512GB)。为了后面的叙述方便,我们把 CPU实际物理地址的位数叫做M,比如,对于物理地址大小为36位的CPU,M就是36。

   使用了分页机制之后,256TB的地址空 间被分成了固定大小的页(有三种大小,4KB,2MB,1GB),每一页或者被映射到物理内存,或者没有映射任何东西。对于一般程序来说,256TB的地 址空间,只有一小部分(沧海一粟)映射了物理内存,大片大片的部分是没有映射任何东西。物理内存也被分页,来映射地址空间。对于x86-64,页的大小有 三种,分别是4KB,2MB,1GB。CPU用来把虚拟地址转换成物理地址的信息存放在叫做"page map level 4"," page directory pointer","pagedirectory"(页目录),"pagetable"(页表)的结构里。每个进程都有自己的一套 PML4,PDPT,PD,PT结构。一个进程中的虚拟地址,最多需要四级转换,来得到对应的物理地址。

   物理内存分页,一个物理页 的大小为4KB,第0个物理页从物理地址 0x0000000000000000处开始,大小为4KB(0x1000B),第1个物理页从物理地址 0x0000000000001000 处开始。第2页从物理地址0x0000000000002000处开始。由于页的大小是4KB,所以只需要64位的地址中的M-12bit(低12bit 之后)来寻址物理页。

    "pagetable"(页表),一个页表的大小为4KB,放在一个物理页中。由512个8字节的PTE(页表项)组成。页表项的大小为8个字节(64 位),所以一个页表中有512个页表项。页表中的每一项的内容(每项8个字节,64位)低12位之后的M-12位用来放一个物理页的物理地址,低 12bit放着一些标志。

    "pagedirectory"(页目录),一个页目录大小为4KB,放在一个物理页中。由512个8字节的PDE(页目录项)组成。页目录项的大小为8 个字节(64位),所以一个页目录中有512个页目录项。页目录中的每一项的内容(每项8个字节,64位)低12位之后的M-12位用来放一个页表(页表 放在一个物理页中)的物理地址,低12bit放着一些标志。

    "pagedirectory pointer"表,一个page directorypointer表大小为4KB,放在一个物理页中。由512个8字节的PDPTE项组成。PDPTE项的大小为8个字节(64位),所 以一个pagedirectory pointer表中有512个PDPTE。page directorypointer表中的每一项的内容(每项8个字节,64位)低12位之后的M-12位用来放一个页目录(页目录放在一个物理页中)的物 理地址,低12bit放着一些标志。

    "page maplevel 4"表,一个page map level4表大小为4KB,放在一个物理页中。由512个8字节的PML4E项组成。PML4E项的大小为8个字节(64位),所以一个pagemap level 4表中有512个PML4E。page map level4表中的每一项的内容(每项8个字节,64位)低12位之后的M-12位用来放一个page directory pointer表(pagedirectory pointer表放在一个物理页中)的物理地址,低12bit放着一些标志。

   对于x86-64系统,"page map level 4"表的物理地址放在CPU的CR3寄存器中。

   CPU把虚拟地址转换成物理地址:
   一 个虚拟地址,大小8个字节(64位,实际只使用低48位),包含着找到物理地址的信息,分为5个部分:第39位到第47位这9位(最高9位) 是"pagemap level 4"表中的索引,第30位到第38位这9位是"page directorypointer"表中的索引,第21位到第29位这9位是页目录中的索引,第12位到第20位这9位是页表中的索引,第0位到第11位 这12位(低12位)是页内偏移。对于一个要转换成物理地址的虚拟地址,CPU首先根据CR3中的值,找到"pagemap level4"表所在的物理页,然后根据虚拟地址的第39位到第47位这9位(最高9位)的值作为索引,找到相应的PML4E项,PML4E项中有这个虚 拟地址所对应的"pagedirectory pointer"表的物理地址。有了"page directorypointer"表的物理地址,根据虚拟地址的第30位到第38位这9位的值作为索引,找到该"page directorypointer"表中相应的PDPTE项,PDPTE项中有这个虚拟地址所对应的页目录的物理地址。有了页目录的物理地址,根据虚拟地 址的第21位到第29位这9位的值作为索引,找到该页目录中相应的页目录项,页目录项中有这个虚拟地址所对应的页表的物理地址。有了页表的物理地址,根据 虚拟地址的第12位到第20位这9位的值作为索引,找到该页表中相应的页表项,页表项中有这个虚拟地址所对应的物理页的物理地址。最后用虚拟地址的最低 12位,也就是页内偏移,加上这个物理页的物理地址,就得到了该虚拟地址所对应的物理地址。

    一个"page maplevel 4"表有512项,虚拟地址从48位向低走的9位刚好可以索引512项(2的9次方等于512),一个"pagedirectorypointer"表有 512项,虚拟地址接下来的9位刚好索引512项。一个页目录有512项,虚拟地址接下来的9位刚好索引512项。一个页表有512项,虚拟地址接下来的 9位刚好索引512项。虚拟地址最低的12位(2的12次方等于4096),作为页内偏移,刚好可以索引4KB,也就是一个物理页中的每个字节。

   一 个虚拟地址转换成物理地址的计算过程就是,处理器通过CR3找到当前"page map level4"表所在物理页,取虚拟地址从48位向低走的9位,然后把这9位右移3位(因为每个PML4E项8个字节长,右移3位相当于乘8)得到在该页 中的地址,取出该地址处的PML4E(8个字节),就找到了该虚拟地址对应"pagedirectorypointer"表所在物理页,然后同样方法依次 找出该虚拟地址对应的页目录所在物理页,该虚拟地址对应的页表所在物理页,该虚拟地址对应的物理页的物理地址,最后将虚拟地址对应的物理页的物理地址加上 12位的页内偏移得到了物理地址。

   48位的一个指针,可以寻址范围0x000000000000-0xFFFFFFFFFFFF,256TB大小。也就是说一个48位的指针可以寻址整个256TB地址空间的每一个字节。
一个页表项负责4KB的地址空间和物理内存的映射,一个页表512项,也就是负责512*4KB=2MB的地址空间的映射。
一个页目录项,对应一个页表。一个页目录有512项,也就对应着512个页表,每个页表负责2MB地址空间的映射,512个页表负责512*2MB=1GB的地址空间映射。
一个PDPTE项,对应一个页目录。一个"page directorypointer"表有512项,也就对应着512个页目录,每个页目录负责1GB地址空间的映射。512个页目录负责512*1GB=512GB的地址空间映射。
一 个"page map level 4"表项,对应一个"page directory pointer"表。一个"page maplevel 4"表有512项,也就对应着512个"page directory pointer"表,每个"page directorypointer"表负责512GB地址空间的映射。512个"page directorypointer"表负责512*512GB=256TB的地址空间映射。
一个进程有一个"page map level4"表。所以以页为单位,一套PML4,PDPT,PD,PT结构可以保证256TB的地址空间中的每页和物理内存的映射。

   一 个虚拟地址在转换过程中,如果发现对应的PDPTE项的PS位为0则继续之后的转换步骤,如果发现对应的PDPTE项的PS位为1,则本PDPTE项中的 物理地址,就是该虚拟地址对应的一个大小为1GB物理页的地址,该虚拟地址之后的30位为这个1GB物理页的页内偏移,就可以得到该虚拟地址对应的物理地 址。

   一个虚拟地址在转换过程中,如果发现对应的页目录项的PS位为0则继续之后的转换步骤,如果发现对应的页目录项的PS位为1, 则本页目录项中的物理地址,就是该虚拟地址对应的一个大小为2MB物理页的地址,该虚拟地址之后的21位为这个2MB物理页的页内偏移,就可以得到该虚拟 地址对应的物理地址。

   虚拟地址48位,寻址256TB。48位地址:9bit+9bit+9bit+9bit+12bit。
每一级表的大小都为4KB。表项大小8B(64位),所以每个表512项。
4级转换:CR3-> "page map level 4"表-> "page directorypointer"表-> 页目录-> 页表-> 得到物理地址。
一个PTE项对应4KB地址范围。一张PT表对应512*4KB=2MB地址范围。
一个PDE项对应2MB地址范围。一张PD表对应512*2MB=1GB地址范围。
一个PDPTE项对应1GB地址范围。一张PDPT表对应512*1GB=512GB地址范围。
一个PML4E项对应512GB地址范围。一张PML4表对应512*512GB=256TB地址范围。
页大小有3种,4KB,2MB,1GB。

   每 个进程都有自己的256TB地址空间,"0000000000000000 - 00007fffffffffff" 和"ffff800000000000 - ffffffffffffffff" 。因为CPU会忽略高16位,所以相当于"000000000000 - 7fffffffffff" 和 "800000000000 -ffffffffffff"。
因为CPU有特殊规定,被忽略的高16位的每一 位必须等于第47位的值(并会做检查,不符合规定将引发异常)。"000000000000 -7fffffffffff"的第47位是0,所以高16位也必须都为0。"800000000000 -ffffffffffff"的第47位是1,所以高16位也必须都为1。
每个进程都有自己的256TB地址空间,通过每个进程自己的一套 PML4,PDPT,PD,PT结构来实现。由于每个进程有自己的一套PML4,PDPT,PD,PT结构,所以每个进程的地址空间映射的物理内存是不一 样的。两个进程的同一个虚拟地址处(如果都有物理内存映射)的值一般是不同的,因为他们往往对应不同的物理页。

   256TB地址空间 中低128TB,0x000000000000-0x7fffffffffff是用户地址空间,256TB地址空间中高 128TB,0x800000000000-0xffffffffffff是系统地址空间。访问系统地址空间需要程序有ring0的权限。

未完待续...

微博:http://weibo.com/ddqqppb
邮箱:thejiurl@163.com
QQ:6291898

欢迎交流。

 

转载于:https://www.cnblogs.com/jiurl/p/4925007.html

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

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

相关文章

[react] React怎样跳过重新渲染?

[react] React怎样跳过重新渲染? 生命周期 shouldComponentUpdate return false ? 个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

C++之deque

From: http://blog.csdn.net/zxjzxj521/article/details/8172953 1 什么是STL STL就是C Standard Template Library,也就是标准模版库,是一个高效的C程序库。STL包含六大组件:容器(container)、算法(algor…

STM32 设置片外SRAM分散加载

STM32F407 通过FSMC外挂一片SRAM 容量1MB, 设置应用程序的中的超大数组存放在外部SRAM。 (1)首先通过设置FSMC,保证正确挂接SRAM。 (2)MDK设置 (3)应用程序用__attribute__指定需要…

.NET4.0 之 Dynamic VS Refle“.NET研究”ction 效率

在我先前的文章中,不断的推广.NET4.0新特性。特别是.NET4.0 Dynamic 这个新特性。随之而来的问题也出现了—Dynamic 执行效率如何? 我们做开发的不光需要代码简洁,能够希望自己能够写出好的架构。还有一点非常重要的就是,我们的写…

[react] 经常用React,你知道React的核心思想是什么吗?

[react] 经常用React,你知道React的核心思想是什么吗? 一切皆组件 数据驱动视图 单向数据流 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

高性能I/O设计模式

http://blog.csdn.net/chexlong/article/details/22417079转载于:https://www.cnblogs.com/fight-tao/p/4925705.html

回调函数总结(个人见解)

回调函数总结(个人见解):1. 回调函数的实现 > 被调用者写2. 写库的人 > 调用回调函数的人 > 调用者2.1 调用者: 1) 不关心谁是被调用者2) 只关心回调函数的原型及返回值3) 声明回调函数的接口,回调函数的实现交给被调用者去处理2.2 被…

lwip+freeRTOS 无法ping通的解决方案

0、工程环境 STM32F407ZGT6LAN8720FreeRTOSlwIP 1、硬件 (1)确认PHY芯片RMII管脚是否配置正确; (2)PHY芯片初始化完成后,用HAL_ETH_ReadPHYRegister读一下寄存器0,1,2&#xff0c…

数据流图

数据流图(Data Flow Diagram,简称DFD)是一种图形化技术,它描绘信息流和数据从输入移动到输出的过程中所经历的变换,其既提供了功能建模机制也提供了信息建模机制。是结构化系统分析方法的主要表达工具及用于表示软件模型的一种图示方法。 它以…

[react] 你对immutable有了解吗?它有什么作用?

[react] 你对immutable有了解吗?它有什么作用? 让 react 的渲染符合预期,比如我们使用 ref 保留对象引用后,传递给子组件渲染,如果这是对象内的属性变更,不会触发子组件重新渲染,如果使用 immu…

lwip+freeRTOS 实现热插拔功能

1、lwip启用LWIP_NETIF_CALLBACK 宏,cubeMX会自动生成相关函数()。 /* Set the link callback function, this function is called on change of link status*/netif_set_link_callback(&gnetif, ethernetif_update_config); 回调函数在v…

iOS设计模式 - 享元

iOS设计模式 - 享元 原理图 说明 享元模式使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结…

C# 视频监控系列(11):H264播放器——封装API[HikPlayM4.dll]

前言 当你认真的写完客户端和服务器端的时候可能不需要再继续往下看关于播放器的代码和说明,因为你已经掌握了如何转换VC代码的技巧了,加上GOOGLE再来完成这个播放器应该算小菜了。但是作为我的系列,我还是有必要认真的将这部分写完才算完整&…

[react] React16废弃了哪些生命周期?为什么?

[react] React16废弃了哪些生命周期?为什么? React16废弃的生命周期有3个will: componentWillMount componentWillReceiveProps componentWillUpdate 废弃的原因,是在React16的Fiber架构中,调和过程会多次执行will周…

lwip+freeRTOS 故障容错 客户端主动发起连接

1、简单的需求 STM32终端为tcp客户端,主动向TCP服务器发起连接,然后进行通信。 流程:STM32网卡初始化-----lwIP初始化--------DHCP-------------creat socket Client-------send-------recv 2、实际情况 (1)如何处…

JS正则表达式大全【转】

正则表达式中的特殊字符 字符 含意 \ 做为转意,即通常在"\"后面的字符不按原来意义解释,如/b/匹配字符"b",当b前面加了反斜杆后/\b/,转意为匹配一个单词的边界。 -或- 对正则表达式功能字符的还原&#xff0c…

C++回调函数用法

From: http://blog.csdn.net/wubin1124/article/details/4386269 一回调函数 我们经常在C设计时通过使用回调函数可以使有些应用(如定时器事件回调处理、用回调函数记录某操作进度等)变得非常方便和符合逻辑,那么它的内在机制如何呢&#x…

[react] 举例说明什么是高阶组件(HOC)的属性代理

[react] 举例说明什么是高阶组件(HOC)的属性代理 function HOC(WrappedComponent) {return class HOC extends Component {render() {const newProps { type: HOC };return <div><WrappedComponent {...this.props} {...newProps} /></div>}} }hoc class O…

树莓派使用STEP8:使能串口调试

1、打开SD卡根目录"config.txt"文件&#xff0c;文末增加dtoverlaypi3-miniuart-bt并且保存 &#xff1b; 2、修改根目录"cmdline.txt"&#xff0c;清空原内容&#xff0c;增加 dwc_otg.lpm_enable0 consoletty1 consoleserial0,115200 root/dev/mmcblk0p…

【C++模板】特化与偏特化 template [partial] specialization

1 template specialization 模板特化 一般情况下类模板定义如下&#xff1a; template<class Window, class Controller> class Widget {... 泛化实现代码 ... };特化是指把类模板中指定的class T变成具体的类型&#xff1a;class Widget<ModalDialog, MyController&g…