吉游网提供最新游戏下载和手游攻略!

Linux paging_init分析

发布时间:2024-09-19浏览:42

本篇文章给大家谈谈Linux paging_init分析,以及对应的知识点,文章可能有点长,但是希望大家可以阅读完,增长自己的知识,最重要的是希望对各位有所帮助,可以解决了您的问题,不要忘了收藏本站喔。

内核版本:4.14

ARM64处理器,Contex-A53,双核

使用的工具:Source Insight 3.5、Visio

一、简介

从Linux物理内存初始化可以看出,在paging_init调用之前,存放Kernel Image和DTB的两个物理内存区域是可以访问的(对应的页表已经建立)。虽然已经通过memblock_add将物理内存添加到系统中,但这部分物理内存到虚拟内存的映射还没有建立起来。通过memblock_alloc可以分配一段物理内存,但还不能访问。一切还需要等待paging_init的执行。最终页表建立之后,就可以通过虚拟地址来访问最终的物理地址。

像往常一样,我们先从上图开始,拍一张ARM64核心的内存布局图。最终布局如下:

2. 分页初始化

paging_init的源码很短,简洁,直接粘贴到这里,在模块中引入即可。

/* * paging_init() 设置页表,初始化区域内存映射并设置零页。 */void __init paging_init(void){phys_addr_t pgd_phys=Early_pgtable_alloc(); /********(标记1)********/pgd_t *pgd=pgd_set_fixmap(pgd_phys);map_kernel(pgd); /********(标记2)************/map_mem(pgd); /********(mark 3)************//* * 我们想重用原来的swapper_pg_dir 所以我们不必* 将新地址传达给非一致的地址secondary_entry 中的辅助节点,因此cpu_switch_mm 可以使用* adrp+add 生成地址,而不是从某个全局变量加载。 * * 为此,我们需要通过临时pgd。 */cpu_replace_ttbr1(__va(pgd_phys)); /********(标记4)********/memcpy(swapper_pg_dir,pgd,PGD_SIZE);cpu_replace_ttbr1(lm_alias(swapper_pg_dir));pgd_clear_fixmap();memblock_free(pgd_phys,PAGE_SIZE);/* * 我们只重用来自swapper_pg_dir 的PGD,而不是分配给它的pud + pmd *。 */memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE, SWAPPER_DIR_SIZE - PAGE_SIZE);}

标记1:分配一页物理内存来存储pgd;

标记2:映射内核各段;

标记3:映射memblock子系统添加的物理内存;

标记4:切换页表,将swapper_pg_dir页表内容替换为新创建的页表内容;

代码看起来很费力?这是图片:

下面对各个子模块进行进一步分析。

3.early_pgtable_alloc

该模块与FIX MAP映射区域相关。建议先阅读之前的文章(二)Linux物理内存初始化:

FIX MAP的区域划分如图所示。

该函数会先分配物理内存,然后借用之前的全局页表bm_pte建立物理地址到虚拟地址的映射。这个映射的目的是访问物理内存并清除内存,所以它只是一个临时操作。操作完成后,会调用pte_clear_fixmap()来清除映射。

在early_pgtable_alloc之后,我们看到paging_init调用了pgd_set_fixmap函数。调用该函数后,通过memblock_alloc分配的物理内存最终将用于存储pgd表,并且该区域的内容最终将被复制到swapper_pg_dir。

4.map_kernel

map_kernel的主要工作是完成内核中各个段的映射。另外,还包括FIXADDR_START虚拟地址的映射,如下所示:

映射完成后,您可以查看每个段的具体区域。以我使用的平台为例:

该地址信息也可以在System.map 文件中找到。

aarch64-linux-gnu-objdump -x vmlinux 可以查看更详细的地址信息。

5. 映射内存

从函数名可以看出,map_mem主要完成物理内存的映射。这部分物理内存是通过memblock_add添加到系统中的。当相应的memblock设置MEMBLOCK_NOMAP标志时,不对其进行地址映射。

在map_mem函数中,会遍历memblock中的每个块,然后调用__map_memblock来完成实际的映射操作。让我们从渲染开始:

map_mem 将物理地址映射到线性区域。我们还发现内核图像中的文本和rodata 段被映射了两次。原因是其他子系统,比如hibernate,会映射到线性区域,并且可能需要线性区域。该地址用于引用内核的文本和rodata。映射时,也会被限制为只读/不可执行,以防止意外修改或执行。

map_kernel和map_mem函数中的页表映射最终是通过调用__create_pgd_mapping函数来实现的:

一般来说,就是通过逐级页表建立映射关系,同时在中间控制权限。我不再赘述细节。结合图片阅读代码效果会更好。

6.页表替换和内存释放

这部分代码不多,就不在图中展示了。我们看一下代码:

