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中.
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中.