简体   繁体   English

如何从 Linux kernel 模块中的逻辑地址获取物理地址?

[英]How to get the physical address from the logical one in a Linux kernel module?

Is there any suitable way to get the physical address by the logical one except to walk through page directory entries by hand?除了手动遍历页面目录条目之外,是否有任何合适的方法可以通过逻辑地址获取物理地址? I've looked for this functionality in kernel's sources and found that there is a follow_page function that do it well with built-in huge and transparent-huge pages support.我在内核的源代码中寻找了这个功能,发现有一个follow_page function 可以很好地支持内置的大页面和透明大页面。 But it's not exported to kernel modules (why???)...但它没有导出到 kernel 模块(为什么???)...

So, I don't want to invent the wheel and I think that it's not very good to reimplement the follow_page functionality by hand.所以,我不想发明轮子,我认为手动重新实现follow_page功能并不是很好。

Well, it might looks as something like that (follow PTE from an virtual address):好吧,它可能看起来像这样(从虚拟地址跟随 PTE):

void follow_pte(struct mm_struct * mm, unsigned long address, pte_t * entry)
{
    pgd_t * pgd = pgd_offset(mm, address);

    printk("follow_pte() for %lx\n", address);

    entry->pte = 0;
    if (!pgd_none(*pgd) && !pgd_bad(*pgd)) {
        pud_t * pud = pud_offset(pgd, address);
        struct vm_area_struct * vma = find_vma(mm, address);

        printk(" pgd = %lx\n", pgd_val(*pgd));

        if (pud_none(*pud)) {
            printk("  pud = empty\n");
            return;
        }
        if (pud_huge(*pud) && vma->vm_flags & VM_HUGETLB) {
            entry->pte = pud_val(*pud);
            printk("  pud = huge\n");
            return;
        }

        if (!pud_bad(*pud)) {
            pmd_t * pmd = pmd_offset(pud, address);

            printk("  pud = %lx\n", pud_val(*pud));

            if (pmd_none(*pmd)) {
                printk("   pmd = empty\n");
                return;
            }
            if (pmd_huge(*pmd) && vma->vm_flags & VM_HUGETLB) {
                entry->pte = pmd_val(*pmd);
                printk("   pmd = huge\n");
                return;
            }
            if (pmd_trans_huge(*pmd)) {
                entry->pte = pmd_val(*pmd);
                printk("   pmd = trans_huge\n");
                return;
            }
            if (!pmd_bad(*pmd)) {
                pte_t * pte = pte_offset_map(pmd, address);

                printk("   pmd = %lx\n", pmd_val(*pmd));

                if (!pte_none(*pte)) {
                    entry->pte = pte_val(*pte);
                    printk("    pte = %lx\n", pte_val(*pte));
                } else {
                    printk("    pte = empty\n");
                }
                pte_unmap(pte);
            }
        }
    }
}

I think you can achieve virtual->physical translation through an indirect method by a combination of /proc/[pid]/maps ( gives the virtual mapping for a process ) and /proc/[pid]/pagemap ( Gives Virtual Page to Physical Page mapping for every addressable page ).我认为您可以通过/proc/[pid]/maps (为进程提供虚拟映射)和/proc/[pid]/pagemap (为物理提供虚拟页面)的组合通过间接方法实现虚拟->物理转换每个可寻址页面的页面映射)。 First, find out the mapping of virtual addresses of your process from maps ( This is done so that you don't search every byte in pagemap ) Then check for the physical mapping of the desired virtual address in pagemap ( pagemap is not in text format. Here is a detailed explantion of the format Pagemap ) This should give you the exact virtual-->physical mapping首先,从映射中找出进程的虚拟地址的maps (这样做是为了不搜索pagemap中所需虚拟地址的物理映射(pagemap 不是文本格式. 这是Pagemap格式的详细解释)这应该给你准确的虚拟->物理映射

It sounds like you're looking for virt_to_phys .听起来您正在寻找virt_to_phys

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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