liang's profile阿斯提亚神殿——梦幻天子's skyPhotosBlogLists Tools Help
    October 07

    PTE/PDE(转载)

      虚拟地址如何转换到物理地址?必须用到PDE,PTE的虚拟地址吗?

    按照以前学习的分页机制,一个虚拟地址转换成物理地址的计算过程应该是:

    1 处理器通过CR3找到当前页目录所在的物理页地址a
    2 计算PDE的物理地址:a+ 虚拟地址高十位左移两位 (因为每个页目录项四个字节),取出该地址处的PDEPDE的前20位+低12位0是这个虚拟地址对应页表的物理地址b
    3 计算PTE的物理地址:b+ 虚拟地址的中间10位左移两位,取出该地址处的PTEPTE的前20位是这个虚拟地址+低12位0是所对应物理页的地址c
    4 计算该虚拟地址对应的物理地址:c + 虚拟地址最低12

    是这样的吗?
    实验代码://老师上课给的代码相同,只是把虚拟地址改成了60010020
    int main()
    {
          char buf[100] = "Hello world";                              
          VirtualAlloc( (void  *)0x60010020, 0x3000, MEM_RESERVE, PAGE_READWRITE );   //保留三页
          VirtualAlloc( (void *)0x60010020, 0x2000, MEM_COMMIT, PAGE_READWRITE );   //提交两页
          printf( "Accessing memory...\n" );                           
          getchar();
          memcpy( (void *)0x60010020, buf, 100 );
          printf( "Releasing memory...\n");
          getchar();
          VirtualFree( (void *)0x60010020, 0, MEM_RELEASE );
          printf( "Exiting memory...\n" );
          getchar();
          return 0;
    }

    1 查寄存器CR3中的值

    kd> r cr3

    cr3=0e238000
    2 计算PDE的物理地址:0e238000 + 00000600= 0e238600

    取出该地址处的PDE

    kd> !dd 0e238600

    # e238600 0dfc9867 00000000 00000000 00000000

    # e238610 00000000 00000000 00000000 00000000

    # e238620 00000000 00000000 00000000 00000000

    # e238630 00000000 00000000 00000000 00000000

    # e238640 00000000 00000000 00000000 00000000

    # e238650 00000000 00000000 00000000 00000000

    # e238660 00000000 00000000 00000000 00000000

    # e238670 00000000 00000000 00000000 00000000

    3计算PTE的物理地址:0dfc9000 + 00000040 = 0dfc9040
    取出该地址处的PTE

    kd> !dd 0dfc9040

    # dfc9040 0dece867 00000080 00000080 00000000

    # dfc9050 00000000 00000000 00000000 00000000

    # dfc9060 00000000 00000000 00000000 00000000

    # dfc9070 00000000 00000000 00000000 00000000

    # dfc9080 00000000 00000000 00000000 00000000

    # dfc9090 00000000 00000000 00000000 00000000

    # dfc90a0 00000000 00000000 00000000 00000000

    # dfc90b0 00000000 00000000 00000000 00000000
    4 计算虚拟地址对应的物理地址:0dece000 + 00000020 = 0dece020
    取出该物理地址处的数据:

    kd> !db 0dece020

    # dece020 48 65 6c 6c 6f 20 77 6f-72 6c 64 00 00 00 00 00 Hello world.....

    # dece030 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

    # dece040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

    # dece050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

    # dece060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

    # dece070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

    # dece080 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

    # dece090 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
    实验结果表明:虚拟地址0x60010020对应的物理地址为:0dece020,并不需要用到PDE,PTE的虚拟地址,上面的计算方法是正确的

    通过基址c0300000c0000000计算出的PDEPTE的虚拟地址有什么用?


    cpu在转换地址的过程中,并不需要页表,页目录的虚拟地址,那为什么还需要计算PDE,PTE的虚拟地址呢?是因为在分页标志设置后,cpu把指令中的虚拟地址转换成物理地址,程序中只能使用虚拟地址,因此要把页目录和页表映射到虚拟地址空间中,页表被映射到了从0xC00000000xC03FFFFF4M地址空间,页目录被映射到了0xC0300000开始处的4K地址空间

    因此PDE的虚拟地址为: c0300000 + 00000600 = c0300600
    取出该虚拟地址处的PDE,可以看到和上面用PDE的物理地址取出来的结果相同

    kd> dd c0300600

    c0300600  0dfc9867 00000000 00000000 00000000

    c0300610  00000000 00000000 00000000 00000000

    c0300620  00000000 00000000 00000000 00000000

    c0300630  00000000 00000000 00000000 00000000

    c0300640  00000000 00000000 00000000 00000000

    c0300650  00000000 00000000 00000000 00000000

    c0300660  00000000 00000000 00000000 00000000

    c0300670  00000000 00000000 00000000 00000000


    PTE的虚拟地址为:  c0000000 + 00180040 = c0180040
    取出该虚拟地址处的PTE,和上面用PTE的物理地址取出来的结果相同

    kd> dd c0180040

    c0180040  0dece867 00000080 00000080 00000000

    c0180050  00000000 00000000 00000000 00000000

    c0180060  00000000 00000000 00000000 00000000

    c0180070  00000000 00000000 00000000 00000000

    c0180080  00000000 00000000 00000000 00000000

    c0180090  00000000 00000000 00000000 00000000

    c01800a0  00000000 00000000 00000000 00000000

    c01800b0  00000000 00000000 00000000 00000000