4. memblock
上文讲的内容都只是铺垫,为了能正确访问DTB
文件并且解析得到物理地址信息。从入口到最终添加的调用过程如下图:
所以,这个章节的重点就是memblock
模块,这个是早期的内存分配管理器,我不禁想起了之前在Nuttx
中的内存池实现了,细节已然不太清晰了,但是框架性的思维都大同小异。
4.1 结构体
总共由三个数据结构来描述:
struct memblock
定义了一个全局变量,用来维护所有的物理内存;struct memblock_type
代表系统中的内存类型,包括实际使用的内存和保留的内存;struct memblock_region
用来描述具体的内存区域,包含在struct memblock_type
中的regions
数组中,最多可以存放128个。
直接上个代码吧:
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,
};
定义的memblock
为全局变量,在定义的时候就进行了初始化。初始化的时候,regions
指向的也是静态全局的数组,其中数组的大小为INIT_MEMBLOCK_REGIONS
,也就是128个,限制了这些内存块的个数了,实际在代码中可以看到,当超过这个数值时,数组会以2倍的速度动态扩大。
初始化完了后,大体是这个样子的:
4.2 memblock_add/memblock_remove
memblock
子模块,基本的逻辑都是围绕内存的添加和移除操作来展开,最终是通过调用memblock_add_range/memblock_remove_range
来实现的。
memblock_add_range
:
图中的左侧是函数的执行流程图,执行效果是右侧部分。右侧部分画的是一个典型的情况,实际的情况可能有多种,但是核心的逻辑都是对插入的region
进行判断,如果出现了物理地址范围重叠的部分,那就进行split
操作,最终对具有相同flag
的region
进行merge
操作。
memblock_remove_range
该函数执行的一个典型case效果如下图所示:
假如现在需要移除掉一片区域,而该区域跨越了多个region
,则会先调用memblock_isolate_range
来对这片区域进行切分,最后再调用memblock_remove_region
对区域范围内的region
进行移除操作。
当调用memblock_alloc
函数进行地址分配时,最后也是调用memblock_add_range
来实现的,申请的这部分内存最终会添加到reserved
类型中,毕竟已经分配出去了,其他人也不应该使用了。
5. arm64_memblock_init
当物理内存都添加进系统之后,arm64_memblock_init
会对整个物理内存进行整理,主要的工作就是将一些特殊的区域添加进reserved
内存中。函数执行完后,如下图所示:
- 其中浅绿色的框表示的都是保留的内存区域, 剩下的部分就是可以实际去使用的内存了。