内存管理初始化源码4:add_active_range
Posted 若离相惜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了内存管理初始化源码4:add_active_range相关的知识,希望对你有一定的参考价值。
我们在阅读源码时,函数功能可以分为两类:1. bootmem.c 2. page_alloc.c。
1. bootmem.c是关于bootmem allocator的,上篇文章已经简述过。
2. page_alloc.c是关于Memory Management subsystem的。
关于内存管理子系统的初始化调用了多个函数,我们首先分析在bootmem_init中调用的add_active_range函数。
start_kernel --> setup_arch ---> arch_mem_init ---> bootmem_init ---> add_active_range.
通过上述分析,我们此时可以确认内存信息,那么我们确认的内存信息必然要告诉Memory Management subsystem,首先通过add_active_range完成。
调用两次add_active_range:
1. add_active_range(0, start, end); // start = 0, end = 57344
2. add_active_range(0, start, end); // start = 196608, end = 262144
/** * add_active_range - Register a range of PFNs backed by physical memory 【注册物理内存的PFN范围】 * @nid: The node ID the range resides on * @start_pfn: The start PFN of the available physical memory * @end_pfn: The end PFN of the available physical memory
* @id : 该物理内存所属的内存结点。由于我们是UMA系统,只用一个内存结点,所以我们在调用时,传入的参数为0. * @start_pfn: 可用物理内存的开始PFN号
* @end_pfn: 可用屋里内存的结束PFN号 * These ranges are stored in an early_node_map[] and later used by * free_area_init_nodes() to calculate zone sizes and holes. If the * range spans a memory hole, it is up to the architecture to ensure * the memory is not freed by the bootmem allocator. If possible * the range being registered will be merged with existing ranges.
* 传入的物理内存信息存储到一个数组中:early_node_map[], 稍后会在 free_area_init_nodes() 函数中使用,用来计算 zone sizes 和 holes。
* 如果物理内存的范围包含一个 memory hole,it is up to the architecture to ensure the memory is not freed by the bootmem allocator.
* 新注册的物理内存范围会Merge到已经存在的物理内存范围中去。 */ void __init add_active_range(unsigned int nid, unsigned long start_pfn, unsigned long end_pfn) { int i; mminit_dprintk(MMINIT_TRACE, "memory_register", "Entering add_active_range(%d, %#lx, %#lx) " "%d entries of %d used\n", nid, start_pfn, end_pfn, nr_nodemap_entries, MAX_ACTIVE_REGIONS); mminit_validate_memmodel_limits(&start_pfn, &end_pfn); // 对start_pfn 和 end_pfn 做某些验证,我们不Care /* Merge with existing active regions if possible */ for (i = 0; i < nr_nodemap_entries; i++) { if (early_node_map[i].nid != nid) continue; /* Skip if an existing region covers this new one */ if (start_pfn >= early_node_map[i].start_pfn && end_pfn <= early_node_map[i].end_pfn) return; /* Merge forward if suitable */ if (start_pfn <= early_node_map[i].end_pfn && end_pfn > early_node_map[i].end_pfn) { early_node_map[i].end_pfn = end_pfn; return; } /* Merge backward if suitable */ if (start_pfn < early_node_map[i].start_pfn && end_pfn >= early_node_map[i].start_pfn) { early_node_map[i].start_pfn = start_pfn; return; } } /* Check that early_node_map is large enough */ // earlay_node_map数组有上限 if (i >= MAX_ACTIVE_REGIONS) { printk(KERN_CRIT "More than %d memory regions, truncating\n", MAX_ACTIVE_REGIONS); return; } early_node_map[i].nid = nid; early_node_map[i].start_pfn = start_pfn; early_node_map[i].end_pfn = end_pfn; nr_nodemap_entries = i + 1;
/*
early_node_map[0].nid = 0;
early_node_map[0].start_pfn = 0;
early_node_map[0].end_pfn = 57344;
early_node_map[1].nid = 0;
early_node_map[1].start_pfn = 196608;
early_node_map[1].end_pfn = 262144;
很好理解,不啰嗦了!!!
*/ }
总结:我们在从command_line中确定了屋里内存信息后,这是第一个把这个好消息告诉了buddy system。所以,一定要记住这个关键的数组——>early_node_map.
以上是关于内存管理初始化源码4:add_active_range的主要内容,如果未能解决你的问题,请参考以下文章
Linux 内核 内存管理Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )
Linux 内核 内存管理Linux 内核内存布局 ④ ( ARM64 架构体系内存分布 | 内核启动源码 start_kernel | 内存初始化 mm_init | mem_init )
内存管理初始化源码5:free_area_init_nodes
Linux 内核 内存管理虚拟地址空间布局架构 ② ( 用户虚拟地址空间组成 | 内存描述符 mm_struct 结构体源码 )