本文共 4566 字,大约阅读时间需要 15 分钟。
pfn_valid(pfn)用于判断page index是否是有效的page。如下所示: source/include/asm-generic/page.h #define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr) ARCH_PFN_OFFSET 定义在下面的文件中 source/arch/arm/include/asm/memory.h #define ARCH_PFN_OFFSET PHYS_PFN_OFFSET 继续PHYS_PFN_OFFSET 定义如下 source/arch/arm/include/asm/memory.h 162 #if defined(__virt_to_phys) 163 #define PHYS_OFFSET PLAT_PHYS_OFFSET 164 #define PHYS_PFN_OFFSET ((unsigned long)(PHYS_OFFSET >> PAGE_SHI 135 #define PLAT_PHYS_OFFSET UL(CONFIG_PHYS_OFFSET) 可见PHYS_OFFSET 定义成PLAT_PHYS_OFFSET,而PLAT_PHYS_OFFSET又被定义成CONFIG_PHYS_OFFSET。而CONFIG_PHYS_OFFSET一般是在kernel的defconfig文件中配置的,我们这边平台上定义的是0.也就是第一个page. 所以pfn_valid 定义现在如下: #define pfn_valid(pfn) ((pfn) >= 0 && ((pfn) < max_mapnr) 我们继续来看max_mapnr的定义。 source/include/linux/mm.h 38 static inline void set_max_mapnr(unsigned long limit) 39 { 40 max_mapnr = limit; 41 } 调用set_max_mapnr 如下: arch/arm/mm/init.c 477 void __init mem_init(void) 478 { 479 #ifdef CONFIG_HAVE_TCM 480 /* These pointers are filled in on TCM detection */ 481 extern u32 dtcm_end; 482 extern u32 itcm_end; 483 #endif 484 485 set_max_mapnr(pfn_to_page(max_pfn) - mem_map); 可见max_mapnr = pfn_to_page(max_pfn) - mem_map。 而max_pfn 赋值如下: 282 void __init bootmem_init(void) 283 { 284 unsigned long min, max_low, max_high; 285 286 memblock_allow_resize(); 287 max_low = max_high = 0; 288 289 find_limits(&min, &max_low, &max_high); 290 291 early_memtest((phys_addr_t)min << PAGE_SHIFT, 292 (phys_addr_t)max_low << PAGE_SHIFT); 293 294 /* 295 * Sparsemem tries to allocate bootmem in memory_present(), 296 * so must be done after the fixed reservations 297 */ 298 arm_memory_present(); 299 300 /* 301 * sparse_init() needs the bootmem allocator up and running. 302 */ 303 sparse_init(); 304 305 /* 306 * Now free the memory - free_area_init_node needs 307 * the sparse mem_map arrays initialized by sparse_init() 308 * for memmap_init_zone(), otherwise all PFNs are invalid. 309 */ 310 zone_sizes_init(min, max_low, max_high); 311 312 /* 313 * This doesn't seem to be used by the Linux memory manager any 314 * more, but is used by ll_rw_block. If we can get rid of it, we 315 * also get rid of some of the stuff above as well. 316 */ 317 min_low_pfn = min; 318 max_low_pfn = max_low; 319 max_pfn = max_high; 320 } 在319行赋值max_high。而max_high是在find_limits函数中赋值 90 static void __init find_limits(unsigned long *min, unsigned long *max_low, 91 unsigned long *max_high) 92 { 93 *max_low = PFN_DOWN(memblock_get_current_limit()); 94 *min = PFN_UP(memblock_start_of_DRAM()); 95 *max_high = PFN_DOWN(memblock_end_of_DRAM()); 96 } 可见max_high 表示memblock的最后一个page 所以max_pfn就表示memblock的最后一个page. 我们在来看看mem_map的赋值 6030 static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat) 6031 { 6032 unsigned long __maybe_unused start = 0; 6033 unsigned long __maybe_unused offset = 0; 6034 6035 /* Skip empty nodes */ 6036 if (!pgdat->node_spanned_pages) 6037 return; 6038 6039 #ifdef CONFIG_FLAT_NODE_MEM_MAP 6040 start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1); 6041 offset = pgdat->node_start_pfn - start; 6042 /* ia64 gets its own node_mem_map, before this, without bootmem */ 6043 if (!pgdat->node_mem_map) { 6044 unsigned long size, end; 6045 struct page *map; 6046 6047 /* 6048 * The zone's endpoints aren't required to be MAX_ORDER 6049 * aligned but the node_mem_map endpoints must be in order 6050 * for the buddy allocator to function correctly. 6051 */ 6052 end = pgdat_end_pfn(pgdat); 6053 end = ALIGN(end, MAX_ORDER_NR_PAGES); 6054 size = (end - start) * sizeof(struct page); 6055 map = alloc_remap(pgdat->node_id, size); 6056 if (!map) 6057 map = memblock_virt_alloc_node_nopanic(size, 6058 pgdat->node_id); 6059 pgdat->node_mem_map = map + offset; 6060 } 6061 #ifndef CONFIG_NEED_MULTIPLE_NODES 6062 /* 6063 * With no DISCONTIG, the global mem_map is just set as node 0's 6064 */ 6065 if (pgdat == NODE_DATA(0)) { 6066 mem_map = NODE_DATA(0)->node_mem_map; 6067 #if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM) 6068 if (page_to_pfn(mem_map) != pgdat->node_start_pfn) 6069 mem_map -= offset; 6070 #endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ 6071 } 6072 #endif 6073 #endif /* CONFIG_FLAT_NODE_MEM_MAP */ 6074 } 在6066行赋值,mem_map = NODE_DATA(0)->node_mem_map而node_mem_map是由6059行赋值的 如下所示: 而pgdat->node_mem_map = map + offset; offset 在我们的平台上等于0,所以pgdat->node_mem_map = map; 所以 set_max_mapnr(pfn_to_page(max_pfn) - mem_map); 就等于两个地址相减,就等于max_pfn,即总的page 个数. 所以pfn_valid 的函数就很明确,代表系统page index是否在总的dram size中,或者可以这么理解page index是否在low memory + high_memmory中.转载地址:http://avcmi.baihongyu.com/