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

后端 未结 3 1091
刺人心
刺人心 2020-12-08 17:06

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

相关标签:
3条回答
  • 2020-12-08 17:49

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

    0 讨论(0)
  • 2020-12-08 17:49

    It sounds like you're looking for virt_to_phys.

    0 讨论(0)
  • 2020-12-08 18:06

    Well, it might looks as something like that (follow PTE from an virtual address):

    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);
                }
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题