arm64内存-sparsemem-宏定义和指针数组空间分配
相关的宏定义
arch/arm64/include/asm/sparsemem.h
9#define MAX_PHYSMEM_BITS CONFIG_ARM64_PA_BITS 10#define SECTION_SIZE_BITS 30
MAX_PHYSMEM_BIT 最大物理内存地址bits - 通常 CONFIG_ARM64_PA_BITS 为 48
SECTION_SIZE_BITS 一个section 大小,1G
include/linux/page-flags-layout.h
30/* SECTION_SHIFT #bits space required to store a section # */ 31#define SECTIONS_SHIFT (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS)
48 - 30 = 18 ,物理地址的 30 ~ 47 bit 表示 section idx。 section idx 占用的 bits 数 。
include/linux/mmzone.h
1158#define PA_SECTION_SHIFT (SECTION_SIZE_BITS) // 30 1159#define PFN_SECTION_SHIFT (SECTION_SIZE_BITS - PAGE_SHIFT) // 30 - 12 = 18 bit 12 ~ 29 这 18 个bits 表示 pfn 的idx 1160 1161#define NR_MEM_SECTIONS (1UL << SECTIONS_SHIFT) // 最大的 section idx 值 1162 1163#define PAGES_PER_SECTION (1UL << PFN_SECTION_SHIFT) // 最大的 pfn 值 1164#define PAGE_SECTION_MASK (~(PAGES_PER_SECTION-1)) // pfn idx round down 到 pfn 所在的 section 的第一个 pfn 使用的mask。
// pfn = pfn & PAGE_SECTION_MASK 即round down, 到 pfn 对应的 section 的 第 0 个 pfn 1165 1244#define SECTIONS_PER_ROOT (PAGE_SIZE / sizeof (struct mem_section)) // 一页 可以存放的 mem_section 对象个数 1249#define SECTION_NR_TO_ROOT(sec) ((sec) / SECTIONS_PER_ROOT) // mem_section idx 转 root idx 1250#define NR_SECTION_ROOTS DIV_ROUND_UP(NR_MEM_SECTIONS, SECTIONS_PER_ROOT) // root idx 最大值 1251#define SECTION_ROOT_MASK (SECTIONS_PER_ROOT - 1) // 取 root idx 使用的 mask 1254extern struct mem_section **mem_section; // mem_section 指向 指针数组 .
结构体定义
include/linux/mmzone.h
CONFIG_PAGE_EXTENSION 没有 设置的情况下
1213struct mem_section { 1226 unsigned long section_mem_map; // 这个是一个 地址 + 额外信息。 地址 存在 高位,额外信息存低位。地址处放 struct page 对象数组,数组个数 PAGES_PER_SECTION
1228 struct mem_section_usage *usage; 1241};
对齐之后,arm64 上面占用 16 个字节的大小。
一页 4K ,可以存放 256 个 mem_section 对象。
mem_section 空间分配
sparse_init -> memblocks_present -> memory_present
252static void __init memory_present(int nid, unsigned long start, unsigned long end) 253{ 254 unsigned long pfn; 255 256#ifdef CONFIG_SPARSEMEM_EXTREME 257 if (unlikely(!mem_section)) { 258 unsigned long size, align; 259 260 size = sizeof(struct mem_section*) * NR_SECTION_ROOTS; 261 align = 1 << (INTERNODE_CACHE_SHIFT); 262 mem_section = memblock_alloc(size, align); 263 if (!mem_section) 264 panic("%s: Failed to allocate %lu bytes align=0x%lx\n", 265 __func__, size, align); 266 } 267#endif 292static void __init memblocks_present(void) 293{ 294 unsigned long start, end; 295 int i, nid; 296 297 for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, &nid) 298 memory_present(nid, start, end); 299} 300 575void __init sparse_init(void) 576{ 577 unsigned long pnum_end, pnum_begin, map_count = 1; 578 int nid_begin; 579 580 memblocks_present();
257 - mem_section 如果为 0 ,则使用 memblock 分配 空间,存放 指针数组,数组个数为 NR_SECTION_ROOTS
如果 mem_section 非0,说明已经分配了,不再分配。