背景

  • Read the fucking source code! --By 鲁迅
  • A picture is worth a thousand words. --By 高尔基

说明:

  1. Kernel版本:4.14
  2. ARM64处理器,Contex-A53,双核
  3. 使用工具:Source Insight 3.5, Visio

1. 介绍

(二)Linux物理内存初始化中,可知在paging_init调用之前,存放Kernel ImageDTB的两段物理内存区域可以访问了(相应的页表已经建立好)。尽管物理内存已经通过memblock_add添加进系统,但是这部分的物理内存到虚拟内存的映射还没有建立,可以通过memblock_alloc分配一段物理内存,但是还不能访问,一切还需要等待paging_init的执行。最终页表建立好后,可以通过虚拟地址去访问最终的物理地址了。

按照惯例,先上图,来一张ARM64内核的内存布局图片吧,最终的布局如下所示:

开启探索之旅吧!

2. paging_init

paging_init源代码短小精悍,直接贴上来,分模块来介绍吧。

/*
* paging_init() sets up the page tables, initialises the zone memory
* maps and sets up the zero page.
*/
void __init paging_init(void)
{
phys_addr_t pgd_phys = early_pgtable_alloc(); /********(mark 1)*******/
pgd_t *pgd = pgd_set_fixmap(pgd_phys); map_kernel(pgd); /********(mark 2)*******/
map_mem(pgd); /********(mark 3)*******/ /*
* We want to reuse the original swapper_pg_dir so we don't have to
* communicate the new address to non-coherent secondaries in
* secondary_entry, and so cpu_switch_mm can generate the address with
* adrp+add rather than a load from some global variable.
*
* To do this we need to go via a temporary pgd.
*/
cpu_replace_ttbr1(__va(pgd_phys)); /********(mark 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); /*
* We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
* allocated with it.
*/
memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
SWAPPER_DIR_SIZE - PAGE_SIZE);
}
  • mark 1:分配一页大小的物理内存存放pgd
  • mark 2:将内核的各个段进行映射;
  • mark 3:将memblock子系统添加的物理内存进行映射;
  • mark 4:切换页表,并将新建立的页表内容替换swappper_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 table了,这片区域的内容最后也会拷贝到swapper_pg_dir中去。

4. map_kernel

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

映射完成之后,可以看一下具体各个段的区域,以我自己使用的平台为例:

这些地址信息也能从System.map文件中找到。

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

5. map_mem

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

map_mem函数中,会遍历memblock中的各个块,然后调用__map_memblock来完成实际的映射操作。先来一张效果图:

map_mem都是将物理地址映射到线性区域中,我们也发现了Kernel Image中的text, rodata段映射了两次,原因是其他的子系统,比如hibernate,会映射到线性区域中,可能需要线性区域的地址来引用内核的text, rodata,映射的时候也会限制成了只读/不可执行,防止意外修改或执行。

map_kernelmap_mem函数中的页表映射,最终都是调用__create_pgd_mapping函数实现的:

总体来说,就是逐级页表建立映射关系,同时中间会进行权限的控制等。

细节不再赘述,代码结合图片阅读,效果会更佳噢。

6. 页表替换及内存释放

这部分代码不多,不上图了,看代码吧:

	/*
* We want to reuse the original swapper_pg_dir so we don't have to
* communicate the new address to non-coherent secondaries in
* secondary_entry, and so cpu_switch_mm can generate the address with
* adrp+add rather than a load from some global variable.
*
* To do this we need to go via a temporary pgd.
*/
cpu_replace_ttbr1(__va(pgd_phys));
memcpy(swapper_pg_dir, pgd, PGD_SIZE);
cpu_replace_ttbr1(lm_alias(swapper_pg_dir)); pgd_clear_fixmap();
memblock_free(pgd_phys, PAGE_SIZE); /*
* We only reuse the PGD from the swapper_pg_dir, not the pud + pmd
* allocated with it.
*/
memblock_free(__pa_symbol(swapper_pg_dir) + PAGE_SIZE,
SWAPPER_DIR_SIZE - PAGE_SIZE);

简单来说,将新建立好的pgd页表内容,拷贝到swapper_pg_dir中,也就是覆盖掉之前的临时页表了。当拷贝完成后,显而易见的是,我们可以把paging_init一开始分配的物理内存给释放掉。

此外,在之前的文章也分析过swapper_pg_dir页表存放的时候,是连续存放的pgd, pud, pmd等,现在只需要复用swapper_pg_dir,其余的当然也是可以释放的了。

好了,点到为止,前路漫漫,离Buddy System,Slab,Malloc以及各种内存的骚操作好像还有很远的样子,待续吧。

