__virt_to_phys与__phys_to_virt
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) { struct page *page; /* * __get_free_pages() returns a 32-bit address, which cannot represent * a highmem page */ VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0); page = alloc_pages(gfp_mask, order); if (!page) return 0; return (unsigned long) page_address(page); }
kernel/4.9includelinuxMm.h #if !defined(HASHED_PAGE_VIRTUAL) && !defined(WANT_PAGE_VIRTUAL) #define page_address(page) lowmem_page_address(page) #define set_page_address(page, address) do { } while(0) #define page_address_init() do { } while(0) #endif
static __always_inline void *lowmem_page_address(const struct page *page) { return page_to_virt(page); }
kernel4.9includelinuxMm.h #ifndef page_to_virt #define page_to_virt(x) __va(PFN_PHYS(page_to_pfn(x))) #endif
kernel4.9includeasm-genericMemory_model.h #elif defined(CONFIG_SPARSEMEM_VMEMMAP) /* memmap is virtually contiguous. */ #define __pfn_to_page(pfn) (vmemmap + (pfn)) //根据这两个macro,可以看出pfn实际就是page的index #define __page_to_pfn(page) (unsigned long)((page) - vmemmap)
#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT)
kernel4.9archarm64includeasmMemory.h #ifndef __phys_to_virt #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET) | PAGE_OFFSET) #endif #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
virt_to_page
kernel4.9archarm64includeasmMemory.h #define __virt_to_phys(x) ({ phys_addr_t __x = (phys_addr_t)(x); __x & BIT(VA_BITS - 1) ? (__x & ~PAGE_OFFSET) + PHYS_OFFSET : (__x - kimage_voffset); }) #define __pa(x) __virt_to_phys((unsigned long)(x)) #define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
如果VA_BITS = 39
#define PAGE_OFFSET (UL(0xffffffffffffffff) -
(UL(1) << (VA_BITS - 1)) + 1)
==>
PAGE_OFFSET = 0xFFFFFFC000000000
上述__virt_to_phys macro define里BIT(VA_BITS - 1)即BIT(38),等于0x4000000000,和0xFFFFFFC000000000相与,结果是1,所以取(__x & ~PAGE_OFFSET) + PHYS_OFFSET,和__phys_to_virt里的操作相反
vmemmap=(struct page *)ffffffbdbf000000 //MACRO, can't get from KE minidump, can dump to log
example:
pfn=fa193=>page=(struct page *)ffffffbdbf000000+fa193=(struct page *)(ffffffbdbf000000+fa193*64)=(struct page *)ffffffbdc2e864c0
page=ffffffbdc2e864c0=>pfn=(unsigned long)((struct page *)ffffffbdc2e864c0-(struct page *)ffffffbdbf000000)=(unsigned long)((ffffffbdc2e864c0-ffffffbdbf000000)/64)=fa193
64 is sizeof(struct page)
PTE 2 PFN/PFN 2 PTE
#define pte_pfn(pte) ((pte_val(pte) & PHYS_MASK) >> PAGE_SHIFT)
#define pfn_pte(pfn,prot) (__pte(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))