简体   繁体   中英

Page Table Walk in Linux

Consider the following piece of code:

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);

If I understand correctly, addr should be the physical address corresponding to the user-space virtual address. Then I should be able to dereference that using __va . However, it doesn't work. If I use pte_page and kmap , though, it works exactly how it is supposed to. Why does this happen? I'm on x86-64, so high memory shouldn't be a problem? Is there something else kmap does?

I fixed the problem thanks to TonyTannous. The page table entry doesn't contain just the physical address, but also some other bits used for access rights and the like. The physical address can be obtained by masking it with PTE_PFN_MASK :

    addr = ptep->pte & PTE_PFN_MASK

I can then dereference it with __va .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM