内核早期内存分配器 - memblock与bootmem

Linux内核使用伙伴系统管理内存,那么在伙伴系统工作前,如何管理内存?答案是memblock;
memblock在系统启动阶段进行简单的内存管理,记录物理内存的使用情况;

在进一步介绍memblock之前,有必要先了解下系统内存的使用情况:
首先,内存中的某些部分是永久的分配给内核的,比如内核代码段和数据段,ramdisk和fdt占用的空间等,它们是系统内存的一部分,但是不能被侵占,也不参与内存分配,称之为静态内存;
其次,GPU,Camera等都需要预留大量连续内存,这部分内存平时不用,但是系统必须提前预留好,称之为预留内存;
最后,内存的其余部分称之为动态内存,是需要内核管理的宝贵资源;

memblock把物理内存划分为若干内存区,按使用类型分别放在memory和reserved两个集合(数组)中,memory即动态内存的集合,reserved集合包括静态内存和预留内存;

1. memblock关键数据结构
memblock数据结构定义如下:
struct memblock {
     bool bottom_up; 
     phys_addr_t current_limit;
     struct memblock_type memory;
     struct memblock_type reserved;
};

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;
};

struct memblock_region {
     phys_addr_t base;
     phys_addr_t size;
     unsigned long flags;
};

memblock相关数据结构十分的简单,内核还为memblock定义了一个全局变量,并为其赋初值,如下:
struct memblock memblock __initdata_memblock = {
     .memory.regions     = memblock_memory_init_regions,
     .memory.cnt           = 1,     /* empty dummy entry */
     .memory.max          = INIT_MEMBLOCK_REGIONS,

     .reserved.regions    = memblock_reserved_init_regions,
     .reserved.cnt          = 1,     /* empty dummy entry */
     .reserved.max         = INIT_MEMBLOCK_REGIONS,

     .bottom_up            = false,
     .current_limit          = MEMBLOCK_ALLOC_ANYWHERE,
};

memory类型的内存集合指向memblock_memory_init_regions数组,最多可以记录128个内存区;
reserved类型的内存集合指向memblock_reserved_init_regions数组,最多可以记录128个内存区;

注:内核代码经常用到类似"__initdata_memblock"的宏定义,通常用来指定变量或函数所在的section,该宏的定义如下:
#define __meminitdata    __attribute__ ((__section__(".meminit.data")))

2. memblock基本操作
1) 添加内存区
int memblock_add (phys_addr_t base , phys_addr_t size );
int memblock_reserve (phys_addr_t base , phys_addr_t size );

分别为memory和reserved集合添加内存区,如果新加入的内存区与原有内存区重叠,则合并到原有内存区,否则插入新内存区;
实际工作由memblock_add_range()完成,type参数指定内存集合类型;

需要注意的是该函数内部会执行两次:
第一次计算需要插入几个内存区,如果超过允许的最大内存区个数,则double内存区数组; 
第二次执行内存区的实际插入与合并操作;  
int memblock_add_range (struct memblock_type * type ,
                    phys_addr_t base , phys_addr_t size ,
                    int nid, unsigned long flags)
{
     bool insert = false;
     ... ...
     
/* 特例: 如果内存集合为空,则不需要执行插入或合并操作,直接插入新的内存区就可以了 */
     if (type->regions[0].size == 0) {
          WARN_ON(type->cnt != 1 || type->total_size);
          type->regions[0].base = base;
          type->regions[0].size = size;
          type->regions[0].flags = flags;
          memblock_set_region_node(&type->regions[0], nid);
          type->total_size = size;
          return 0;
     }

repeat:
     base = obase;
     nr_new = 0;

     for (i = 0; i < type->cnt; i++) {
          struct memblock_region *rgn = &type->regions[i];
          phys_addr_t rbase = rgn->base;
          phys_addr_t rend = rbase + rgn->size;

          if (rbase >= end)
               break;
          if (rend <= base)
               continue;
<
  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值