4

In a kernel module (2.6.32-358.el6.x86_64) I'd like to print out all the physical addresses, which are mapped into a process' virtual memory. Given task->mm, I attempt to traverse the process' struct page's as follows:

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); } } } } 

The output looks a bit strange (in particular, there are serieses of identical addresses), so I'd like to ask whether the above is correct, in theory.

1
  • The series of identical addresses are probably copy-on-write mappings of the zero page. Commented Jan 6, 2014 at 3:24

2 Answers 2

5

A better approach would be to traverse process' VMAs and translate each VMA to physical pages/addresses by means of the page directory:

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

Where virt2phys would look like this:

//... 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; 
Sign up to request clarification or add additional context in comments.

Comments

1

Since the code from the previous answer is pretty old and we now have 5-level paging on some CPUs here is an updated version:

#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); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.