内存管理是操作系统内核中最复杂的部分之一, start_kernel函数在内核启动第一个init进程前初始化了所有的内核特性(包括那些依赖于不同架构的特性),你也许还记得引导时创立的临时页表,但复杂的内存管理部分还没有开始,当start_kernel函数被调用时,我们会看到初期内存管理到更复杂的内存管理数据结构和技术的转变,为了更好的理解内核的初始化过程,我们需要对这些技术有更清晰的理解,今天我们会着重讨论这个过程,主要针对初期的内存管理memblock的介绍。
首先我们知道在内核启动后,对于内存,分成好几块:
内存中的某些部分使永久分配给内核的,例如代码段和数据段、ramdisk和dtb占用的空间、临时页表和设备数中的保留区域等,是系统内存的一部分,不能被侵占,也不参与内存的分配,称之为静态内存;
GPU/camera/多核共享的内存都需要预留大量连续内存,这部分内存平时不使用,但是必须为各个应用场景预留,这样的内存称之为预留内存;
内存其余的部分,是需要内核管理的内存,称之为动态内存;
那么memblock就是将以上内存按功能划分为若干内存区,使用不同的类型存放在memory和reserved的两个集合中,memory即为动态内存,而resvered包括静态内存等。
memblock是什么
memblock介绍
memblock即linux启动后kernel管理内存空间抽象出来的结构,此时buddy系统和slab分配器等并没有初始化,当需要执行一些内存管理、内存分配的任务,此时就是有初期的管理模块memblock机制。在mm_init中会建立内核的内存分配器,停用memblock,释放内存给伙伴系统和slab分配器。memblock是bootmem的升级版本,在config中配置:CONFIG_NO_BOOTMEM=Y。
需要的结构体
第一个结构体的名字就叫做 memblock。它的定义如下:
struct memblock {
bool bottom_up;
phys_addr_t current_limit;
struct memblock_type memory; --> array of memblock_region
struct memblock_type reserved; --> array of memblock_region
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
struct memblock_type physmem;
#endif
};
这个结构体包含五个域。第一个 bottom_up 域置为 true 时允许内存以自底向上模式进行分配。下一个域是 current_limit。这个域描述了内存块的尺寸限制。接下来的三个域描述了内存块的类型。内存块的类型可以是:被保留、内存和物理内存( CONFIG_HAVE_MEMBLOCK_PHYS_MAP 编译配置选项被开启)。
接下来我们可以看看下一个数据结构memblock_type,定义如下:
struct memblock_type {
unsigned long cnt;
unsigned long max;
phys_addr_t total_size;
struct memblock_region *regions;
};
memblock_region 提供了内存区域的基址和大小,如果 CONFIG_HAVE_MEMBLOCK_NODE_MAP 编译配置选项被开启, memblock_region 结构体也提供了整数域 - numa 节点选择器。flags 域可以是:
/* Definition of memblock flags. */
enum memblock_flags {
MEMBLOCK_NONE = 0x0, /* No special request */
MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */
MEMBLOCK_MIRROR = 0x2, /* mirrored region */
MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */
};
以上的关系如图所示: