kernel: 5.10
arch: arm64
VMEMMAP区域存放的的是struct page结构体,pfn_to_page实际就是通过物理页帧号来从VMEMMAP区域索引到对应的struct page结构体
#define pfn_to_page __pfn_to_page
对于定义了CONFIG_SPARSEMEM_VMEMMAP宏,则
#define __pfn_to_page(pfn) (vmemmap + (pfn))
注意pfn是按照实际的物理地址编号的,如本例中物理内存起始地址为0x40000000,起始物理页帧号为0x40000
vmemmap 定义如下:
#define vmemmap ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
memstart_addr为物理地址0x40000000,从打印上看vmemmap为0xfffffdfffee00000,它就是用来存放struct page结构体的虚拟空间起始地址偏移(memstart_addr >> PAGE_SHIFT),为何会有这个偏移?原因是实际物理页帧号是根据实际的物理地址计算的,并非从0开始,当然也可以将vmemmap理解成是物理地址0x0对应的struct page所在的位置,只不过内存物理地址一般不是从0x0开始。
#define SZ_2M 0x00200000
#define VMEMMAP_START (-VMEMMAP_SIZE - SZ_2M)
通过打印看VMEMMAP_START:0xfffffdffffe00000,它位于虚拟地址空间PCI I/O区间以上,不知道VMEMMAP_START为何会这样计算?它就是VMEMMAP空间的起始地址
#define _PAGE_END(va) (-(UL(1) << ((va) - 1)))
#define VA_BITS_MIN (VA_BITS)
#define VA_BITS (CONFIG_ARM64_VA_BITS)
/*
* VMEMMAP_SIZE - allows the whole linear region to be covered by
* a struct page array
*
* If we are configured with a 52-bit kernel VA then our VMEMMAP_SIZE
* needs to cover the memory region from the beginning of the 52-bit
* PAGE_OFFSET all the way to PAGE_END for 48-bit. This allows us to
* keep a constant PAGE_OFFSET and "fallback" to using the higher end
* of the VMEMMAP where 52-bit support is not available in hardware.
*/
#define VMEMMAP_SIZE ((_PAGE_END(VA_BITS_MIN) - PAGE_OFFSET) \
>> (PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT))
通过打印_PAGE_END(VA_BITS_MIN)可以得到虚拟地址为:0xffff800000000000也就是线性映射区的结束地址,而PAGE_OFFSET为线性映射区的起始地址,PAGE_SHIFT - STRUCT_PAGE_MAX_SHIFT代表一个页可以存放多少个struct page结构体,因此整体VMEMMAP_SIZE就表示线性影射区需要多少页大小的空间来存放struct page结构体