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 th开发者_开发百科at there is a follow_page
function that do it well with built-in huge and transparent-huge pages support. But it's not exported to kernel modules (why???)...
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.
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);
}
}
}
}
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
It sounds like you're looking for virt_to_phys
.
精彩评论