【原创】(三)Linux paging_init解析
背景
Read the fucking source code!
--By 鲁迅A picture is worth a thousand words.
--By 高尔基
说明:
- Kernel版本:4.14
- ARM64处理器,Contex-A53,双核
- 使用工具:Source Insight 3.5, Visio
1. 介绍
从(二)Linux物理内存初始化
中,可知在paging_init
调用之前,存放Kernel Image
和DTB
的两段物理内存区域可以访问了(相应的页表已经建立好)。尽管物理内存已经通过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_kernel
和map_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解析的更多相关文章
- JSON三种数据解析方法(转)
原 JSON三种数据解析方法 2018年01月15日 13:05:01 zhoujiang2012 阅读数:7896 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...
- Linux下解析域名命令-dig 命令使用详解
Linux下解析域名除了使用nslookup之外,开可以使用dig命令来解析域名,dig命令可以得到更多的域名信息.dig 命令主要用来从 DNS 域名服务器查询主机地址信息.dig的全称是 (dom ...
- 使用nsswitch控制linux dns解析顺序
参考:1.DNS原理入门参考:http://www.ruanyifeng.com/blog/2016/06/dns.html 2.http://cn.linux.vbird.org/linux_ser ...
- (原创)Linux下MySQL 5.5/5.6的修改字符集编码为UTF8(彻底解决中文乱码问题)
« CloudStack+XenServer详细部署方案(10):高级网络功能应用 (总结)CentOS Linux 5.x在GPT分区不能引导的解决方法 » 2013-1 11 (原创)Linux下 ...
- Linux进程状态解析
引言 Linux是一个多用户,多任务的系统,可以同时运行多个用户的多个程序,就必然会产生很多的进程,而每个进程会有不同的状态. 在下文将对进程的R.S.D.T.Z.X 六种状态做个说明. PROCE ...
- 【原创】Linux中断子系统(二)-通用框架处理
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...
- Linux主机解析顺序
1.介绍 本篇文章由于因公司项目上线,需要对项目环境进行压力测试.在压测过程中,所有打压机从公网对目标项目服务器进行压力测试,发现和内网压力测试的性能结果差距10倍左右,在调整主机对DNS的解析顺序之 ...
- Android Animation学习(三) ApiDemos解析:XML动画文件的使用
Android Animation学习(三) ApiDemos解析:XML动画文件的使用 可以用XML文件来定义Animation. 文件必须有一个唯一的根节点: <set>, <o ...
- Linux系统解析域名的先后顺序【转帖】
Linux系统解析域名的先后顺序 gd_WWW已经在本地(/etc/hosts)进行指向,但是竟然还能解析到外网,让我百思不得其解.经过不断查找发现域名解析与以下四个文件有关: /etc/hosts ...
随机推荐
- setInterval循环设置并传入不同的参数
var taskId; var __sto = setInterval; window.setInterval = function(callback,timeout,param){ var args ...
- snort规则中byte_test参数详解
例子: byte_test:4,>,1000,20 这里是从本规则内前面匹配的位置结尾开始,向后偏移20个字节,再获取后面的4个字节的数据,与十进制数据1000进行比较,如果大于1000,就命中 ...
- jenkins部署自动化项目备注
一.定时任务部署: 第一个*表示分钟,取值0~59 第二个*表示小时,取值0~23 第三个*表示一个月的第几天,取值1~31 第四个*表示第几月,取值1~12 第五个*表示一周中的第几天,取值0~7, ...
- java8(一)Lambda表达式
其实很久前已经学习过了Lambda表达式,但是学习后没有多少使用的机会,久而久之也就忘记(惭愧).最近新的项目用的jdk8所以准备再学习一次,写下文章也是为了记录,方便以后再忘的时候,不用到处找资料( ...
- egg-sequelize-ts 插件
egg-sequelize-ts plugin 目的 (Purpose) 能让使用 typescript 编写的 egg.js 项目中能够使用 sequelize方法,并同时得到egg.js所赋予的功 ...
- 全世界仅有的唯一最高LINUX版本的白菜路由,支持NAND记
在上上篇 真千兆路由的极限之OPENWRT MAKE, 某品牌白菜价QCA9558/QCA9880/QCA8337N纯种组合OS搭建时记 里,有没有还记否之模式退一步,海阔天空 回到了远古时代的ar7 ...
- 自己动手实现MQTT协议
写在前面 前段时间弄IoT相关的东西,系统学习了一下 MQTT 协议,在此分享出来. 本文先是对 MQTT 协议做了简单的介绍:接着是对 MQTT协议的内容做了较为全面的解读:最后使用 Python ...
- 使用flash2print 代替 printflash 将office文档 转为flash 在页面中播放
前一些日子公司需求把用户上传的一些word等 文档 能像百度文库那样 显示给用户, 但是如果是直接显示office文档的话就需要 些控件的支持 .非常的不友好,所以 一开始我就想能不能转成pdf 来 ...
- Go_ go mod 命令解决墙的问题
简介 由于众所周知的原因,在下载一些库的时候会下载不了,比如 golang.org/x/... 相关的库.为此,网上出现了很多解决方案. 从 Go1.11 开始,Go 引入了 module,对包进行管 ...
- Springboot源码分析之jar探秘
摘要: 利用IDEA等工具打包会出现springboot-0.0.1-SNAPSHOT.jar,springboot-0.0.1-SNAPSHOT.jar.original,前面说过它们之间的关系了, ...