分类: LINUX
2015-08-18 17:39:26
memblock和mem_map是linux内存管理中非常重要的两个全局变量。memblock保存着所有物理内存区域,包括可用的(memory)与保留的(reserved)。mem_map是全局page数组,物理内存每个页对应一个page结构体,顺序存储在mem_map中。
1 memblock初始化
可用的物理内存区域由bootloader通过dts传递给kernel,节点名称是“memory”。这个节点的内容可以由用户指定,也有可能是用户只预留这个节点(通过skeleton.dtsi),然后bootloader修改其具体内容。kernel中解析memory节点,添加可用内存区域的流程如下:
start_kernel
--> setup_arch
--> setup_machine_fdt
--> of_scan_flat_dt(early_init_dt_scan_memory,
NULL);
--> early_init_dt_add_memory_arch
--> memblock_add
从而把dts指定的所有内存区域添加在memblock的memory中。
随后kernel会把不能使用的保留内存区域添加到memblock的reserved中,这些区域包括kernel自己使用的text,data区、页表内存,还有用户在dts中定义预留给其它硬件或内核特定模块使用的内存。它们通过以下代码来实现:
memblock的物理内存区域决定了后续kernel内存管理的范围,首先在bootmem_init过程中,memblock的memory区域全部被添加到bootmem,然后遍历memblock的reserved区域,同样在bootmem中标记。
2 mem_map初始化
每个物理内存页都对应mem_map的一个元素,而且通过页号pfn能够迅速转化成物理地址,这就决定了mem_map的元素是按物理地址顺序排列的,而不是仅仅是可用的内存。如果可用内存区域之间间隔很大,会导致mem_map浪费很多内存来存储无效page,因此在mem_map完成初始化后,会把中间不用的元素占用的内存释放到buddy中,节省空间。于是mem_map可能是一个很大的数组,但中间有很多元素不能作为page访问,因为这些内存已经作为buddy的空间内存供他人使用了。
mem_map的初始化流程如下:
start_kernel
--> setup_arch
--> paging_init
--> bootmem_init
start_kernel
--> mm_init
--> mem_init
--> free_unused_memmap
释放的目标是bootmem,这些内存随后会被buddy使用