boot memory allocator——自举内存分配器(一:基本介绍)
在启动过程期间,尽管内存管理尚未初始化,但内核仍然需要分配内存以创建各种数据结构。bootmem分配器用于在启动阶段早期分配内存。
显然,对该分配器的需求集中于简单性方面,而不是性能和通用性。因此内核开发者决定实现一个最先适配(first-fit)分配器用于在启动阶段管理内存。这是可能想到的最简单的方式。
该分配器使用一个位图来管理页,位图比特位的数目与系统中物理内存页的数目相同。比特位位1,表示页以用;比特位位0,表示页空闲。
在需要分配内存时,分配器逐位扫描位图,知道找到一个能提供足够连续页的位置,即所谓的最先最佳(first-best)或最先适配位置。
该过程不是很高效,因为每次分配都必须从头扫描比特链。因此在内核完全初始化之后,不能将该适配器用于内存管理。伙伴系统(连同slab、slub、或slob分配器)是一个好得多的备选方案。
即使最先适配分配器也必须管理一些数据。内核为系统中的每个结点都提供一个bootmem_data结构的实例,用于该用途。当然该结构所需的内存无法动态分配,必须在编译时分配给内核。bootmem_data结构定义如下:
// 页对齐
#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK)
// 获取x所代表的物理地址的后一个PFN值,即x如果属于page 0, 则返回1.
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
// 获取x所代表的物理地址的前一个PFN值,即x如果属于page 1, 则返回0.
#define PFN_DOWN(x) ((x) >> PAGE_SHIFT)
// 返回PFN的值为x时,所对应物理页的起始地址。
#define PFN_PHYS(x) ((x) << PAGE_SHIFT)以上四个是和PFN相关的宏定义,内核使用这4个宏完成PFN到物理地址之间的映射。