【问题标题】:Page Table Walk in LinuxLinux 中的页表遍历
【发布时间】:2018-03-28 17:04:33
【问题描述】:

考虑以下代码:

pgd_t *pgd;
pte_t *ptep;
pud_t *pud;
pmd_t *pmd;
char *addr;

struct page *page = NULL;
struct mm_struct *mm = current->mm;

pgd = pgd_offset(mm, addr);
if (pgd_none(*pgd) || pgd_bad(*pgd))
    goto out;
printk(KERN_NOTICE "Valid pgd");

pud = pud_offset(pgd, addr);
if (pud_none(*pud) || pud_bad(*pud))
    goto out;
printk(KERN_NOTICE "Valid pud");

pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd) || pmd_bad(*pmd))
    goto out;
printk(KERN_NOTICE "Valid pmd");

ptep = pte_offset_map(pmd, addr);
if (!ptep)
    goto out;

addr = ptep->pte;
printk(KERN_INFO "byte = %d\n", *(char *)__va(addr));
pte_unmap(ptep);

如果我理解正确的话,addr 应该是用户空间虚拟地址对应的物理地址。然后我应该能够使用__va 取消引用它。但是,它不起作用。但是,如果我使用pte_pagekmap,它会完全按照预期的方式工作。为什么会这样?我在 x86-64 上,所以高内存应该不是问题吗? kmap 还有什么别的吗?

【问题讨论】:

  • Walk page directory函数返回与发送给函数的虚拟地址参数对应的页表目录中的页表条目的地址。它应该返回一个虚拟地址而不是物理地址。如果我没记错的话,xv6 操作系统就是这种情况,你的情况也应该如此。 __va(addr) 基本上是在翻译一个虚拟地址,然后你可能会尝试访问你无权访问的一部分内存,这会导致你的程序崩溃。
  • @TonyTannous 页表中的地址不是物理地址吗?我直接取消引用页表:addr = ptep->pte,然后将其用于__va
  • 不,页表项中的地址不是物理地址。您在该条目中也有标志位。实际返回的是该页面条目的虚拟地址,而不是其内容。我不是专家,也许也弄错了,所以最好等待更多的答案\意见。
  • @TonyTannous 啊,我认为你是对的。我忘记了用于访问权限和其他内容的位。

标签: c linux memory operating-system kernel


【解决方案1】:

感谢 TonyTannous,我解决了这个问题。页表条目不仅包含物理地址,还包含一些其他用于访问权限等的位。物理地址可以通过PTE_PFN_MASK屏蔽得到:

    addr = ptep->pte & PTE_PFN_MASK

然后我可以使用 __va 取消引用它。

【讨论】:

  • 我还是要小心,因为addr 可能是页表条目的虚拟地址,而不是它的内容。您可能有权访问__va(addr) 内存位置,但它可能不是您想要的。唯一知道的方法是检查它自己的 Linux 源代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多