zoukankan      html  css  js  c++  java
  • 关于windows虚拟内存管理的页目录自映射

    Windows页目录自映射

    Windows的内存访问是采用虚拟内存形式,即对于任何一个Adr,首先根据CR3寄存器的值来得到页目录表的地址,此时页目录表是一个刚好大小为4k的页。页目录表中,每一项大小为4B,内容包括对应页表的物理地址和一些标志位。由于页表也是一个大小为4K的页,所以地址是按4K对齐的,因此这里的地址只需要20位就可以了,剩下的12位作为标志位。Adr所在页表的地址由页目录表的第Adr>>22项给出。得到页表的地址之后,同样重复前面所做的工作,利用(Adr<<10)>>22来得到所在页在页表中的索引,从而得到虚拟地址指向页的物理地址,然后再根据页内地址来定位读取内存。至此,虚拟地址到物理地址的转化过程结束。

    但是在windows初始化的时候,前期是直接操纵物理地址的,通过分配一个页目录表所在页的地址和页表所在大页的地址,来直接操纵pte和pde。因为根据系统的内存布局,pde的地址是0xc0030000,pte的地址是0xc0000000,除此之外还有一些其他的系统默认虚拟地址空间,都是直接操纵pde和pte来进行初始化,同时更新相应的pfn数据库。

    在刚初始化完之后,windows的虚拟内存系统正式开始运行,一切对内存的访问都需要虚拟地址。而之前我们所有做的操作都是在pde和pte上进行的,因此当前我们所有的地址都是pte和pde的虚拟地址,而我们真正需要的是pte和pde所指向的页的虚拟地址。这是需要将我们前面所述的虚拟页到页表和页目录表的过程进行逆推。由于页表的后22位是虚拟页的地址,因此直接将页表的虚拟地址左移10位即可得到虚拟页的地址,刚好是以4k为单位对齐的。对于页目录表,也可以同样的理解,因为页目录表的长度为4k,所以页目录表的表项的虚拟地址都是0xc0300开头的,而且最后的两位都是0,因为页目录表项的大小是4b对齐。左移10位之后,前10位变为1100000000,最后的十二位全部为0,刚好是以页为单位对齐的,中间的10位刚好指向对应的页表的虚拟地址索引。因此根据pte和pde可以直接得到它所指向物理页面的虚拟地址,而且都是以页为单位对齐的。

    这里需要注意的是,pte的大小为4mb,由于其虚拟空间是连续的,所以这个连续的空间在页目录表中占据一个表项,根据之前说过的方法和pte的虚拟地址空间,pte所在的页目录项为第0x300项,又因为每个项为4b,所以页内地址为0xc00,所以最后的虚拟地址为0xc0300c00,其中的物理地址应该指向页表的开始物理地址。而页目录表的大小为4k,刚好为一页 ,他在pte中也占据一项,由于页目录虚拟地址为0xc0300000,所以是页表中的第0xc0300项,又因为页表项也是4B对齐的,所以他距页表开始地址的偏移为0x300c00因此页目录表的pte的虚拟地址为0xc0300c00。此外可以看出,页表包括220页,又因为页表项的大小为4B,所以整个页表所占的虚拟空间的大小为222位,为0x400000。又因为页表的虚拟地址开始为0xc0000000,所以结束地址为0xc0400000。所以页目录表的地址空间属于页表地址空间,即可以当pde使用又可以当作pte使用。两个地址是相同的,因此为了使得在访问pde和pte时得到正确的结果,必须设计使得pte和pde的数据格式一模一样。因为pde和pte中的物理地址指向的都是一个大小为4K的页,所以一般情况下不会出问题。但是对于0xc0300c00这个地址,当作页目录项来使用时其中应该指向的是页表0xc0000000的物理地址;而当作也表项来使用时,指向的应该是虚拟页0xc0300000的地址,即页目录的物理地址。我们知道这两个物理地址是不相同的,所以我们必须决定采用哪一个物理地址。Windows中采用的是使用cr3寄存器中的地址,即页目录表自己的物理地址。这个时候,如果程序需要访问页表内的某个地址,直接查pde的话,得到的地址还是cr3;再经过第二次查表来查询pte,不过这个表仍然是当前的pde,只不过把他当作pte来使用,我们确保经过两次查表之后所得的结果是正确的。

    现在举例子来说明。假设要访问的地址(虚拟地址)为0xc0390c84。按照一般情况下,对于这个虚拟地址,我们首先得到页目录表的索引,为0x300项。这个项指向页表的开始页。然后再在页表的开始页中寻找页表的索引,为0x390,得到一个物理页的地址,最后再根据页内偏移0xc84得到所需字节的内容。看上去我们根据流程得到了正确的结果 ,但是这个时候页表的0x390项指的是虚拟地址为0x390000的页面,再根据页内偏移,我们最终得到的是虚拟地址为0x390c84所指向的内容,并不是我们希望得到的0xc0390c84所指向的内容。因此,把页目录表中的第0x300项按照常规设置为页表0xc0000000的地址是不正确的。

    而在页目录表中的第0x300项设置为cr3的地址,亦即页目录表自己的地址时,寻址过程如下所示。首先根据页目录号0x300所指向的地址得到一个页表,其实也还是当前页目录。这时再根据页表中的索引0x390,得到一个页的物理地址。然后再根据页内偏移0xc84来得到最后所需的内容。注意,当前页目录表当作页表使用时,里面的项的相对偏移都是相对0xc0000000。这时页表中0x390所指向的页的虚拟地址为0xc0000000+(0x390<<12)==0xc0390000,的确是我们所希望访问的虚拟页。因此最后所得到的访问内容是正确的。

    对于虚拟地址在页目录区的访存过程

                           

  • 相关阅读:
    如何在服务器后台跑程序
    相对熵(KL散度)
    Colab使用fitlog或者tensorboardx
    PlotNeuralNet模型图
    scikitplot绘制ROC图
    算法作业:FFT实现大数乘法
    集成学习--Bagging、Boosting、Stacking、Blending
    numpy删除指定元素
    UniLM模型
    周练(11)70. 爬楼梯
  • 原文地址:https://www.cnblogs.com/huangfeidian/p/3103394.html
Copyright © 2011-2022 走看看