首先,在x86架构的处理器上,一个正常页面大小为4KB,非PAE模式下,CR3持有页目录页面的物理地址,PDE和PTE格式相同大小为4字节。此时每个页表页面包含1024个PTE,可以映射1024个页面。而x86的4GB地址空间共包含1M个4KB的页面,映射所有这些页面共需要1024个页表页面,映射这1024个页表页面又需要1个页目录页面。乍看起来我们一共需要1025个页面来管理1M个页面的映射,其实不然。

我们不妨逆向理顺一下思路。首先,我们的地址空间中有1M=1024x1024个页面,而一个页表页面可以映射1024个页面。所以,我们把4GB地址空间的1M个页面按每1024个页面分为1024组。映射这1024组页面正好需要1024个页表页面,所以我们从刚才的1024组页面中拿掉一组用作页表。刚才的页面还剩下1023组,会消耗掉我们这组页表页面中的1023个用来映射。所以我们这组页表页面中还剩下一个,我们用它来映射刚刚的1023个页表页面,从而消耗掉了1023个Entry,那剩下的1个Entry呢?用来映射最后这个页面本身。

这样分配听起来似乎清晰多了,能实现吗?按上面的思路,最后一个页表页面无疑是要用作页目录。x86处理器MMU访问线性地址是要经过两次查找加一个偏移(非PAE模式)来确定物理地址的。以此为基础,通过页目录、页表、再加上偏移访问那1023组页面很好理解,但是如何在线性地址中访问1023个页表页面及页目录页面呢?也就是如何通过页目录页面把1023个页表页面和页目录页面自身映射到线性地址中。其实这就是32位Windows的页表自映射机制。

在32位的Windows中,页表的起始线性地址恒为0xC0000000,整个页表区域占用了连续的4MB线性地址空间。最关键的一个设计,就是页目录的第0x300项Entry指向页目录本身,进而也就决定了页目录页面的线性地址为0xC0300000。这一设计使得MMU在查找0xC0000000~0xC03FFFFF这一线性地址空间内的任一线性地址的物理地址时,会把页目录页面当做页表页面来使用,也就是说会访问页目录页面两次。如下图,是微软2004年在东京大学举办Windows Kernel Internals讲座解释GetPteAddress原理时所给出的一张图示:

其实GetPteAddress功能就是给定一个线性地址,得出用以映射这个线性地址所属页面的PTE的地址。原理很明了,4GB的地址空间中包含1M个页面,而4MB的页表区域包含1MB个PTE,这些PTE正是按顺序一一对应了所有这些页面。所以把整个地址空间看作是页面的数组,可以很轻松计算出某个线性地址所属页面的索引,例如0xE4321000>>12=0xE4321,而PTE数组中对应PTE的线性地址即为0xC0000000+(0xE4321<<2)=0xC0390C84。

由上图可以看出,给定的线性地址的高10位为1100000000=0x300,即MMU转译线性地址的第一步:在页目录页面中查找页表指针时使用的索引为0x300,从而使MMU得到页目录页面本身的物理地址。因此MMU在第二个步骤:在页表页面中查找最终的页面指针时,会使用页目录页面作为页表页面以供查找。而页目录页面的所有1024个Entry存储的是其本身和其他1023个页表页面的物理地址,所以MMU经过两次查找最终得到的是某个页表页面的物理地址。当线性地址的高10位固定为1100000000时,剩余低22位仅能表示4MB的范围,因此其所能表示的线性地址限定在0xC0000000~0xC03FFFFF这一区间内,也正是所有页表页面所占用的线性地址空间范围。因为微软所给出的图示适是用于讲解PTE的,PTE大小为4字节并且其地址也是4字节对齐,所以最后的12位页面内偏移也可以理解为利用前10位用作PTE数组索引,最低2位恒为0。

不难想到当MMU第二步查找时如果仍然使用0x300索引,也就是线性地址高20位为11000000001100000000,那么MMU经过两次查找最终得到的物理地址就是页目录页面的物理地址,如下图:

再加上最低12位的页面内偏移, MMU最终转译得到的地址落在页目录页面内,也就是说线性地址0xC0300000~0xC0300FFF表示的区间范围即为页目录页面在线性地址中的地址区间范围。如果在12位的页面偏移中,继续使高10位为1100000000用作PTE索引,那么得到的就是指向页目录自身的PTE,也是PDE,其线性地址为0xC0300C00。

总结,使用一个页面用作页目录,使它的第0x300个Entry指向其自身,剩余的1023个Entry指向其他的1023个页表页面。从而巧妙的将页表区间映射到0xC0000000~0xC03FFFFF这一线性地址区间。