/* * 我们希望重用原始的swapper_pg_dir,这样我们就不必* 将新地址传达给* secondary_entry 中的非一致辅助节点,因此cpu_switch_mm 可以使用* adrp+add 生成地址,而不是从某些全局负载生成地址多变的。 * * 为此,我们需要通过临时pgd。 PAGE_SIZE);/* * 我们只重用swapper_pg_dir 中的PGD,而不是用它分配的pud + pmd *。 */memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE, SWAPPER_DIR_SIZE - PAGE_SIZE);

用户评论

浅嫣婉语

这篇博文写的太好了!终于有人解释清楚了Linux系统的页表初始化过程。我一直对paging机制有点困惑,现在阅读完后感觉豁然开朗了。感谢作者的细致讲解和清晰的图示!

    有20位网友表示赞同!

一纸愁肠。

哈哈,我刚看了一下内核源码,就发现这玩意儿好复杂啊!不过这篇博文读起来还是挺容易懂的,让我明白了paging_init函数的作用和步骤。希望后续还能看到作者分享更多关于Linux内存管理的知识!

    有10位网友表示赞同!

▼遗忘那段似水年华

感觉这篇文章有些过于深入了,对于初学者来说可能有点难懂。建议作者可以先介绍一下分页机制的基本原理,然后再深入讲解paging_init的过程。

    有17位网友表示赞同!

泡泡龙

讲 verdad, reading this post really helped me understand how Linux paging works. I've been struggling with this topic for a while, and your clear explanation and diagrams were incredibly helpful! Thanks!

    有17位网友表示赞同!

未来未必来

我觉得这篇博客标题写的有点含糊,"解析"究竟是什么意思呢?我读了以后却感觉只是做了个简单的介绍,并没有给到很多具体的剖析。希望作者能够进一步深入讲解,比如一些重要的内核数据结构和函数细节。

    有9位网友表示赞同!

莫飞霜

终于有人把Linux这方面的内容解释清楚啦!平时看源码的时候遇到paging_init总是不太明白是怎么回事,现在看了这篇博文就明白了。真的要感谢作者的耐心讲解,太棒了!

    有13位网友表示赞同!

陌上花

我倒是觉得这篇文章写的还可以吧,至少比之前的博客更容易理解。不过我还是不太理解 kernel_pages参数是怎么决定的啊?关于这个部分可以多加解释一下吗?

    有12位网友表示赞同!

暮光薄凉

对于初学者来说,这篇博文可能有些难度。它假设读者已经对Linux内核和内存管理有一定的了解。如果能先解释一些核心概念,比如page frame、page table、虚拟地址空间等,会更容易理解paging_init的运作方式。

    有11位网友表示赞同!

单身i

作者的图示真棒!在动图基础上,再加入函数流程的注释,让我一下子就明白了Paging机制从初始化到使用整个过程。强烈推荐!”

    有20位网友表示赞同!

巷陌繁花丶

我一直在忙着学习其他技术,最近才发现Linux内存管理这个部分也很重要啊!这篇博文正好帮了我的忙,讲解得很清晰,让我能更快速地理解paging_init的细节

    有7位网友表示赞同!

将妓就计

这篇文章内容挺不错,但是有些地方还是比较浅薄的。比如可以多讲讲不同的页表类型和它们之间的关系,以及一些实际应用场景如何影响Paging机制的设计吗?

    有10位网友表示赞同!

安好如初

终于不用再看那些生涩难懂的源码了! 这篇文章讲解得很清楚,让我清晰地了解了Linux是如何初始化自己的内存页管理体系的。非常感谢作者的分享!

    有10位网友表示赞同!

|赤;焰﹏゛

我觉得这篇文章比较适合有一定编程背景的人阅读。如果是纯粹从零开始学Linux 内核,可能需要先学习一些基本知识才能更好地理解本文内容

    有12位网友表示赞同!

减肥伤身#

我尝试运行了paging_init函数代码,但是遇到了些许问题,代码注释不够详细啊!希望作者能够提供更完善的代码例子和调试技巧,这样大家可以更直观地理解Linux系统是如何运作的。

    有14位网友表示赞同!

風景綫つ

这篇文章对初学者来说解释得太浅了,可能无法深入了解paging_init函数实现细节。我希望能找到更多高层次的技术博客或者论文来学习内核机制!

    有12位网友表示赞同!

凝残月

这篇博文写的很全面,将Linux paging机制从概念到代码实践都进行了详细的阐述,对于想要深入学习Linux内存管理的人来说非常推荐!

    有7位网友表示赞同!

念安я

这篇博客让我对 Linux 内核中的内存管理有了更清晰的认识。我之前一直只是粗略了解过,现在明白了 paging_init 函数的重要性以及它如何为操作系统正常运行奠定基础。

    有14位网友表示赞同!

热点资讯