对于一个这样的参数 mem=151M mem=118M@768M 内核中是怎么处理的已经在前篇文章里提到。这里再详细分析一下由这三个数据而引发的一连串的计算。使用这个参数的内核在启动过程中打印的内存信息:
- [ 0.000000] Determined physical RAM map:
- [ 0.000000] memory: 04000000 @ 00000000 (usable)
- [ 0.000000] User-defined physical RAM map:
- [ 0.000000] memory: 09700000 @ 00000000 (usable)
- [ 0.000000] memory: 07600000 @ 30000000 (usable)
- [ 0.000000] Zone PFN ranges:
- [ 0.000000] Normal 0x00000000 -> 0x00020000
- [ 0.000000] HighMem 0x00020000 -> 0x00037600
- [ 0.000000] Movable zone start PFN for each node
- [ 0.000000] early_node_map[2] active PFN ranges
- [ 0.000000] 0: 0x00000000 -> 0x00009700
- [ 0.000000] 0: 0x00030000 -> 0x00037600
- [ 0.000000] On node 0 totalpages: 68864
- [ 0.000000] Normal zone: 1152 pages used for memmap
- [ 0.000000] Normal zone: 0 pages reserved
- [ 0.000000] Normal zone: 37504 pages, LIFO batch:7
- [ 0.000000] Initialising map node 0 zone 0 pfns 0 -> 131072
- [ 0.000000] HighMem zone: 842 pages used for memmap
- [ 0.000000] HighMem zone: 29366 pages, LIFO batch:7
- [ 0.000000] Initialising map node 0 zone 1 pfns 131072 -> 226816
- [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 66870
- …………
- [ 0.092000] Memory: 266060k/154624k available (3044k kernel code, 9152k reserved, 1166k data, 152k init, 120832k highmem)
这里的“Determined physical RAM map:”和“User-defined physical RAM map:”便是由arch_mem_init函数根据boot_mem_map里面的信息打印的。前者是自动检测的,后者是启动参数指定的。并且前者会被后者覆盖,除非启动参数中不指定mem参数。
下面对这一大堆数据慢慢地做做计算, 看看它们到底是怎么得来的。
- [ 0.000000] Zone PFN ranges:
- [ 0.000000] Normal 0x00000000 -> 0x00020000
- [ 0.000000] HighMem 0x00020000 -> 0x00037600
- [ 0.000000] Movable zone start PFN for each node
- [ 0.000000] early_node_map[2] active PFN ranges
- [ 0.000000] 0: 0x00000000 -> 0x00009700
- [ 0.000000] 0: 0x00030000 -> 0x00037600
代码位置:head.S --> start_kernel --> setup_arch --> arch_mem_init --> paging_init --> free_area_init_nodes
这一段log就是由free_area_init_nodes函数打印的。
Zone PFN ranges打印的是每个Zone最小和最大可能的PFN取值。这只是一个允许的取值范围,并不一定是真正用到的PFN值。真正使用的PFN肯定是该范围的一个子集。我们的系统中配置有两个Zone分别是Normal和HighMem.
- [ 0.000000] Normal 0x00000000 -> 0x00020000
Normal Zone的PFN范围从0到0x20000,换算成物理地址既是从0到512M(0x20000*4K=512M,每个Page大小为4K)。那么0x20000是怎么得来的呢?只能去源代码中找答案了。arch_zone_highest_possible_pfn[ZONE_NORMAL] 值其实是从max_zone_pfns[ZONE_NORMAL]得来的,在paging_init函数中有max_zone_pfns[ZONE_NORMAL] = max_low_pfn; 所以0x20000其实就是全局变量max_low_pfn的值,它表示(猜测)低端内存最大允许的PFN值,对应的还有min_low_pfn. 这两个全局变量在bootmem_init()函数中计算。
计算方法是: 遍历boot_mem_map,找到最大的RAM物理地址,计算其PFN赋给max_low_pfn。但是如果已经超过了HIGHMEM_START,则把HIGHMEM_START的PFN值赋给max_low_pfn。
在我们的系统中HIGHMEM_START为512M,而启动参数配置的最大RAM地址0x37600000(即768M+118M=886M)已经超过了512M,所以max_low_pfn=0x20000.
- [ 0.000000] HighMem 0x00020000 -> 0x00037600
如果启动参数配置的最大RAM地址超过了HIGHMEM_START,那么超过的部分就属于ZONE_HIGHMEM了。highstart_pfn就是0x20000, 而highend_pfn则是配置的最大RAM,即0x37600000, 换算成pfn就是0x00037600.
TODO: 如果板子上的RAM实际只有512M,那么配置了highmem会怎么处理呢?会映射到真正的RAM上吗?- [ 0.000000] Movable zone start PFN for each node
我们没有配置Movable Zone, 所以这里什么也不打印。 启动参数kernelcore和movablecore可以用来指定Movable Zone的大小。
- [ 0.000000] early_node_map[2] active PFN ranges
- [ 0.000000] 0: 0x00000000 -> 0x00009700
- [ 0.000000] 0: 0x00030000 -> 0x00037600
这里才是真正使用到的PFN范围。也就是从0到151M, 768M到768+118=886M
是从early_node_map数组中打印的,该数组由 add_active_range(0, start, end);填充。函数调用过程为:
head.S --> start_kernel --> setup_arch --> arch_mem_init --> bootmem_init --> add_active_range
- /**
- * add_active_range - Register a range of PFNs backed by physical memory
- * @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
- *
- * 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.
- */
TODO: 这里说Register a range of PFNs backed by physical memory, 而我们118M@768M似乎并没有backed by physical memory.
- [ 0.000000] On node 0 totalpages: 68864
- [ 0.000000] Normal zone: 1152 pages used for memmap
- [ 0.000000] Normal zone: 0 pages reserved
- [ 0.000000] Normal zone: 37504 pages, LIFO batch:7
计算方法为: 0x9700 + (0x37600-0x30000) = 0x10D00 = 68864
或者:151M + 118M = 269M
269M/4K = 68864
free_area_init_nodes --> free_area_init_node --> calculate_node_totalpages free_area_init_nodes --> free_area_init_node --> free_area_init_core
- free_area_init_core:
- /*
- * Set up the zone data structures:
- * - mark all pages reserved
- * - mark all memory queues empty
- * - clear the memory bitmaps
- */
- [ 0.000000] Normal zone: 1152 pages used for memmap
这里意思是为Normal Zone里的每个page创建struct page结构体所需要的页数。所谓memmap就是全部struct page结构体占用的内存。计算方法为:Normal Zone共有0x20000个页(包括0x9700个真正使用的页和余下的zone holes页),则创建0x20000个struct page结构体需要的内存容量为0x20000*sizeof((struct page)), 这些内存占用的页数就是memmap占用的页数:(0x20000*sizeof((struct page))) >> PAGE_SHIFT. 在我们的系统中
sizeof(struct page) = 36Bytes, 则(0x20000*36) >> 12 = 1152.
- [ 0.000000] Normal zone: 37504 pages, LIFO batch:7
这是在zone_pcp_init()函数中打印的,意思是除了memmap之外可用的内存容量:0x9700-1152 = 37504.
TODO: LIFO batch是什么意思?
- [ 0.000000] Initialising map node 0 zone 0 pfns 0 -> 131072
这是在init_currently_empty_zone()函数中打印的。Zone 0就是Zone_Normal.
PFN范围为0到0x20000 = 131072.
TODO: init_currently_empty_zone()函数具体做了什么?- [ 0.000000] HighMem zone: 842 pages used for memmap
- [ 0.000000] HighMem zone: 29366 pages, LIFO batch:7
- [ 0.000000] Initialising map node 0 zone 1 pfns 131072 -> 226816
同理,对于HighMem Zone, 也是类似计算。
((0x37600-0x20000) * sizeof(struct page))) >> PAGE_SHIFT
= (0x17600*36)>>12
= 841.5
= 842
注意要按页对齐。
(0x37600-0x30000) - 842 = 29366
PFN 131072 = 0x20000 -> 226816 = 0x37600
- [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 66870
这是build_all_zonelists()函数打印的. Total Pages: 37504 + 29366 = 66870
阅读(4669) | 评论(0) | 转发(2) |