All Discussions - HelloWorld http://www.yanddstudio.cn/HelloWorld/discussions/feed.rss Mon, 21 May 12 08:42:39 -0400 All Discussions - HelloWorld en-CA 【每日一推荐】程序员面试题狂想曲:第一章、左旋转字符串 http://www.yanddstudio.cn/HelloWorld/discussion/4/%E6%AF%8F%E6%97%A5%E4%B8%80%E6%8E%A8%E8%8D%90%E7%A8%8B%E5%BA%8F%E5%91%98%E9%9D%A2%E8%AF%95%E9%A2%98%E7%8B%82%E6%83%B3%E6%9B%B2%E7%AC%AC%E4%B8%80%E7%AB%A0%E5%B7%A6%E6%97%8B%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2 Sat, 16 Apr 2011 12:23:22 -0400 yarpee 4@/HelloWorld/discussions http://blog.csdn.net/v_JULY_v/archive/2011/04/14/6322882.aspx]]> 【每日一推荐】C++串比较问题(小试NetBeans IDE进行的反汇编调试) http://www.yanddstudio.cn/HelloWorld/discussion/3/%E6%AF%8F%E6%97%A5%E4%B8%80%E6%8E%A8%E8%8D%90c-%E4%B8%B2%E6%AF%94%E8%BE%83%E9%97%AE%E9%A2%98%E5%B0%8F%E8%AF%95netbeans-ide%E8%BF%9B%E8%A1%8C%E7%9A%84%E5%8F%8D%E6%B1%87%E7%BC%96%E8%B0%83%E8%AF%95 Thu, 14 Apr 2011 11:54:07 -0400 yarpee 3@/HelloWorld/discussions http://blog.csdn.net/UndeadWraith/archive/2011/04/08/6310399.aspx]]> 【原创】乱侃WindowsNT内核之内存管理 http://www.yanddstudio.cn/HelloWorld/discussion/2/%E5%8E%9F%E5%88%9B%E4%B9%B1%E4%BE%83windowsnt%E5%86%85%E6%A0%B8%E4%B9%8B%E5%86%85%E5%AD%98%E7%AE%A1%E7%90%86 Wed, 13 Apr 2011 14:25:05 -0400 yarpee 2@/HelloWorld/discussions 作 者: xxxdebug
时 间: 2010-04-22,18:10:50
链 接: http://bbs.pediy.com/showthread.php?t=111508


题外话:

假设大家都已经了解了x86体系的内存管理机制,知道什么是flat模式,知道运算部件AU和存储管理部件MMU的含义,知道什么是虚拟地址(flat模式下线性地址和虚拟地址是等同的,不考虑分段情况),什么是物理地址(内存、IO端口);知道什么是页表,什么是页表项pte,什么是页目录pde等等。

本文为做特别说明,都是基于x80体系,非PAE的4k分页的情况讨论。
==================================================================


页表在系统空间的映射:
================================================================
Windows采用的是将整个页表映射到一段连续的地址,在非PAE的4k分页的情况下(PAE模式下页表项的大小是8个字节),页表映射开始于系统空间的0xc0000000的0x400000个字节。虚拟地址相邻的页表所映射的虚拟地址也是连续的,即0xc0000000指向的PTE所映射的是用户空间的0~0xfff;0xc0000004指向的PTE所描述的是0x1000~0x1fff…

Windows对页表的这种精心安排,好处是不言而喻的,比如对于一个确定的虚拟地址,其对应的页表位置也就确定了,如对于虚拟空间的某一地址x,其PTE的地址就是x/0x1000*4+0xc000000,如页表本身所对应的PTE地址(也称PDE)= 0xc0000000/0x1000*4+0xc00000000= 0xc0300000;反过来转换也很简单,对于也个PTE的地址x,其所映射的页的起始地址是(x-0xc0000000)/4*0x1000。

0xc0000000开始映射页表是唯一选择么?我觉得未必,其实页表在虚拟空间映射的位置是可以浮动的,但有一个要求,必须映射在系统空间。如果将页表映射在用户空间会出什么问题呢?用户空间是属于进程的私有财产,操作系统有时候是没有进程上下文的,所以如果将页表映射在用户空间将导致系统无法进行内存管理。

页表可以映射到不连续的空间么?当然可以,只是这样做页表项的地址和其所对应的虚拟地址之间就不那么容易转换了。

从MMU的角度来看,在地址转换过程中,只和物理地址打交道,因为页表保存的是物理地址,所以页表甚至不需映射到虚拟空间中的。

但是AU只能对已经映射的地址进行访问,而且建立和取消映射需要对页表项(PTE、PDE)进行读写操作,如果页表项没有映射就无法读写,所以将整个页表保持一个固定的映射是一个不错的选择,当然也可以每次都进行临时映射,但这样做的效率可想而知。

还有一点,页表的映射区是独立于进程的,在系统空间中有两块区域在不同的进程中所保存的内容是不一样的,一块就是页表映射区域,还有一块是被称作超级空间(hyperspace)的地方,超级空间是系统用来做临时映射(打草稿)用的,这两块地方在进程切换是需要更新,其他空间在所有进程看来都是一样的,即所谓公用区域,比如各个系统模块的映射区,包括系统缓冲区(pool)等等。


页表的初始化:
==========================================================
我们知道,在启动分页以后,CR3指向的物理地址指向页目录

如果我们已经将页目录映射到了一个确定的地址,下面的工作就不是问题了

也许你会问,我们如何将页目录映射到一个确定的地址呢?这似乎是一个先有鸡还是先有蛋的问题

其实很简单,两句话,子进程的页目录映射由父进程代劳,老祖宗进程的页目录的映射工作由实模式代劳。

对于子进程,父进程会在其hyperspace上将子进程的页表映射构造好,然后将页目录对应的物理地址写道子进程的EProcess里就一切OK了。

而对于第一个进程的页表是在启动分页前设置好的。

其实windows的做法是子进程的页表映射数据是直接从父进程中拷贝而来的,上面已经说过,所有进程的系统空间的映射除了页表和hyperspace两块区块外都是相同的,所以所要做的工作就是申请两个页面,映射到父进程的hyperspace,这样父进程就可以读写这两个页面了,其中一个页面用于保存页目录,其高半部分直接从父进程的pde的高半部分拷贝,一页用于保存hyperspace的页表项,并修改保存目录页面中的两个pte的值,一个是指向其自身的pte(pde),一个是指向hyperspace的pte。至于这两个pte在页目录页面中的偏移是容易计算的,而且是固定不变的。

其实让页目录页面中的某一项的pte值指向其自身也就完成了页目录页面本身的映射,比如要想将页目录页面映射到0xc0300000,只需将偏移0xc00除的pte指向其自身即可,计算公式:0xc0300000/1000*4+0xc0000000-0xc0300000=0xc00。 ]]>