SPARSEMEM VMEMMAP 是SPARSEMEM的一个具体实现方式,它使用vmemmap数据结构来管理内存。vmemmap是一个数组,每个元素对应一个page frame的描述符,包含了该page frame的状态、大小等信息。
VMEMMAP 通过提供更详细的内存映射信息,帮助系统更有效地管理和分配内存。
/* linux-4.9.37/include/asm-generic/memory_model.h */
#define page_to_pfn __page_to_pfn
#define pfn_to_page __pfn_to_page
/* memmap is virtually contiguous. */
#define __pfn_to_page(pfn) (vmemmap + (pfn))
#define __page_to_pfn(page) (unsigned long)((page) - vmemmap)
/* linux-4.9.37/arch/arm64/include/asm/page.h */
#define PAGE_SHIFT CONFIG_ARM64_PAGE_SHIFT // 12, .config:10:CONFIG_ARM64_PAGE_SHIFT=12
/* linux-4.9.37/arch/arm64/include/asm/pgtable.h */
#define vmemmap ((struct page *)VMEMMAP_START - (memstart_addr >> PAGE_SHIFT))
/* linux-4.9.37/arch/arm64/include/asm/memory.h */
/*
* VMEMMAP_SIZE - allows the whole linear region to be covered by
* a struct page array
*/
#define VMEMMAP_SIZE (UL(1) << (VA_BITS - PAGE_SHIFT - 1 + STRUCT_PAGE_MAX_SHIFT)) // (1 << (39 - 12 - 1 + 6)) = 1 << 32 = 0x100000000 = 4G
#define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1)) // 0xFFFFFFC000000000 0xFFFF FFC0 0000 0000
#define VMEMMAP_START (PAGE_OFFSET - VMEMMAP_SIZE) // 0xFFFFFFC000000000 - 0x100000000 = 0xFFFFFFBF00000000
/*
* memstart_addr
*/
/* linux-4.9.37/arch/arm64/mm/init.c */
/*
* We need to be able to catch inadvertent references to memstart_addr
* that occur (potentially in generic code) before arm64_memblock_init()
* executes, which assigns it its actual value. So use a default value
* that cannot be mistaken for a real physical address.
*/
s64 memstart_addr __ro_after_init = -1;
void __init arm64_memblock_init(void)
{
const s64 linear_region_size = -(s64)PAGE_OFFSET;
/*
* Ensure that the linear region takes up exactly half of the kernel
* virtual address space. This way, we can distinguish a linear address
* from a kernel/module/vmalloc address by testing a single bit.
*
* 确保线性区域正好占用内核虚拟地址空间的一半。这样,
* 我们可以通过测试单个位来区分线性地址和内核/模块/vmalloc地址。
*/
BUILD_BUG_ON(linear_region_size != BIT(VA_BITS - 1)); // 一半
/*
* Select a suitable value for the base of physical memory.
*
* 为物理内存的基数选择一个合适的值
*/
memstart_addr = round_down(memblock_start_of_DRAM(),
ARM64_MEMSTART_ALIGN);
/*
* Remove the memory that we will not be able to cover with the
* linear mapping. Take care not to clip the kernel which may be
* high in memory.
*
* 移除线性映射无法覆盖的内存。注意不要重叠内存可能很高的内核
*/
memblock_remove(max_t(u64, memstart_addr + linear_region_size, __pa(_end)),
ULLONG_MAX);
if (memstart_addr + linear_region_size < memblock_end_of_DRAM()) {
/* ensure that memstart_addr remains sufficiently aligned 确保memstart_addr保持充分对齐 */
memstart_addr = round_up(memblock_end_of_DRAM() - linear_region_size,
ARM64_MEMSTART_ALIGN);
memblock_remove(0, memstart_addr);
}
.......
}
/* linux-4.9.37/arch/arm64/kernel/arm64ksyms.c */
/* physical memory */
EXPORT_SYMBOL(memstart_addr);
3333

被折叠的 条评论
为什么被折叠?



