前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Fixmap机制深入分析

Fixmap机制深入分析

作者头像
Linux阅码场
发布2021-05-31 09:47:43
1.6K0
发布2021-05-31 09:47:43
举报

作者简介

于浩进,linux内核爱好者,现就职于北京灵汐科技有限公司,任职BSP工程师,主要负责IP验证、多媒体驱动开发及一些bring up等工作。


01 背景介绍

Fixmap机制是kernel在启动过程中(start_kernel)临时的映射机制,目的是在真正页表建立之前用于完成对io设备的访问、device-tree的解析以及paging_init中的页表切换等。本文将对该机制做一个深入的分析。

02 环境说明

2.1 硬件环境

某SOC芯片,CPU为8核cortex-A53,其DDR物理地址为0x800000000,device-tree存放的物理地址为0x843000000。

2.2 kernel版本

4.19.83版本。

2.3 kernel相关配置介绍

  • 相关Config配置
  • 相关宏配置

以下宏的值,只给出结果了:

03 虚拟空间拓扑

3.1 虚拟空间拓扑

3.1.1 VA=39bit下kernel虚拟地址空间拓扑

图1详细展示了VA=39bit下kernel虚拟地址空间拓扑,里面展示了FIXMAP区域在整个虚拟地址空间所处的位置。

3.1.2 FIXMAP地址空间拓扑

Kernel对Fixmap区域做了进一步的划分,各区间是在enum fixed_addresses 枚举类型定义的(/arch/arm64/include/asm/fixmap.h)。

其各个区间的virtual address通过fix_to_virt(const unsigned int idx)函数获得,其定义是在/include/asm-generic/fixmap.h里面,这个函数后面会用到。

下图2详细展示了各个区间的base address。

Fix_to_virt的定义如下:

3.1.3 FIXMAP初始化

Bm_pte、bm_pmd、Bm_pte为三个全局数组,用于暂存pud、pmd、

pte的页表。

early_fixmap_init()函数完成了fixmap映射的基础框架,如下图3所示,bm_pte数组并没有填值,因为当前还不知道哪些物理地址需要映射,等需要映射时候再去填写bm_pte的entry。

经过分析代码,整理了fixmap各段虚拟地址与bm_pmd entry的关系,如下图4所示:

需要说明的是FIX_PGD~FIX_FDTbm_pmd是属于同一个entry,即可以用bm_pte做pte映射。

FIX_FDT~FIX_HOLE不属于该entry,即不可以用bm_pte做pte映射,也为后面device-tree的映射做了一个铺垫。

3.2 fixmap在early ioremap应用介绍

3.2.1 early_ioremap_setup()

该函数的比较简单,主要是依靠__fix_to_virt()给slot_virt[i]填入虚拟地址,其布局如下图5所示。

slot[i]是fix_map区域已经规划好的虚拟地址范围,任何I/O地址空间都可以向这7个slot空间做映射。

其中:slot_virt[i] = __fix_to_virt(FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*i),__fix_to_virt()在之前已经介绍过。Slot_virt每个区间size为256K。

3.2.2 __early_ioremap()

有三个数组需要说明:

slot_virt[slot]:BTMAP区域各个区间虚拟地址;

prev_map[slot]:__early_ioremap()映射后的虚拟地址;

prev_size[slot]:__early_ioremap()要映射的size;

映射流程如下图6所示:

Figure 6 early ioremap映射流程图

图7展示了early ioremap页表转换过程,还是比较简单的。

3.3 fixmap在early console应用介绍

Early console的映射与early ioremap的映射类似,通过__fix_to_vit(FIX_EARLYCON_MEM_BASE)获取虚拟地址,物理地址为UART在SOC的实际分配的地址(该物理地址来自于command line的earlycon=XXX),然后通过向bm_pte写入页表,即可以完成映射。

图8是函数调用关系。图9是页表的建立和转换过程。

3.4 fixmap在device-tree应用介绍

3.4.1 映射过程分析

Device-tree的映射和early-console、early-ioremap的映射原理有所不同,主要区别在于FIX_FDT空间对应的虚拟地址的pmd entry与FIXADDR_START对应的pmd entry是不同的。

