简述linunx内存管理初始化流程

本文基于linux-4.4.6 ,arm64平台

一:mmu和kernel image的映射 

    在汇编阶段,需要完成identity map和kernel image map两个工作,假设arm64 使用48位虚拟地址,4级translation table :9(level 0 or PGD) + 9(level 1 or PUD) + 9(level 2 or PMD) + 9(level 3 or PTE) + 12(page offset),页大小为4k,并且使用了section map机制,那么根据链接文件可知,在bss段之后分配了6个页作为translation table page使用,identity map和kernel image map各使用3个页面,因此对于物理地址、大小、虚拟地址都确定好的两个区域可以完成地址的映射。完成映射之后,就可以根据identity map的内容完成mmu的使能。

简述linunx内存管理初始化流程_第1张图片

 

二:DTB的映射

    完成上述两个映射之后,第三个映射便是DTB。DTB的映射方式是fixmap,fixmap是虚拟地址固定的一段区域,用来映射到一段确定的物理地址空间。DTB的size不能超过2M,这是因为fixmap区域预留给DTB的大小为4M,需要考虑到section map和地址对齐,比如DTB大小为1.5M,物理地址位于3M~4.5M,那么实际映射的空间是2M~6M。如果超过2M,那么可能超出fixmap中DTB的区域大小。完成DTB映射的3个页表在bss段当中。此时kernel image map已经完成当然可以访问bss段了。

简述linunx内存管理初始化流程_第2张图片

 

三:管理物理内存之memblock模块

    完成DTB映射之后,就是对其进行解析了。根据DTB中内存相关节点以及cmdline参数解析,可以了解整个物理内存布局:memory region、reserved memory、removed memory。此时内核是通过memblock模块来管理内存信息的,记录所有memory region和reserved memory。了解了内存布局,但是还需要完成映射才能进行访问,下面就是完成对这些内存的映射。映射过程借助了bss段之后那三个为kernel image map准备的translation table page,通过这三个页表,可以映射1G的物理空间,memblock只需要保证在建立映射时申请的内存(有需要时会通过memblock_alloc分配内存用来存放translation table)位于这1G范围以内,那么便可以正常映射,这之后所有可用的物理地址空间都完成了映射可以访问了。

简述linunx内存管理初始化流程_第3张图片

 

四:建立sparse内存模型

    sparse指的是物理地址存在空洞并且支持内存热插拔。在arm64中,管理sparse内存模型的最小内存单元是section,每个section大小为1G。Linux内核中,通过一个全局的二维数组struct mem_section **mem_section来维护映射关系。同时,每个section都会分配一个usemap来管理页面压缩迁移等的bit位,一个section分为256个pageblock,每个pageblock需要4bit来标志一些flag,因此每个section需要为usemap分配256*4/8=125字节。之后需要遍历所有section,只要在位,就为该section所有物理页面struct page实例分配虚拟地址空间和物理页表内存,并完成映射,其中虚拟地址是从vmemmap开始的,每一个page对应一个struct page结构。

简述linunx内存管理初始化流程_第4张图片

 

五:内存zone的初始化

    对于arm64 UMA来说,整个内存被看成一个node,该node内根据宏定义可分为ZONE_DMA、ZONE_NORMAL(arm64没有高端内存)等,在zone_sizes_init()函数中,会统计node和各个内存域所跨越的内存size和实际使用的内存size(region之间可能存在空洞)。这样把所有的页框纳入管理,同时还会初始化zone的各类锁,初始化usemap,初始化伙伴系统中使用的free_area[],初始化struct page数据结构等。

简述linunx内存管理初始化流程_第5张图片

你可能感兴趣的:(linux内核)