新浪博客

虚拟地址到物理地址的转换步骤

2015-03-25 20:15阅读:
已知一个虚拟地址0x01AF5518, 则转换的过程如下:
  注意: *这里讨论的以Windows下普通模式分页的情况, 也就是2级页表的情况*
1.首先把虚拟地址拆分成3个部分(低12位, 中10位, 高10位), 换成2进制如下:
  -> 0000 0001 1010 1111 0101 0101 0001 1000
  按照10, 10, 12的位数重新排列后
  -> (页目录索引)00 000 00110, (页表项索引)10 1111 0101, (偏移)0101 0001 1000
  换算成十六进制后可以得到如下结果
  页目录索引 = 6, 页表项索引 = 0x2f5 , 偏移 = 0x518
2. 根据当前的CR3寄存器中的物理地址定位页目录表基址
  Cr3中存放的是物理地址, 这个物理地址指向进程的页目录表基址, 由此可以得到
  页目录表基址(PDE) = Cr3 = 0xAA0E5000
3. 计算页表项的地址
  页表地址存放在页目录表(PDE)中的第6个项目中, 也就是
  [0xAA0E5000 + 4 * 6] = [0xAA0E5018] = 0x3D955867, 其中0x00000867为该页表属性值, PTE = 0x3D955000
3. 计算页面物理地址
  我们要找的页面在这个页表中的第0x2f5项, 所以虚拟地址所在的页的物理地址为
  [0x3D955000 + 0x2f5 * 4] = [0x3D955BD4] =
  假设[0x3D955BD4] = 0x7095e847, 页面的物理地址 x0x7095e000, 0x00000847表示的是页面属性
4. 计算最终的物理地址
  由虚拟地址分离的偏移可以计算出最终的物理地址为
  0x7095E000 + 0x00000518 = 0x7095E518.
//--------------------------------
-----------------------------------------
假设两个数据结构之间的关系。
虚拟地址到物理地址的转换步骤

虚存区的设计:
对于一个虚存区会被分为5部分:页全局目录PGD、页上级目录PUD、页中间级目录PMD、页表PT、偏移量offset。其中表项叫做页表项PTE
1、程序的分析
  • 首先重进程描述符中(mm_struct)读取pgd的字段的内容,他就是页全局目录的起始地址;
  • 然后页全局目录起始地址加上页全局目录索引获得页上级目录的起始地址;页上级目录的起始地址加上页上级目录的索引获得页中间目录的起始地址;页中间目录的起始地址加上页中间目录的索引获得页表的起始地址; 页表的起始地址加上索引,可以得到完整的页表项内容;
  • 从页表项中取出物理地址的基址,加上偏移量可以得到最终的物理地址;
2、代码
address.c
  1. #include<</span>linux/kernel.h>
  2. #include<</span>linux/sched.h>
  3. #include<</span>linux/module.h>
  4. #include<</span>linux/init.h>
  5. #include<</span>linux/mm.h>
  6. #include<</span>linux/mman.h>
  7. #include<</span>linux/highmem.h>


  8. MODULE_LICENSE('GPL');
  9. static int pid;
  10. static unsigned long va;
  11. module_param(pid, int ,0644);
  12. module_param(va, long ,0644);

  13. static struct page * my_follow_page( struct vm_area_struct *vma,unsigned long addr)
  14. {
  15. pgd_t *pgd=NULL;
  16. pud_t *pud=NULL;
  17. pmd_t *pmd=NULL;
  18. pte_t *pte=NULL;
  19. spinlock_t *ptl=NULL;
  20. unsigned long full_addr;
  21. struct page *page=NULL;
  22. struct mm_struct *,mm = vma->mm;
  23. printk('mm = %lx',*mm);

  24. pgd = pgd_offset(mm,addr);
  25. printk('pgd = %lx',*pgd);
  26. if(pgd==NULL||unlikely(pgd_bad(*pgd)))
  27. goto out;
  28. pud = pud_offset(pgd,addr);
  29. printk('pud = %lx',*pud);
  30. if(pud_none(*pud)||unlikely(pud_bad(*pud)))
  31. goto out;

  32. pmd = pmd_offset(pud,addr);
  33. printk('pmd = %lx',*pmd);
  34. if(pmd_none(*pmd)||unlikely(pmd_bad(*pmd)))
  35. goto out;
  36. pte = pte_offset_map_lock(mm,pmd,addr,&ptl);
  37. if(!pte)
  38. goto out;

  39. if(!pte_present(*pte))
  40. {
  41. printk('1 unlock');
  42. goto unlock;
  43. }
  44. page = pfn_to_page(pte_pfn(*pte));
  45. if(!page) {
  46. printk('0 unlock');
  47. goto unlock;
  48. }
  49. full_addr = (*pte).pte_low&PAGE_MASK;
  50. full_addr+=addr&(~PAGE_MASK);
  51. printk('full_addr = %lx....',full_addr);
  52. printk('pte = %lx ...........',pte_pfn(*pte));
  53. printk('page = %p......',page);
  54. get_page(page);
  55. unlock:
  56. pte_unmap_unlock(pte,ptl);
  57. out:
  58. return page;

  59. }
  60. static int __init physical_init(void)
  61. {

  62. struct vm_area_struct *p;

  63. my_follow_page(p,va);
  64. return 0;
  65. }
  66. static void __exit physical_exit(void)
  67. {
  68. printk('bye !');
  69. }
  70. module_init(physical_init);
  71. module_exit(physical_exit);

我的更多文章

下载客户端阅读体验更佳

APP专享