linux mm 之 SPARSEMEM VMEMMAP page_to_pfn 与 pfn_to_page

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);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值