1.1.1 memblock

系统初始化的时候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,

                                       int nid)

{

        return memblock_add_range(&memblock.memory, base, size, nid, 0);

}

//移除操作

int __init_memblock memblock_remove(phys_addr_t base, phys_addr_t size)

{

        return memblock_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);

        return memblock_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_);

 

        return memblock_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中:

struct memblock {

        bool bottom_up;  /* is bottom up direction? 是否允许从下往上分配内存*/

        phys_addr_t current_limit;//内存块限制,限制memblock_alloc内存申请

        struct memblock_type memory;//可用内存的集合

        struct memblock_type reserved;//已分配内存的集合

#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP

        struct memblock_type physmem;//物理内存的集合

#endif

};

memblock_region结构体描述了内存区域

struct memblock_region {

        phys_addr_t base;

        phys_addr_t size;

        unsigned long flags;     

#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP

        int nid;

#endif

};

其中base是内存区域其实地址,size是内存区域大小,flags是标记,nid是node号。

结构体memblock_type

struct memblock_type {

        unsigned long cnt;      /* number of regions */  

        unsigned long max;      /* size of the allocated array */

        phys_addr_t total_size; /* size of all regions */

        struct memblock_region *regions;

        char *name;

};

其中cnt是当前集合记录的内存区域个数,max是当前集合记录的内存区域最大个数,total_size是集合记录区域信息大小,regions内存区域结构指针。

1.1.1.2  memblock初始化

以上是memblock的三个结构体和相关函数说明,下面来看下memblock的初始化。

       内核编译时候,会分配好memblock结构所需要的内存空间。

       在文件mm/memblock.c文件中,如下所示:

static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;

static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;

#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP

static struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS] __initdata_memblock;

#endif

struct memblock 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

void memblock_discard(void);

#else

#define __init_memblock

#define __initdata_memblock

#endif

其中INIT_MEMBLOCK_REGIONSINIT_PHYSMEM_REGIONS定义如下:

#define INIT_MEMBLOCK_REGIONS   128

#define INIT_PHYSMEM_REGIONS    4

#define MEMBLOCK_ALLOC_ANYWHERE (~(phys_addr_t)0)

1.1.1.3  内存相关初始化

在内核初始化初期,通过int 0x15来被探测和整理物理内存, 存放到e820中。而memblock初始化就发生在这个以后.

 

1.1.1.4  参考

mm: Use memblock interface instead of bootmem