x86平台上的Windows页表映射机制的更多相关文章

  1. 运行在TQ2440开发板上以及X86平台上的linux内核编译

    一.运行在TQ2440开发板上的linux内核编译 1.获取源码并解压 直接使用天嵌移植好的“linux-2.6.30.4_20100531.tar.bz2”源码包. 解压(天嵌默认解压到/opt/E ...

  2. OpenStack平台上,windows云主机可以ping通百度但是无法打开网页,部分其它网页可以打开

    问题描述: 在OpenStack平台上的64位Windows7虚拟机,可以ping通百度,但是却无法打开百度网页. 于是,笔者又对其它网址进行的测试,发现淘宝.京东.携程部分网页可以打开,而新浪等等网 ...

  3. windows的页自映射机制

    windows下由于启用了页机制,所有软件层面的地址操作都是VA,通过descriptor(base address(32bit))+offset得到的线性地址并不直接对应物理地址,而是经过页转换机构 ...

  4. 全面介绍Windows内存管理机制及C++内存分配实例(四):内存映射文件

    本文背景: 在编程中,很多Windows或C++的内存函数不知道有什么区别,更别谈有效使用:根本的原因是,没有清楚的理解操作系统的内存管理机制,本文企图通过简单的总结描述,结合实例来阐明这个机制. 本 ...

  5. Windows平台上Caffe的训练与学习方法(以数据库CIFAR-10为例)

    Windows平台上Caffe的训练与学习方法(以数据库CIFAR-10为例) 在完成winodws平台上的caffe环境的搭建之后,亟待掌握的就是如何在caffe中进行训练与学习,下面将进行简单的介 ...

  6. Java平台上的AOP实现机制

    Java平台上的AOP实现机制 动态代理(Dynamic Proxy)机制,在运行期间动态的为相应接口生成对应的代理对象.SpringAop默认情况下采用这种机制来实现AOP机能.缺点:相对于编译后的 ...

  7. KVM基于X86硬件辅助的虚拟化技术实现机制【转】

    内存虚拟化 Shadow Paging 作者 Shawn 在其中文博客中很详尽地介绍了 KVM 在只支持一级分页的 x86 平台上用 “Shadow Paging”进行 MMU 虚拟化的实现,由于目前 ...

  8. Linux平台上DPDK入门指南

    1. 简介 本文档包含DPDK软件安装和配置的相关说明.旨在帮助用户快速启动和运行软件.文档主要描述了在Linux环境下编译和 运行DPDK应用程序,但是文档并不深入DPDK的具体实现细节. 1.1. ...

  9. linux 逆向映射机制浅析

    2017-05-20 聚会回来一如既往的看了会羽毛球比赛,然后想到前几天和朋友讨论的逆向映射的问题,还是简要总结下,免得以后再忘记了!可是当我添加时间……这就有点尴尬了……520还在写技术博客…… 闲 ...

随机推荐

  1. 【广告】win10 uwp 水印图床 含代码

    本文主要是广告我的软件. 图床可以加速大家写博客上传图片的时间,通过简化我们的操作来得到加速. 在写博客的时候,我们发现,我们需要上传一张图片,需要先打开图片,然后选择本地图片,然后上传. 但是我经常 ...

  2. WebService的简单运用添加删除

    WebService是一种跨编程语言和跨操作系统平台的远程调用技术,简单来说就是将数据存储到项目的文件夹下 .NET中基于DOM核心类 XmlDocument 表示一个XML文档 XmlNode表示X ...

  3. asp.net C# 实现微信接口权限开发类

    当前微信接口类已实现以下接口,代码上如果不够简洁的,请自行处理. 1.获取access_token 2.获取用户基本信息 3.生成带参数二维码 4.新增永久素材 5.新增临时素材 6.发送微信模版 7 ...

  4. 【转】RAM 大全-DRAM, SRAM, SDRAM的关系与区别

    http://blog.csdn.net/huleide/article/details/5506698 ROM和RAM指的都是半导体存储器,ROM是Read Only Memory的缩写,RAM是R ...

  5. php代码常见错误详解整理

    错误类型: 一.未使用二进制上传   代码:    Fatal error: This encoded file is corrupted. Please refer to http://www.ze ...

  6. daterangepicker 使用方法以及各种小bug修复

    双日历时间段选择插件 — daterangepicker是bootstrap框架后期的一个时间控件,可以设定多个时间段选项,也可以自定义时间段,由用户自己选择起始时间和终止时间,时间段的最大跨度可以在 ...

  7. [oracle 使用(1)] win7/10 下Oracle10g的安装与卸载

    1.安装前提 首先要确保你的电脑之前没有安装过,或者安装过但是已经卸载干净了.至于如何查看是否卸载干净可以看看我后面的Oracle卸载步骤. 2.Oracle的安装. 2.1.首先自己在Oracle官 ...

  8. Loadrunner Http接口Get/Post方法性能测试脚本解析

    最近使用LoadRunner 11进行了一次完整的Http WEB接口性能测试,下面介绍下Http接口Get/Post方法性能测试脚本通用编写方法. 1. Http接口性能测试基本流程 首先定义了一个 ...

  9. log4j 和slf4j的比较

    log4j 和slf4j的比较 slf4j 官网:https://www.slf4j.org/manual.html slf4j(simple logging facade for java)是Jav ...

  10. 优先队列(存储结构数组)--Java实现

    /*优先队列--是对队列的一种改进 *要存储的数据存在优先级--数值小的优先级高--在队头 *优先队列的实现 *1.数组:适合数据量小的情况(没有用rear+front实现) *优先队列头在items ...