linux memblock执行过程

memblock(内存块)属于早期引导期间管理内存区域的方法之一,而通常的内核内存分配器尚未启动、运行。memblock将系统内存视为连续内存的集合区域,它属于在高地址管理内存, 维护两个链表, 即memory和reserved。memory链表维护系统的内存信息(在初始化阶段通过bios获取),对于任何内存分配,先去查找memory链表,然后在reserve链表上记录(新增一个节点或合并)。

memblock_reserve

  x86系列架构中,memblock_reserve函数最早在early_reserve_memory函数中调用,执行顺序为:

  start_kernel -> setup_arch -> early_reserve_memory -> memblock_reserve。

int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size)
{
        phys_addr_t end = base + size - 1;

        memblock_dbg("%s: [%pa-%pa] %pS\n", __func__,
                     &base, &end, (void *)_RET_IP_);

        return memblock_add_range(&memblock.reserved, base, size, MAX_NUMNODES, 0);
}

  memblock_add_range函数包含五个参数:memblock_type对象;内存区域的物理基地址;内存区域的大小;最大 NUMA 节点数;标志参数。先看memblock定义:

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_RESERVED_REGIONS,
        .reserved.name          = "reserved",

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

__initdata_memblock 展开:

define __initdata_memblock __meminitdata
...
#define __meminitdata    __section(".meminit.data")
在.meminit.data段加载数据

memblock.reserved整理到结构大致为:

struct memblock_type reserved {
        unsigned long cnt = 1;
        unsigned long max = INIT_MEMBLOCK_RESERVED_REGIONS;
        phys_addr_t total_size;
        struct memblock_region *regions = memblock_reserved_init_regions, // 128个内存保留区域
        char *name = "reserved";
};


memblock_reserved_init_regions定义如下:

static struct memblock_region memblock_memory_init_regions[INIT_MEMBLOCK_REGIONS] __initdata_memblock;
static struct memblock_region memblock_reserved_init_regions[INIT_MEMBLOCK_RESERVED_REGIONS] __initdata_memblock;
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
static struct memblock_region memblock_physmem_init_regions[INIT_PHYSMEM_REGIONS];
#endif

/**     
 * struct memblock_region - represents a memory region
 * @base: base address of the region
 * @size: size of the region
 * @flags: memory region attributes
 * @nid: NUMA node id
 */
struct memblock_region {
        phys_addr_t base;
        phys_addr_t size;
        enum memblock_flags flags;
#ifdef CONFIG_NUMA
        int nid;
#endif
};

  进入memblock_add_range:

static int __init_memblock memblock_add_range(struct memblock_type *type,
                                phys_addr_t base, phys_addr_t size,
                                int nid, enum memblock_flags flags)
{
        bool insert = false;
        phys_addr_t obase = base;
        phys_addr_t end = base + memblock_cap_size(base, &size); // 得到内存区域末端地址
        int idx, nr_new;
        struct memblock_region *rgn;

        if (!size)
                return 0;

		/* special case for empty array */
		/ * 如果是第一次记录的内存  */
        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_each_memblock_type(idx, type, rgn) {
                phys_addr_t rbase = rgn->base;
                phys_addr_t rend = rbase + rgn->size;

                if (rbase >= end) // 如果获取到的基地址大于或等于传入内存区域末端地址
                        break;
                if (rend <= base) // 如果获取到的内存区域末端小于或等于传入的基地址
                        continue;

				if (rbase > base) { // 如果获取到的基地址大于传入的基地址
#ifdef CONFIG_NUMA
                        WARN_ON(nid != memblock_get_region_node(rgn));
#endif
                        WARN_ON(flags != rgn->flags);
                        nr_new++;
                        if (insert)
                                memblock_insert_region(type, idx++, base,
                                                       rbase - base, nid,
                                                       flags); // 将当前内存区域插入内存块
                }
                /* area below @rend is dealt with, forget about it */
                base = min(rend, end); // 获取到最小的地址为基地址
        }

		/* insert the remaining portion */
        if (base < end) { 
                nr_new++;
                if (insert)
                        memblock_insert_region(type, idx, base, end - base,
                                               nid, flags); // 将当前内存区域插入内存块
        }

        if (!nr_new)
                return 0;

		/*
         * If this was the first round, resize array and repeat for actual
         * insertions; otherwise, merge and return.
         */
        if (!insert) {
                while (type->cnt + nr_new > type->max)
                        if (memblock_double_array(type, obase, size) < 0) // 提供的区域数组长度加倍
                                return -ENOMEM;
                insert = true;
                goto repeat;
        } else {
                memblock_merge_regions(type); // 合并区域
                return 0;
        }
}

memblock_insert_region

static void __init_memblock memblock_insert_region(struct memblock_type *type,
int idx, phys_addr_t base,
phys_addr_t size,
int nid,
enum memblock_flags flags)
{
struct memblock_region *rgn = &type->regions[idx];

    BUG_ON(type->cnt >= type->max);
    memmove(rgn + 1, rgn, (type->cnt - idx) * sizeof(*rgn));
    rgn->base = base;
    rgn->size = size;
    rgn->flags = flags;
    memblock_set_region_node(rgn, nid);
    type->cnt++;
    type->total_size += size;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

坤昱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值