【原创】(三)Linux paging_init解析的更多相关文章

  1. JSON三种数据解析方法(转)

    原 JSON三种数据解析方法 2018年01月15日 13:05:01 zhoujiang2012 阅读数:7896    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...

  2. Linux下解析域名命令-dig 命令使用详解

    Linux下解析域名除了使用nslookup之外,开可以使用dig命令来解析域名,dig命令可以得到更多的域名信息.dig 命令主要用来从 DNS 域名服务器查询主机地址信息.dig的全称是 (dom ...

  3. 使用nsswitch控制linux dns解析顺序

    参考:1.DNS原理入门参考:http://www.ruanyifeng.com/blog/2016/06/dns.html 2.http://cn.linux.vbird.org/linux_ser ...

  4. (原创)Linux下MySQL 5.5/5.6的修改字符集编码为UTF8(彻底解决中文乱码问题)

    « CloudStack+XenServer详细部署方案(10):高级网络功能应用 (总结)CentOS Linux 5.x在GPT分区不能引导的解决方法 » 2013-1 11 (原创)Linux下 ...

  5. Linux进程状态解析

    引言 Linux是一个多用户,多任务的系统,可以同时运行多个用户的多个程序,就必然会产生很多的进程,而每个进程会有不同的状态.  在下文将对进程的R.S.D.T.Z.X 六种状态做个说明. PROCE ...

  6. 【原创】Linux中断子系统(二)-通用框架处理

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  7. Linux主机解析顺序

    1.介绍 本篇文章由于因公司项目上线,需要对项目环境进行压力测试.在压测过程中,所有打压机从公网对目标项目服务器进行压力测试,发现和内网压力测试的性能结果差距10倍左右,在调整主机对DNS的解析顺序之 ...

  8. Android Animation学习(三) ApiDemos解析:XML动画文件的使用

    Android Animation学习(三) ApiDemos解析:XML动画文件的使用 可以用XML文件来定义Animation. 文件必须有一个唯一的根节点: <set>, <o ...

  9. Linux系统解析域名的先后顺序【转帖】

    Linux系统解析域名的先后顺序 gd_WWW已经在本地(/etc/hosts)进行指向,但是竟然还能解析到外网,让我百思不得其解.经过不断查找发现域名解析与以下四个文件有关: /etc/hosts ...

随机推荐

  1. python中的赋值操作与C语言中的赋值操作中的巨大差别

    首先让我们来看一个简单的C程序: a = ; b = a; b = ; printf("a = %d, b = %d\n", a, b); 相信只要学过C语言, 不用运行程序便能知 ...

  2. JDK1.8源码分析01之学习建议(可以延伸其他源码学习)

    序言:目前有个计划就是准备看一下源码,来提升自己的技术实力.同时现在好多面试官都喜欢问源码,问你是否读过JDK源码等等? 针对如何阅读源码,也请教了我的老师.下面就先来看看老师的回答,也许会有帮助呢. ...

  3. Jenkins 持续集成持续发布使用搭建基础

    一.环境搭建基础 1.持续集成.持续交付.持续部署概念 ①.集成: 是指软件多人研发的部分软件代码整合交付,以便尽早发现个人开发部分的问题:持续集成:强调开发人员提交了新代码之后,立刻进行构建(单元) ...

  4. DataPipeline丨DataOps理念与设计原则

    作者:DataPipeline CEO 陈诚 上周我们探讨了数据的「资产负债表」与「现状」,期间抛给大家一个问题:如果我们制作一个企业的“数据资产负债表”,到底会有多少数据是企业真正的资产? 数据出现 ...

  5. 聊聊目标管理之 OKR

    这篇文章我们不谈技术,聊点轻松的,那聊什么呢?聊一下最近很火的目标管理 OKR.不知道小伙伴你们的公司什么情况,我的公司今年开始推行 OKR,用了大半年的时间,感觉效果还不错,上周六又参加了一天的复盘 ...

  6. red hat enterprise Linux 64 bit 配置IP

    在win7 64位操作系统的台式机器上,安装了VMware® Workstation,9.0.1 build-894247.新建一个虚拟机安装linux.具体过程请搜索相关文档.安装的时候选择的网络连 ...

  7. JavaScript数据结构——队列的实现与应用

    队列与栈不同,它遵从先进先出(FIFO——First In First Out)原则,新添加的元素排在队列的尾部,元素只能从队列头部移除. 我们在前一篇文章中描述了如何用JavaScript来实现栈这 ...

  8. C# 发送邮件 并自定义邮件格式

    话不多说,直接上代码 //邮件提醒 string Body = @"Dear " + list.Rows[i]["people"] + ":<b ...

  9. vscode保存代码,自动按照eslint规范格式化代码设置

    # vscode保存代码,自动按照eslint规范格式化代码设置 编辑器代码风格一致,是前端代码规范的一部分.同一个项目,或者同一个小组,保持代码风格一致很必要.就拿vue项目来说,之前做的几个项目, ...

  10. 用小程序·云开发两天搭建mini论坛丨实战

    笔者最近涉猎了小程序相关的知识,于是利用周末时间开发了一款类似于同事的小程序,深度体验了小程序云开发模式提供的云函数.数据库.存储三大能力.关于云开发,可参考文档:小程序·云开发. 个人感觉云开发带来 ...