【发布时间】: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_page 和kmap,它会完全按照预期的方式工作。为什么会这样?我在 x86-64 上,所以高内存应该不是问题吗? kmap 还有什么别的吗?
【问题讨论】:
-
Walk page directory函数返回与发送给函数的虚拟地址参数对应的页表目录中的页表条目的地址。它应该返回一个虚拟地址而不是物理地址。如果我没记错的话,xv6 操作系统就是这种情况,你的情况也应该如此。__va(addr)基本上是在翻译一个虚拟地址,然后你可能会尝试访问你无权访问的一部分内存,这会导致你的程序崩溃。 -
@TonyTannous 页表中的地址不是物理地址吗?我直接取消引用页表:
addr = ptep->pte,然后将其用于__va。 -
不,页表项中的地址不是物理地址。您在该条目中也有标志位。实际返回的是该页面条目的虚拟地址,而不是其内容。我不是专家,也许也弄错了,所以最好等待更多的答案\意见。
-
@TonyTannous 啊,我认为你是对的。我忘记了用于访问权限和其他内容的位。
标签: c linux memory operating-system kernel