mem_init

来源:互联网 发布:js获取当前时间格式化 编辑:程序博客网 时间:2024/06/05 17:06

mem_init() marks the free areas in the mem_map and tells us how much memory is free.
即释放内存到伙伴系统,对一些内存方面的全局变量设置
首先我们需要明白mem_map作用,其是描述所有的物理内存采用的struct page结构的数组的基指针。比如说,对于4GB的内存来说,如果一个页定义为4KB,即2^12字节。那么可想而知,总共这个mem_map数组大小为2^20个。注意我们这里都以flat型内存描述为主,即平坦型内存模型、

而这些页都有一个具体的页帧号与之对应。页帧号一般用pfn来表示,那么由于每个页都有一个页帧号,那最小的页帧号和最大的页帧号为多少呢?需要特别注意的是,页帧号也是与mem_map数组的index相对应。我们一般认为pfn_min为0,而最大pfn_max为mem_map数组下标的最大值,这个最大值也就是max_pfn,这个值跟内核的max_mapnr相对应。

函数set_max_mapnr()就是用于计算max_mapnr。我们可能会想,这个max_pfn是什么时候设置的呢?这个是在setup_arch的paging_init()中调用bootmem_init()来进行的。在成功设置max_mapnr后,我们要把启动过程时所有的空闲内存释放到伙伴系统,这里需要注意三点:

一. bootmem内存管理或者nobootmem管理

二. memblock内存管理

三. 伙伴系统

显然,启动时,不存在伙伴系统,在linux 内核启动的早期,BSP相关的代码需要把内核能使用的内存块大小告知内核,要么通过bootload传递参数给出DDR大小,要么通过命令行形式给出DDR大小,或者通过FDT等形式对DTS分析得出DDR大小。不管什么样的方法,内核需要了解这些信息,我们这里以DTS形式给出内存大小,这些内存块会以

memblock_add形式添加到memblock内存管理块中。这些添加到内核中的内存块被标记为memory类型,另外一种类型为reserve类型。BSP可以通过不同方式添加到内核,

但是在我们内核使用内存之前,必须先添加一块,否则我们使用的内存哪里来呢,使用的内存被标记为reserve。这样,通过这种简单的管理,memblock把所有的内存块维护起来,之后内核慢慢的从这些内存块中获取内存。我们一般称memblock是逻辑内存块管理。

对于bootmem来说,它是物理内存管理。我们这里不详细介绍,后面会有篇章分析。

函数free_unused_memmap()和free_all_bootmem()都是把空闲内存释放到伙伴系统,前者释放memblock中空闲内存,主要是内存空洞的内存,后者释放bootmem中内存。
重点函数:
arm64_swiotlb_init
free_unused_memmap
free_all_bootmem
内存统计信息打印
1.初始化software IO TLB,用于DMA API
void __init arm64_swiotlb_init(void)
{
dma_ops = &arm64_swiotlb_dma_ops;
swiotlb_init(1);
}
dma 操作函数初始化,并从内存中分一片空间出来,作为tlb 配置表的虚拟,物理内存
2.free_unused_memmap
主要函数调用关系:free_unused_memmap—–>free_memmap—->free_bootmem—->free_unused_memmap—–>__memblock_remove
在新的内核版本中,用memblock 管理取代了bootmem中的位图管理。
3.free_all_bootmem
1)reset_node_lowmem_managed_pages,将zone 结构中的z->managed_pages =0,如果支持高端内存
2)free_low_memory_core_early—–>__free_memory_core

引用参考:
内存管理之函数mm_init解读之mem_init