1.1.1memblock
系统初始化的时候buddy系统,slab分配器等并没有被初始化好,当需要执行一些内存管理、内存分配的任务,就引入了一种内存管理器bootmem分配器。
当buddy系统和slab分配器初始化好后,在mem_init()中对bootmem分配器进行释放,内存管理与分配由buddy系统,slab分配器等进行接管。
而memblock是用来替代bootmem的新接口。用__alloc_memory_core_early()取代了bootmem的__alloc_bootmem_core()来完成内存分配.
实现都位于mm/memblock.c文件中。例如,可以通过函数memblock_reserve可以保留内存。
此外还有如下函数:
int__init_memblock memblock_add_node(phys_addr_t base, phys_addr_t size,
intnid)
{
returnmemblock_add_range(&memblock.memory, base, size, nid,0);
}
//移除操作
int__init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)
{
returnmemblock_remove_range(&memblock.memory, base, size);
}
//释放操作
int__init_memblock memblock_free(phys_addr_t base, phys_addr_t size)
{
phys_addr_t end = base + size -1;
memblock_dbg(" memblock_free: [%pa-%pa]%pF\n",
&base, &end, (void*)_RET_IP_);
kmemleak_free_part_phys(base, size);
returnmemblock_remove_range(&memblock.reserved, base, size);
}
//标记已经使用的方法
int__init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
{
phys_addr_t end = base + size -1;
memblock_dbg("memblock_reserve: [%pa-%pa]%pF\n",
&base, &end, (void*)_RET_IP_);
returnmemblock_add_range(&memblock.reserved, base, size, MAX_NUMNODES,0);
}
为了保证系统的兼容性, 内核为bootmem和memblock提供了相同的API接口。编译Kernel的时候可以选择nobootmem或者bootmem来在buddy system起来之前管理memory(参数CONFIG_NO_BOOTMEM)。默认是选择memblock的。
1.1.1.1数据结构
memblock把物理内存划分为若干内存区,按使用类型分别放在memory和reserved两个集合(数组)中,memory即动态内存的集合,reserved集合包括静态内存和预留内存;
定义在文件include/linux/memblock.h中:
structmemblock {
boolbottom_up;/* is bottom up direction?是否允许从下往上分配内存*/
phys_addr_t current_limit;//内存块限制,限制memblock_alloc内存申请
structmemblock_type memory;//可用内存的集合
structmemblock_type reserved;//已分配内存的集合
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
structmemblock_type physmem;//物理内存的集合
#endif
};
memblock_region结构体描述了内存区域
structmemblock_region {
phys_addr_t base;
phys_addr_t size;
unsignedlongflags;
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
intnid;
#endif
};
其中base是内存区域其实地址,size是内存区域大小,flags是标记,nid是node号。
结构体memblock_type
structmemblock_type {
unsignedlongcnt;/* number of regions */
unsignedlongmax;/* size of the allocated array */
phys_addr_t total_size;/* size of all regions */
structmemblock_region *regions;
char*name;
};
其中cnt是当前集合记录的内存区域个数,max是当前集合记录的内存区域最大个数,total_size是集合记录区域信息大小,regions内存区域结构指针。
1.1.1.2memblock初始化
以上是memblock的三个结构体和相关函数说明,下面来看下memblock的初始化。
内核编译时候,会分配好memblock结构所需要的内存空间。
在文件mm/memblock.c文件中,如下所示:
staticstructmemblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
staticstructmemblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
staticstructmemblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS] __initdata_memblock;
#endif
structmemblock memblock __initdata_memblock = {
.memory.regions = memblock_memory_init_regions,
.memory.cnt =1,/* empty dummy entry */
.memory.max = INIT_MEMBLOCK_REGIONS,
.memory.name ="memory",
.reserved.regions = memblock_reserved_init_regions,
.reserved.cnt =1,/* empty dummy entry */
.reserved.max = INIT_MEMBLOCK_REGIONS,
.reserved.name ="reserved",
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
.physmem.regions = memblock_physmem_init_regions,
.physmem.cnt =1,/* empty dummy entry */
.physmem.max = INIT_PHYSMEM_REGIONS,
.physmem.name ="physmem",
#endif
.bottom_up =false,
.current_limit = MEMBLOCK_ALLOC_ANYWHERE,
};
其中__initdata_memblock宏指定存储位置
#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK
#define __init_memblock __meminit
#define __initdata_memblock __meminitdata
voidmemblock_discard(void);
#else
#define __init_memblock
#define __initdata_memblock
#endif
其中INIT_MEMBLOCK_REGIONS和INIT_PHYSMEM_REGIONS定义如下:
#define INIT_MEMBLOCK_REGIONS128
#define INIT_PHYSMEM_REGIONS4
#define MEMBLOCK_ALLOC_ANYWHERE (~(phys_addr_t)0)
1.1.1.3内存相关初始化
在内核初始化初期,通过int 0x15来被探测和整理物理内存, 存放到e820中。而memblock初始化就发生在这个以后.
1.1.1.4参考