遍历进程的所有物理页

问题描述 投票:0回答:2

在内核模块(2.6.32-358.el6.x86_64)中,我想打印出所有映射到进程虚拟内存的物理地址。给定

task->mm
,我尝试遍历该过程'
struct page
,如下所示:

int i, j, k, l;
for (i = 0; i < PTRS_PER_PGD; ++i)
{
    pgd_t *pgd = mm->pgd + i;
    if (pgd_none(*pgd) || pgd_bad(*pgd))
        continue;
    for (j = 0; j < PTRS_PER_PUD; ++j)
    {
        pud_t *pud = (pud_t *)pgd_page_vaddr(*pgd) + j;
        if (pud_none(*pud) || pud_bad(*pud))
            continue;
        for (k = 0; k < PTRS_PER_PMD; ++k)
        {
            pmd_t *pmd = (pmd_t *)pud_page_vaddr(*pud) + k;
            if (pmd_none(*pmd) || pmd_bad(*pmd))
                continue;

            for (l = 0; l < PTRS_PER_PTE; ++l)
            {
                pte_t *pte = (pte_t *)pmd_page_vaddr(*pmd) + l;
                if (!pte || pte_none(*pte))
                    continue;
                struct page *p = pte_page(*pte);
                unsigned long phys = page_to_phys(p);
                printk(KERN_NOTICE "addr %lx", phys);
            }
        }
    }
}

输出看起来有点奇怪(特别是有一系列相同的地址),所以我想问一下,理论上,上面是否正确。

memory-management linux-kernel virtual-memory
2个回答
5
投票

更好的方法是遍历进程的 VMA 并通过页目录将每个 VMA 转换为物理页/地址:

struct vm_area_struct *vma = 0;
unsigned long vpage;
if (task->mm && task->mm->mmap)
    for (vma = task->mm->mmap; vma; vma = vma->vm_next)
        for (vpage = vma->vm_start; vpage < vma->vm_end; vpage += PAGE_SIZE)
            unsigned long phys = virt2phys(task->mm, vpage);
//...

哪里

virt2phys
看起来像这样:

//...
pgd_t *pgd = pgd_offset(mm, virt);
if (pgd_none(*pgd) || pgd_bad(*pgd))
    return 0;
pud = pud_offset(pgd, virt);
if (pud_none(*pud) || pud_bad(*pud))
    return 0;
pmd = pmd_offset(pud, virt);
if (pmd_none(*pmd) || pmd_bad(*pmd))
    return 0;
if (!(pte = pte_offset_map(pmd, virt)))
    return 0;
if (!(page = pte_page(*pte)))
    return 0;
phys = page_to_phys(page);
pte_unmap(pte);
return phys;

0
投票

由于之前答案中的代码相当旧,而且我们现在在某些 CPU 上有 5 级分页,这里是更新版本:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kvm_host.h>
#include <asm/virtext.h>
#include <asm/cpu.h>
#include <asm/tdx.h>
#include <kvm/iodev.h>
#include <linux/kvm_host.h>
#include <linux/kvm.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/percpu.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/vmalloc.h>
#include <linux/reboot.h>
#include <linux/debugfs.h>
#include <linux/highmem.h>
#include <linux/file.h>
#include <linux/syscore_ops.h>
#include <linux/cpu.h>
#include <linux/sched/signal.h>
#include <linux/sched/mm.h>
#include <linux/sched/stat.h>
#include <linux/cpumask.h>
#include <linux/smp.h>
#include <linux/anon_inodes.h>
#include <linux/profile.h>
#include <linux/kvm_para.h>
#include <linux/pagemap.h>
#include <linux/mman.h>
#include <linux/swap.h>
#include <linux/bitops.h>
#include <linux/spinlock.h>
#include <linux/compat.h>
#include <linux/srcu.h>
#include <linux/hugetlb.h>
#include <linux/slab.h>
#include <linux/sort.h>
#include <linux/bsearch.h>
#include <linux/io.h>
#include <linux/lockdep.h>
#include <linux/kthread.h>
#include <linux/suspend.h>
#include <linux/version.h>
#include <asm/processor.h>
#include <asm/ioctl.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>


MODULE_LICENSE("GPL");

unsigned long virt2phys(struct mm_struct *mm, unsigned long virt){
    pgd_t *pgd;
    p4d_t *p4d;
    pud_t *pud;
    pmd_t *pmd;
    pte_t *pte;
    unsigned long phys;
    struct page *page;
    pgd = pgd_offset(mm, virt);
    if (pgd_none(*pgd) || pgd_bad(*pgd))
        return 0;
    p4d = p4d_offset(pgd, virt);
    if (p4d_none(*p4d) || p4d_bad(*p4d))
        return 0;
    pud = pud_offset(p4d, virt);
    if (pud_none(*pud) || pud_bad(*pud))
        return 0;
    pmd = pmd_offset(pud, virt);
    if (pmd_none(*pmd) || pmd_bad(*pmd))
        return 0;
    if (!(pte = pte_offset_map(pmd, virt)))
        return 0;
    if (!(page = pte_page(*pte)))
        return 0;
    phys = page_to_phys(page);
    pte_unmap(pte);
    return phys;
}

static int __init
lkm_example_init(void)
{
    int pid = 1;
    struct task_struct *tsk;
    struct mm_struct *mm;
    struct vm_area_struct *vma = 0;
    unsigned long vpage;
    unsigned long phys;

    tsk = pid_task(find_vpid(pid), PIDTYPE_PID);
    mm = tsk->mm;

    if (mm && mm->mmap){
        for (vma = mm->mmap; vma; vma = vma->vm_next){
            for (vpage = vma->vm_start; vpage < vma->vm_end; vpage += PAGE_SIZE){
                phys = virt2phys(mm, vpage);
                pr_info("phys 0x%lx",phys);
            }
        }
    }
    return -1;
}

static void __exit
lkm_example_exit(void)
{
    pr_info("Goodbye, World!\n");
    return;
}

module_init(lkm_example_init);
module_exit(lkm_example_exit);
© www.soinside.com 2019 - 2024. All rights reserved.