在前面笔记【LM04】Memblock及源码分析中,我提到到目前为止,完成VA->PA
映射的内存空间有内核和FDT/DTS
,其它添加和没有添加入memblock
的内存空间并没有完成VA->PA
的映射。接下来的映射工作将全部交给paging_init()
来完成,这篇笔记也主要围绕这个函数展开。同时,我将简单分析下该函数完成后的内存布局。
memblock管理的内存空间
我们再次回到setup_arch()
函数,看看在完成FIXMAP
的映射后,还会进行什么其它的映射。
1 | // ./arch/arm64/kernel/setup.c |
arm64_memblock_init()
这个函数从名字上就可以知道是干什么的,初始化arm64
中的memblock
。在setup_machine_fdt()
函数中,我们已经将DTS
中读取的信息存入memblock
中。在这个函数中,更多的内存空间会被添加入memblock
中的memory
和reserved
区域。
在完成这一系列工作后,我们就要开始调用paging_init()
来完成相关的映射工作了。
paging_init()
这个函数比较简单,主要工作就是完成内核和memblock
中内存的VA->PA
映射。同时,将init_mm.pgd
替换成swapper_pg_dir
。
1 | // ./arch/arm64/mm/mmu.c |
(1) 将FIX_PGD
与swapper_pg_dir
进行映射;
(2) 重新将内核进行映射,这次映射到swapper_pg_dir
(之前映射到init_pg_dir
) - 在Linux 4.20之前是没有init_pg_dir
的,Linux 4.20之后才用它作为启动时的内核页表;
(3) 将memblock
中memory
区域的内存空间都进行映射,这里会使用memblock
来进行页表物理内存的分配(early_pgtable_alloc()
函数);
(4)
a) 清除FIX_PGD
的临时映射;
b) 重新设置TTBR1
;
c) 更新init_mm.pgd
;
d) 释放init_pg
在memblock
占用的内存空间;
e) 允许memblock
扩容。
内存的布局
至此,内核空间的内存都映射完成。这里我借用下大神LoyenWang
的图和我自己实验平台的图,
这是我的实验平台的内存布局图,
从图中,我们可以看到,在内核空间,PAGE_OFFSET
以上都是线性区域。在这个区域,物理内存和虚拟内存按照PAGE_OFFSET
的偏移进行映射。PAGE_OFFSET
以下区域,分别映射了vmemmap
, PCI/IO
, FIXMAP
, vmalloc
以及内核和modules
。PAGE_OFFSET
在 arch/arm64/include/asm/memory.h
中进行了定义,查看文件获取更多信息。
在这篇笔记【LM03】FIXMAP和相关页表的创建中我已经介绍了这个布局了,这里就不做过多解释了。