Linux内核启动过程中打印的内存信息是怎么计算的


对于一个这样的参数 mem=151M mem=118M@768M 内核中是怎么处理的已经在前篇文章里提到。这里再详细分析一下由这三个数据而引发的一连串的计算。使用这个参数的内核在启动过程中打印的内存信息:

  1. [ 0.000000] Determined physical RAM map:
  2. [ 0.000000] memory: 04000000 @ 00000000 (usable)
  3. [ 0.000000] User-defined physical RAM map:
  4. [ 0.000000] memory: 09700000 @ 00000000 (usable)
  5. [ 0.000000] memory: 07600000 @ 30000000 (usable)
  6. [ 0.000000] Zone PFN ranges:
  7. [ 0.000000] Normal 0x00000000 -> 0x00020000
  8. [ 0.000000] HighMem 0x00020000 -> 0x00037600
  9. [ 0.000000] Movable zone start PFN for each node
  10. [ 0.000000] early_node_map[2] active PFN ranges
  11. [ 0.000000] 0: 0x00000000 -> 0x00009700
  12. [ 0.000000] 0: 0x00030000 -> 0x00037600
  13. [ 0.000000] On node 0 totalpages: 68864
  14. [ 0.000000] Normal zone: 1152 pages used for memmap
  15. [ 0.000000] Normal zone: 0 pages reserved
  16. [ 0.000000] Normal zone: 37504 pages, LIFO batch:7
  17. [ 0.000000] Initialising map node 0 zone 0 pfns 0 -> 131072
  18. [ 0.000000] HighMem zone: 842 pages used for memmap
  19. [ 0.000000] HighMem zone: 29366 pages, LIFO batch:7
  20. [ 0.000000] Initialising map node 0 zone 1 pfns 131072 -> 226816
  21. [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 66870
  22. …………
  23. [ 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参数。

下面对这一大堆数据慢慢地做做计算, 看看它们到底是怎么得来的。

  1. [ 0.000000] Zone PFN ranges:
  2. [ 0.000000] Normal 0x00000000 -> 0x00020000
  3. [ 0.000000] HighMem 0x00020000 -> 0x00037600
  4. [ 0.000000] Movable zone start PFN for each node
  5. [ 0.000000] early_node_map[2] active PFN ranges
  6. [ 0.000000] 0: 0x00000000 -> 0x00009700
  7. [ 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.

  1. [ 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.

  1. [ 0.000000] HighMem 0x00020000 -> 0x00037600
如果启动参数配置的最大RAM地址超过了HIGHMEM_START,那么超过的部分就属于ZONE_HIGHMEM了。highstart_pfn就是0x20000, 而highend_pfn则是配置的最大RAM,即0x37600000, 换算成pfn就是0x00037600.

TODO: 如果板子上的RAM实际只有512M,那么配置了highmem会怎么处理呢?会映射到真正的RAM上吗?

  1. [ 0.000000] Movable zone start PFN for each node
我们没有配置Movable Zone, 所以这里什么也不打印。 启动参数kernelcore和movablecore可以用来指定Movable Zone的大小。

  1. [ 0.000000] early_node_map[2] active PFN ranges
  2. [ 0.000000] 0: 0x00000000 -> 0x00009700
  3. [ 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

  1. /**
  2. * add_active_range - Register a range of PFNs backed by physical memory
  3. * @nid: The node ID the range resides on
  4. * @start_pfn: The start PFN of the available physical memory
  5. * @end_pfn: The end PFN of the available physical memory
  6. *
  7. * These ranges are stored in an early_node_map[] and later used by
  8. * free_area_init_nodes() to calculate zone sizes and holes. If the
  9. * range spans a memory hole, it is up to the architecture to ensure
  10. * the memory is not freed by the bootmem allocator. If possible
  11. * the range being registered will be merged with existing ranges.
  12. */
  • 1
  • 2
  • 下一页

相关内容