The followings are some ways to translate a virtual address to the corresponding physical address, if exist.
Step 1. Walk the page tables to get pte_t *
.
// struct mm_struct *mm : The memory descriptor of the current process.
// unsigned long address: The virtual address to be translated.
pgd_t *pgd = pgd_offset(mm, address);
if (!pgd_none(*pgd) && !pgd_bad(*pgd)) {
pud_t *pud = pud_offset(pgd, address);
if (!pud_none(*pud) && !pud_bad(*pud)) {
pmd_t *pmd = pmd_offset(pud, address);
if (!pmd_none(*pmd) && !pmd_bad(*pmd)) {
pte_t *pte = pte_offset_map(pmd, address);
if (!pte_none(*pte)) {
// now you get a pointer pointing to a pte entry!
}
pte_unmap(pte);
}
}
}
Step 2.
- A) Calculate the bits directly.
// Assume it is on 32-bit machine with 4 KB pages.
unsigned long phys = pte_val(*pte) & 0xfffff000 + address & 0x00000fff;
- B) With the help of a page descriptor.
struct page *pg = pte_page(*pte);
unsigned long phys = page_to_phys(pg);
cat /proc/<pid>/maps
to get virtual address intervals.
xxd /proc/<pid>/pagemap
to get virtual - physical address mappings.
documention
-
virt_to_page(unsigned long address)
seems to be a faster way to getstruct page*
, but you have to make sure the return value is valid. (code) -
virt_to_phys(volatile void *address)
is only suitable for addresses directly mapped or mapped by kmalloc. (code)
- Understanding the Linux Kernel 3rd (Daniel P. Bovet, Marco Cesati), Sections 2.5, 8.1, 9.2, etc.
- page_to_phys from <asm/io.h>
- How to get the physical address from the logical one in a Linux kernel module? Stack Overflow
- How to find the physical address of a variable from user-space in Linux? Stack Overflow