在8086时期,寄存器是16位,无法存放20位的物理地址,为了解决这问题,人们提出了分段机制,分段机制就是将内存分段,每段大小64kb,在段寄存器中放入段基址,然后+上段偏移量就成了物理地址或者线性地址,为什么说是或呢?因为在采用分页基址的系统中,线性地址加上页偏移量才是真正的物理地址,如果没有用分页机制,计算出来的就是物理地址。
windows NT引入了内存分页机制,此种内存管理机制,使得从应用程序角度来看,其是独占使用4
GB的内存空间,应用程序间内存空间隔离而互不影响,一个进程崩溃不会蔓延、影响到其它进程,另外使得虚拟内存机制成为可能,把暂时不用的内存页交换到磁盘pagefile文件中,需要时再交换进来。
内存分页机制是把物理内存按固定大小分成很多个等份,一般为4K大小,下面也以4K为一页来说明,每个等份称为一页,我称它为物理页,线性地址空间也进行了分页,我称它为线性页,对于某个进程可访问的线性地址空间0~0x3fffffff,如何映射到物理内存中呢?也就是说线性页如何映射到物理页呢?线性页和物理页好像没人如此叫,我来引入一个。下面来探讨一下。
原来在进程地址空间的0xC0000000起始处的4M空间,到0xC03fffff结束,存放了各个线性页所对应的物理页的物理地址值,每4字节为一项,每1024个项组成一个页表PT,故共1024个PT,页表内的项索引叫PTE(page table entry),如第一个线性页,即0~0x00000fff线性地址空间,其物理页是哪个呢?显然是线性地址0xC0000000指向的DWORD值,依此类推,诙 鱿咝砸常 锢硪澄 咝缘刂?xC0000001的值,线性页映射到物理页后加上页内偏移就可以得到物理地址了,原来挺简单的嘛。
显然页内偏移为线性地址的末尾12位嘛,即有如下公式:
offset=LA && 0x00000fff
LA : 线性地址,line address
offset:页内偏移
PA:物理地址,physic address
理解了前面的描述,易知,线性地址的高20位即为PTE索引
即有PA=*(0xC0000000+LA>>12*4),*表示取地址内容
那0xC0000000开始的4M线性地址,物理页是哪些呢?我们来计算一下
0xC0000000+0xC0000000>>12*4=0xC0300000
可见0xC0300000开始的页表比较特殊,称为页目录表,该表的每一项正好指向一个页表的开始位置,也就是页表的表,页目录表的索引,称为PDE(page directory entry),
假设知道了一个线性地址的PDE,PTE,可按以下公式计算物理地址:
PA = *(0xC0000000+PDE*1024*4+PTE*4)
= *(0xC0000000+(PDE<<10+PTE)<<2)
对比前面的公式,
*(0xC0000000+LA>>12*4) == *(0xC0000000+(PDE<<10+PTE)<<2)
LA>>12 == (PDE<<10+PTE)
PDE,PTE最大1024=2的10次方,所以PDE即为线性地址的高10位,PTE为线性地址的中间10
位,线性地址的低12为页内偏移。
有些文章中提到的PDE地址,PTE地址,如何理解?
PDE地址指线性地址在页目录表对应项的地址,
PDE_add=LA>>22+0xC0300000
PTE地址指线性地址在页表对应项的地址,
PTE_add=LA>>12+0xC0000000
PTE地址低12位包含了页属性,用windbg可看到
lkd> dt _hardware_PtE
nt!_HARDWARE_PTE
+0x000 Valid : Pos 0, 1 Bit
+0x000 Write : Pos 1, 1 Bit
+0x000 Owner : Pos 2, 1 Bit
+0x000 WriteThrough : Pos 3, 1 Bit
+0x000 CacheDisable : Pos 4, 1 Bit
+0x000 Accessed : Pos 5, 1 Bit
+0x000 Dirty : Pos 6, 1 Bit
+0x000 LargePage : Pos 7, 1 Bit
+0x000 Global : Pos 8, 1 Bit
+0x000 CopyOnWrite : Pos 9, 1 Bit
+0x000 Prototype : Pos 10, 1 Bit
+0x000 reserved : Pos 11, 1 Bit
+0x000 PageFrameNumber : Pos 12, 20 Bits
当0位为1时,说明PTE有效,页在物理内存中,而7位的LargePage表示当前虚拟地址大于等于0x80000000并且小于0xa0000000(减去0x80000000就得到了物理地址)
CPU是如何计算一个线性地址的物理地址的呢?以下参考了一些网上资料。
1 CR3寄存器保存了当前活动进程的页目录所在物理页地址,CPU通过CR3找到当前页目录所在的物理页地址a
2 计算PDE的物理地址:a+ 线性地址高10位左移两位 (因为每个页目录项四个字节),取出该地址处的PDE,PDE的前20位+低12位0是这个虚拟地址对应页表的物理地址b
3 计算PTE的物理地址:b+ 虚拟地址的中间10位左移两位,取出该地址处的PTE,PTE的前20位是这个虚拟地址+低12位0是所对应物理页的地址c
4 计算该虚拟地址对应的物理地址:c + 虚拟地址最低12位
引自: http://hi.baidu.com/zqfazqq/blog/item/35e41116b8916255f2de3214.html