内核管理实战之虚地址转换为物理地址

来源:互联网 发布:python io模块 编辑:程序博客网 时间:2024/05/17 21:06
CPU只能访问虚拟内存,而实际的数据都存放在物理内存上面,
这就需要将虚拟内存映射到物理内存上面去,然后在物理内存上获取数
据传送到CPU中进行运算,而这个地址的映射就通过页表来完成的。
---------------------------------------------------------------------------------
一,linux内核的四级页表。
       内核为什么要设计四级页表呢?主要是为了支持多种硬件平台,
各种CPU提供的硬件支持不一样,还有要支持64位机。内核的4级页表可
以退化为3级页表,还可以退化到2级页表。四级页表也就是把一个虚拟
地址分为了5部分,分别是PGD,PUD,PMD,PTE,offset
示意图如下:

------------------------------------------------------------------------------
二,实战,将一个用vmalloc开辟的地址映射为物理地址。

  1. static unsigned long vaddr_to_paddr(unsigned long va)
  2. {
  3.     pgd_t *pgd;
  4.     pud_t *pud;
  5.     pmd_t *pmd;
  6.     pte_t *pte;
  7.     unsigned long paddr;
  8.     unsigned long page_addr;
  9.     unsigned long page_offset;

  10.     pgd = pgd_offset(current->mm,va);
  11.     printk("pgd_val = 0x%lx\n",pgd_val(*pgd));
  12.     printk("pgd_index = %lu\n",pgd_index(va));
  13.     if (pgd_none(*pgd)) {
  14.         printk("not mapped in pgd!\n");
  15.         return -1;
  16.     }

  17.     pud = pud_offset(pgd,va);
  18.     printk("pud_val = 0x%lx\n",pud_val(*pud));
  19.     printk("pud_index = %lu\n",my_pud_index(va));
  20.     if (pud_none(*pud)) {
  21.         printk("not mapped in pud!\n");
  22.         return -1;
  23.     }

  24.     pmd = pmd_offset(pud,va);
  25.     printk("pmd_val = 0x%lx\n",pmd_val(*pmd));
  26.     printk("pmd_index = %lu\n",pmd_index(va));
  27.     if (pmd_none(*pmd)) {
  28.         printk("not mapped in pmd!\n");
  29.         return -1;
  30.     }

  31.     pte = pte_offset_kernel(pmd,va);
  32.     printk("pte_val = 0x%lx\n",pte_val(*pte));
  33.     printk("pte_index = %lu\n",pte_index(va));
  34.     if (pte_none(*pte)) {
  35.         printk("not mapped in pte!\n");
  36.         return -1;
  37.     }
  38.     

  39.     page_addr = pte_val(*pte) & PAGE_MASK;
  40.     page_offset = va & ~PAGE_MASK;
  41.     paddr = page_addr | page_offset;

  42.     printk("vaddr = %lx,paddr = %lx\n",va,paddr);
  43.     printk("page_addr = %lx\n",page_addr);
  44.     
  45.     return paddr; 
  46. }
模块运行结果:(环境:linux.2.6.36,intel 32位系统)

  1. [263298.365202] pgd_val = 0x5e18067
  2. [263298.365207] pgd_index = 995
  3. [263298.365210] pud_val = 0x5e18067
  4. [263298.365213] pud_index = 0
  5. [263298.365216] pmd_val = 0x5e18067
  6. [263298.365218] pmd_index = 0
  7. [263298.365221] pte_val = 0x63c0163
  8. [263298.365223] pte_index = 127
  9. [263298.365226] vaddr = f8c7f000,paddr = 63c0000
  10. [263298.365229] page_addr = 63c0000
可以看出pud和pmd的偏移量均为0,说明在这儿就只使用了二级页表,
将pud和pmd都“折叠”起来了。代码的过程完全可以由上面的图解释。
-----------------------------------------------------------------------------------------
三,模块完整代码
 vaddr_to_paddr.rar   
------------------------------------------------------------------------------------------
0 0
原创粉丝点击