通过分析kernel代码可知对于device-tree的映射需要建立一个2M的block entry即可,即在bm_pmd建立一个block entry。

如下图10所示,只需要找到pmdp,写入block entry的页表项即可。

那问题来了,pmdp的虚拟地址我们是知道的,对应的bm_pmd的entry的物理地址也能知道,但是两者之间的页表还未建立。

因此在用pmdp指针向bm_pmd写入block entry之前,必须要先建立pmdp的页表,这个页表建立过程就与early console的页表建立过程相同了。见下图11所示。

设备树页表的建立会调用到init_pmd()建立block entry,也就是下图12圈2对应的代码,圈1的代码就是对应上图11给pmdp建立页表的过程。

在写入block entry之后,pmdp也就无用了,圈3代码把刚才的pmdp的页表清除了,即把bm_pte对应的表项清除了。

最后再简单展示一下fixmap为设备树建立页表的函数调用关系,如下图13所示。

3.5 fixmap在paging_init中页表切换介绍

3.5.1 paging_init函数简单分析

下图14是paging_init的代码分析。

  • 圈1代码通过memblock分配器分配了一个物理页面,该页面暂存后面代码建立的页表;
  • 圈2代码是通过fixmp机制把这个物理页面映射为虚拟地址;
  • 圈3代码把kernel的镜像的一些代码段、数据做等做映射,在图1有说明;
  • 圈4代码把memblock.memory类型的region区域做线性映射,比如设备树的memory节点的内存,会在此做线性映射,但是会排除代码段和只读数据段,具体细节,还请看源码;
  • 圈5~圈7代码将暂存页表内容拷贝到swapper_pg_dir,同时切换ttbr寄存器,此后CPU发出的虚拟地址就可以通过这套新建的页表进行虚实转换了;
  • 圈8清除pgdp的映射;
  • 圈9代码释放刚才申请的物理页;

3.5.2 paging_init中的fixmap

上图 圈6代码是把临时页表拷贝到swapper_pg_dir,临时页表的物理页是memblock分配器获得的物理地址。

由于mmu已经开启,memcpy无法使用物理地址,所以必须要先用fixmap机制做该物理页面的映射,得到其虚拟地址,即pgd_set_fixmap(addr),其定义如下:

其是借助于fixmp的“FIX_PGD”区域做的映射,页表映射及转换过程如下图15所示。

04 小结

  • 在进入start_kernel之前,head.S的“__primary_switch”已经开启mmu了,使能mmu之后CPU发出的ldr、str指令都为虚拟地址了,因此必须要提前建立好页表,mmu才能把虚拟地址转为物理地址,以访问真正的物理内存;
  • Fixmap用于在” earlyconsole”、” device-tree的解析”、” earlyioremap”、” paging_init的页表切换”等过程建立临时页表。
  • Fixmap机制实际就是为mmu做了相关的虚拟和物理地址的映射;
  • Bm_pmd、bm_pte是两个全局数组,用于存放pmd、pte的页表项;

05 参考文献

https://www.cnblogs.com/LoyenWang/p/11483948.html

https://www.cnblogs.com/LoyenWang/p/11440957.html

https://www.cnblogs.com/pengdonglin137/p/9157639.html

armv8_arm.pdf,从ARM官网下载即可。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-05-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Linux阅码场 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 作者简介
  • 01 背景介绍
  • 02 环境说明
  • 03 虚拟空间拓扑
  • 04 小结
  • 05 参考文献
相关产品与服务
轻量应用服务器
轻量应用服务器(TencentCloud Lighthouse)是新一代开箱即用、面向轻量应用场景的云服务器产品,助力中小企业和开发者便捷高效的在云端构建网站、Web应用、小程序/小游戏、游戏服、电商应用、云盘/图床和开发测试环境,相比普通云服务器更加简单易用且更贴近应用,以套餐形式整体售卖云资源并提供高带宽流量包,将热门开源软件打包实现一键构建应用,提供极简上云体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档