BootMem内存管理方案过于简单,无法满足内存的需求,它最重要的使命其实是为建立buddy内存管理方案服务。而bootmem_init函数就是建立buddy内存管理方案的重要一步。
基础知识点
内存节点
在多处理其系统中,存在两种共享存储模型:
UMA
Uniform-Memory-Access,一致性内存访问模型。该模型中,只有一个物理内存,所有的处理器共享一个物理内存。在该模型中,只有一个内存节点,在软件上定义为contig_page_data。NUMA
Nouniform-Memory-Access,非一致性内存访问模型。该模型中,每个处理器都有自己的本地物理内存,所有的物理内存通过总线链接起来。在该模型中,有多个内存节点。
在接下来的分析中,我们只关注UMA模型,而不会花精力在NUMA模型上。
内存域
一个内存节点,会分成多个的内存域,内存域定义如下:
enum zone_type {
#ifdef CONFIG_ZONE_DMA
ZONE_DMA,
#endif
#ifdef CONFIG_ZONE_DMA32
ZONE_DMA32,
#endif
ZONE_NORMAL,
#ifdef CONFIG_HIGHMEM
ZONE_HIGHMEM,
#endif
ZONE_MOVABLE,
#ifdef CONFIG_ZONE_DEVICE
ZONE_DEVICE,
#endif
__MAX_NR_ZONES
};
- ZONE_DMA
对应到 普通的DMA内存域。考虑到有些外设的DMA无法访问整个物理内存空间,DMA内存域应运而生,DMA内存域的物理内存可以被所有外设的DMA访问。当然,如果系统中没有这种需求,可以不使用该该内存域。
- ZONE_DMA32
同样也是DMA内存域,这个主要是为X86设计的。由于历史原因,X86同时支持类型的外设DMA,一种是只能访问最低16M,另外一种是只能访问低4G。
- ZONE_NORMAL
对应到普通内存域。
- ZONE_HIGHMEM
对应到高端内存域。这是32位系统普遍使用的内存域,因为32位系统将虚拟地址空间按1:3划分给内核地址空间和用户地址空间,内核只有1G的虚拟地址空间,如果物理内存大于1G,则内核无法将整个物理地址空间线性映射到虚拟地址空间,也即无法访问整个物理内存。为了解决这个问题,特定划分了高端内存域,高端内存域并不会静态映射到某块物理地址,而是动态映射到不同的物理地址。
不过对于64位系统来说,给内核分配的虚拟地址空间足够大,不需要高端内存。
稀疏内存管理方案
稀疏内存管理方案是为了在一定程度上解决内存空洞带来的空间浪费。考虑如下场景:
两块物理内存1.5G和3G之间,有一段2G的物理内存空洞。我们知道物理内存是按page管理的,即物理内存被分成一个个物理页面,一般来说是4K,当然也支持16K或其他page size,我们后面讨论都按4K来讨论。软件上需要为每一个物理页面分配一个struct page实例。
如果不采用稀疏内存管理方案,则整个6.5G物理地址空间都需要分配struct page实例,但其实有2G的空洞没有必要分配struct page实例,这就造成了浪费。
稀疏内存管理方案首先将整个物理地址空间划分为section,对于ARM64来说,一般支持48bits物理地址(当然也支持其他物理地址),即256T物理地址空间,首先