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. But it's not exported to kernel modules (why???)...
除了手动遍历页面目录条目之外,有没有合适的方法来获取逻辑地址的物理地址?我在内核的源代码中寻找了这个功能,并发现有一个follow_page函数可以很好地完成内置的巨大且透明的大页面支持。但它没有导出到内核模块(为什么???)...
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功能并不是很好。
3 个解决方案
#1
5
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);
}
}
}
}
#2
3
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
我认为你可以通过/ proc / [pid] / maps(给出进程的虚拟映射)和/ proc / [pid] / pagemap(给虚拟页面到物理)的组合,通过间接方法实现虚拟 - >物理翻译每个可寻址页面的页面映射)。首先,从地图中找出您的进程的虚拟地址的映射(这样做是为了不搜索页面映射中的每个字节)然后检查页面映射中所需虚拟地址的物理映射(页面映射不是文本格式以下是格式(Pagemap)的详细说明。这应该为您提供精确的虚拟 - >物理映射
#1
5
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);
}
}
}
}
#2
3
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
我认为你可以通过/ proc / [pid] / maps(给出进程的虚拟映射)和/ proc / [pid] / pagemap(给虚拟页面到物理)的组合,通过间接方法实现虚拟 - >物理翻译每个可寻址页面的页面映射)。首先,从地图中找出您的进程的虚拟地址的映射(这样做是为了不搜索页面映射中的每个字节)然后检查页面映射中所需虚拟地址的物理映射(页面映射不是文本格式以下是格式(Pagemap)的详细说明。这应该为您提供精确的虚拟 - >物理映射