有些时候需要根据已有的虚拟地址获得对应的物理地址,尤其是需要进行DMA的场景。
对于低端内存来说,由于物理地址和虚拟地址有一个固定的差值(PAGE_OFFSET),因此通过__pa()或者virt_to_phys()便可直接获得对应的物理地址;
但是对于高端地址,比如使用vmalloc或者ioremap映射得到的虚拟地址,是无法直接得到的。
然而无论如何,所有使用中的虚拟地址必定都在页表中与物理地址存在一个对应关系,我们可以借助该对应关系找到一个虚拟地址virt_addr对应的物理地址phy_addr,具体方法如下:
pgd_t *pgd = pgd_offset(current->active_mm, virt_addr); /* 找到页全局目录项指针*/
或者pgd_t *pgd = pgd_offset_k(address);
pud_t *pud = pud_offset(pgd, virt_addr); /* 获得pud指针 */
pmd_t *pmd = pmd_offset(pud, virt_addr); /* 获得pmd 指针*/
pte_t *pte = pte_offset_kernel(pmd, virt_addr); /* 获得pte指针,pte中存储的就是物理地址相关的信息 */
目标物理地址:phy_addr = pte_val(*pte) & PTE_PFN_MASK;
物理地址对应的页帧号:pfn = pte_pfn(*pte)
另外几个比较常用的宏函数:
物理页帧号与struct page的转换:pfn_to_page & page_to_pfn
物理地址与struct page的转换:page_to_phys & phys_to_page
查看virt_addr指向的page是否在物理内存中(可能会被交换到swap分区):pte_present(*pte)
本文内容如有错误,欢迎留言指正。