当前位置: 首页 > article >正文

[A-13]ARMv8/ARMv9-Memory-虚拟地址翻译(页表映射过程)

ver 0.1
gzh

更多精彩内容,请关注公众号

前言

前面我们介绍了ARM的关于内存管理的软硬件体系,对相关的一些重要的基础组件和设计概念做了详细的介绍,目的就是和大家一起摸一摸ARM的AArch64 Virtual Memory System Architecture (VMSA)。VMSA体系的核心思想就是构建一个虚拟的内存世界,然后将这个世界分成不同的空间,在运行时让这些空间共享物理内存,最大程度的发掘硬件资源的价值。连接这两个世界的信使就是页表,前面的文章中我们也把页表称之为账本,并且说明了账册结构(多级页表架构)以及账本的明细的格式(页表描述符)。本文讲介绍MMU是如何使用页表完成虚拟地址到物理地址的映射,其实这个过程也是一般现代处理器地址映射的工作原理。

正文

1 页表映射

1.2 虚拟地址翻译的钥匙

前文专门有一篇文章介绍了地址空间,其实一个地址空间就是一段程序执行的上下文,这段程序可以是kernel、可以是用户空间的进程、可以是Hypervisor,也可以是Secure Firmware。ARM通过Exception模型和Secure模型对这些空间做了更加精细的划分,如图1-1所示。
1-1

图1-1 典型的基于ARM架构的内存空间模型划分

上图中是比较典型的基于虚拟化架构的虚拟内存空间的划分。前序的文章中我们已经介绍过了,EL2层是可以配置的,当EL2层存在的时候,EL1&0虚拟地址空间需要经过两个阶段的翻译才能找到物理内存,而本文为了介绍地址翻译的原理我们简化一下模型,舍弃EL2层,让EL1&0地址空间可以直接映射到物理内存空间,如图1-2所示。
1-2

图1-2 None-Secure EL1&0虚拟地址空间映射

通过图1-2,我们从另外一个维度对EL1&0所代表的地址空间做了映射,这里可以看出EL1&0是共享整个64bits的虚拟地址空间,但是ARM觉得它太大了,不好管理,继续分,如图1-3所示。
1-3

图1-3 一种None-Secure EL1&0虚拟地址空间划分配置

通过系统寄存器TCR_ELx(Translation Control Register,地址翻译控制寄存器)的配置,EL1和EL0各自有了自己的虚拟地址空间。现代处理器和操作系统设计的目标就是多任务并发执行,最大程度的发挥硬件的性能,ARM也是如此。以linux系统为例,OS(Kernel)空间(EL1 Space)是共享的(Global),而用户空间(EL0)的各个App是需要做到进程之间隔离的,首先要做到的就是每个进程之间虚拟地址空间的隔离。这个隔离不是将“EL0 VA Space”分段处理然后分配给各个App,而是每个app都独占(Non-Global)属于自己的完整的“EL0 VA Space”。要实现这个设计思路,就需要记录虚拟地址空间分配使用情况的页表具备描述虚拟地址空间是否共享的能力,事实上也是这样,参考图1-4所示。
1-4

图1-4 块(页)描述符属性标志位

来看一下手册中对页描述符中nG位的描述:

For translation regimes that use an ASID, it is possible to mark translations as global or non-global.
The nG bit in a Block descriptor and Page descriptor indicates one of the following:
• If the value is 0, the translation is global and the TLB entry applies to all ASID values.
• If the value is 1, the translation is non-global and the TLB entry applies to only the current ASID value.

简而言之,arm通过页表配置页表的属性来控制用户空间各个进程虚拟地址空间的隔离性,也就是说在不同的上下文都拥有自己独立的页表,kernel、App1、App2… 都拥有自己的页表。这一部分不展开讨论了,先思考一个问题,在EL1&0的虚拟地址空间下,通过配置EL1的部分被配置成了共享的Global区域了,EL0区域的进程的虚拟地址空间又拥有独立的完整虚拟地址空间,那么在运行时,PE发射过来的虚拟地址,MMU能在TLBs中命中还好,如果不能命中,就要对当前的地址空间做页表遍历,这个遍历的入口在哪里?怎么通知MMU呢?答案是通过一个系统寄存器TTBR,如图1-5所示。
1-5

图1-5 典型多级页表架构模型

都说一把钥匙开一把锁,小时候父母经常把钥匙放在家门口的一个固定的位置,放钥匙的地方就是TTBR,而钥匙就是TTBR中存储的页表的基础地址(物理地址),我们先得找到这把钥匙才能打开地址翻译的大门。

1.2 TTBRx

ARM的TTBR(Translation Table Base Register,翻译表基址寄存器)是ARM架构中用于分页管理和地址转换的重要寄存器。结合图1-2 和 图1-5,我们先把这把钥匙给插到EL1&0虚拟地址空间的翻译的锁上看一下,如图1-6所示。
1-6

图1-6 EL1&0 页表映射模型

在AArch64中,按照图1-5的配置,TTBR0和TTBR1寄存器分别用于用户和内核空间,实现了独立的页表。这种设计使得用户虚拟地址空间和内核虚拟地址空间采用了不同的页表,从而提高了系统的安全性和灵活性。用户空间每个进程虚拟地址的高位都是0,而内核虚拟地址的高位都是1。MMU(内存管理单元)会自动根据虚拟地址的高位是否为1来判断该地址是用户虚拟地址还是内核虚拟地址,并据此选择使用TTBR0还是TTBR1寄存器进行地址转换。接下来看看TTBR寄存器的具体实现,如图1-7,1-8所示。
1-7

图1-7 TTBR0_EL1 的64bits格式

1-8

图1-8 TTBR1_EL1 的64bits格式

我们可以看到TTBR0_EL1和 TTBR1_EL1 几乎是一样的,重要的两个字段分别是BADDR和ASID。

BADDR
BADDR保存的就是当前地址空间一级页表的基地址。TTBR0通常用于存放用户空间的一级页表基址,而TTBR1用于存放内核空间的一级页表基址。这样,在进行地址转换时,可以根据虚拟地址的不同范围选择不同的TTBR寄存器。
ASID
ASID(Address Space Identifier,地址空间标识符)使得操作系统能够为每个进程分配一个唯一的标识符,以便在TLB(Translation lookaside Buffer,转换后备缓冲器)中区分不同进程的页表项。这样,当进程切换时,TLB中缓存的页表项不会被错误地应用于其他进程。这样就可以减少TLB刷新开销,在没有ASID的情况下,每次进程切换时都需要刷新TLB,以确保新的进程不会使用旧的进程页表项。而ASID的引入使得TLB可以缓存多个进程的页表项,从而在进程切换时无需刷新整个TLB,只需刷新与当前进程不相关的TLB条目,从而降低了进程切换的开销。最终的效果就是,通过减少TLB刷新次数和提高TLB命中率,提高系统的了整体性能。因为TLB是访问内存时的重要缓存,其命中率直接影响到内存访问的速度和效率。

EL1&0空间的虚拟地址翻译的Stage1阶段的钥匙(TTBR0_EL1和TTBR1_EL1 ),我们就介绍到这里。其他地址空间和阶段的钥匙,我们通过图1-9表示一下,格式和工作原理基本相似,感兴趣的同学可以自行阅读手册。
1-9

图1-9 两级地址翻译中使用的TTBR

1.3 虚拟地址翻译(页表映射)

现在我们已经找到了地址翻译的钥匙,下面就看一下MMU是如何利用这把钥匙进行虚拟地址翻译的。首先,我们来看图1-10,来回忆一下MMU工作的过程。
1-10

图1-10 页表遍历流程

CPU执行软件的过程中发射了虚拟地址,那么MMU要用这个虚拟地址在TLBs里面进行匹配,当然匹配的时候只能在自己的内存空间中中做匹配,这就用到了ASID(有的时候还需要VMID和其他条件)。如果能命中的话,直接返回VA对应的物理地址就好了,如果不能命中那么BADDR就派上用处了,TWU(Table Walk Unit)需要通过这个BADDR中存放的PA去变量Cache中缓存的页表,如果命中则返回,如果还不能命中就要到主存中进行遍历了,当然遍历的还是自家(ASID)的页表空间,我们下面的章节要讲的就是这个遍历的过程。

1.3.1 翻译过程(核心思想)

我们前文的叙述和前序文章的叙述,都是为了这一刻,看看现在处理器和现代操作系统是如何紧密的配合将一个虚拟地址VA翻译成物理地址PA返回给PE,如图1-11所示。
1-11

图1-11 4k页-4级页表配置的虚拟地址的翻译流程

上图中,我们终于看到了一个虚拟地址翻译流程(核心思想)的全貌:
(1) Step-1:确定TTBRn
PE的MMU根据系统寄存起TCR_ELx的的配置和虚拟地址VA来判断使用哪个页表基地址寄存器,是 TTBR0 还是 TTBR1 。当虚拟地址高位区(直接判断VA[63] )为 1 时选择 TTBR1 ;当虚拟地址高位区(直接判断VA[63])为 0 时选择 TTBR0 。页表基地址寄存器中存放着 1 级页表的基地址。确定TTBRn_ELx后,就能通过TTBRn_ELx.BADDR拿到当前地址空间的L0级页表的起始物理地址。
(2) Step-2:遍历L0级页表
处理器将 VA[47:39] 作为 L0 索引,在 1 级页表( L0 页表)中找到页表项, 1 级页表有 512(VA[47~39]) 个页表项。1 级页表的页表项中存放着 2 级页表( L1 页表)的物理基地址。遍历结束后拿到L1级页表的起始物理地址。
(3) Step-3:遍历L1级页表
处理器将 VA[38:30] 作为 L1 索引,在 2 级页表中找到相应的页表项, 2 级页表有 512(VA[38~30]) 个页表项。2级页表的页表项中存放着 3 级页表( L2 页表)的物理基地址。遍历结束后拿到L2级页表的起始物理地址。
(4) Step-4:遍历L2级页表
处理器以 VA[29:21] 作为 L2 索引,在 3 级页表( L2 页表)中找到相应的页表项, 3 级页表有 512(VA[29~21]) 个页表项。3 级页表的页表项中存放着 4 级页表( L3 页表)的物理基地址。遍历结束后拿到L3级页表的起始物理地址。
(5) Step-5:遍历L3级页表
处理器以 VA[20:12] 作为 L3 索引,在 4 级页表( L3 页表)中找到相应的页表项, 4 级页表有 512 (VA[20~12]) 个页表项。4 级页表的页表项里存放着 4KB 页面的物理基地址。遍历结束后拿到对应4K页面的起始物理地址。
(6) Step-6:计算物理地址
拿到4K页面的起始物理地址,然后加上 VA[11:0] ,就构成了新的物理地址,此时MMU就完成了页表的查询和翻译工作。

上面的就是在没有异常情况下的一次4级页表的遍历过程,这个过程全部由MMU自己完成,是一次硬件行为。请大家注意一个前提,就是没有任何异常的情况下,这里我们为了方便简化了流程,实际上在处理的过程需要处理各种内存 Aborts,比如:Translation Fault、Address size fault、External abort 、Access flag fault、Permission fault等。这些异常有的需要软件参与处理,比如缺页错误,有的可能会直接导致系统崩溃重启,这些内容正在规划一篇文章完整的介绍一下。这里,目前大家能从上面的流程中举一反三,推导出其他内存配置下的虚拟地址翻译过程就可以了。

1.3.2 上下文切换

考虑到文章的完整性,这里还要针对系统执行时的上下文做一个介绍,来看一下在多任务系统中怎么能让MMU始终能够拿到正确的TTBRn,从而让整个翻译的过程始终处于正确的内存空间。
通过图1-1,我们可以看到ARM的PE在运行时要在不同的安全状态下进行切换,也要在不同的异常等级下切换。就算在同一个系统下(EL1&0),也要在不同的task下进行切换,或者在异常处理状态和Task下进行切换,这些具体的执行场景其实就是一个又一个的上下文。而这个上下文中,最重要的一个元素就是地址空间:从一个task切换到另一个task,要切换task地址空间;从一个GuestOS切换到另外一个GuestOS,也需要切换地址空间;等等。上下文的切换是一个系统的、完整的执行状态的切换,PE-Core上执行的系统级别的代码要完成当前上下文元素的保存,然后再恢复另外一个上下文元素的恢复。我们来看一下一个Task切换到另外一个Task的这种场景下,需要保存和恢复的上下文有哪些元素:

Exactly what has to be saved and restored varies between different operating systems, but typically a process context switch includes saving or restoring some or all of the following elements:
• General-purpose registers (X0 - X30).
• Advanced SIMD and floating-point registers (V0 - V31).
• Some status registers.
• TTBR0_EL1 and TTBR0.
• Thread Process ID (TPIDxxx) Registers.
• Address Space ID (ASID).
For EL0 and EL1, there are two translation tables. TTBR0_EL1 provides translations for the bottom of the virtual address space, which is typically application space and TTBR1_EL1 covers the top of the virtual address space, typically kernel space. This split means that the OS mappings do not have to be replicated in the translation tables of each task.

从上面的分析可以看出,任务的切换伴随着TTBRn的切换,这个切换过程需要OS代码的介入才能完成。上面的工作就能保证PE在上下文切换完成后,执行当前任务的代码的时候发射虚拟地址VA的时候,已经成功的更新了系统寄存器TTBRn,这样就能够保证MMU的工作始终在正确的内存地址空间中。其实TLBs的遍历也一样,就是在遍历之前ASID也会得到更新。

结语

本文从一把“钥匙”(TTBRn.BADDR)开始,介绍了MMU进行地址翻译的准备工作,并带着大家完整的走完了一次虚拟地址翻译的流程。我们详细的阐述了PE发射VA的各个段在地址翻译过程中的作用,并最终找到了虚拟地址对应的物理地址,最后返回给PE。最后我们简要的介绍了上下文切换的基本原理,解释了MMU如何在操作系统的配合下始终工作在正确的内存空间。
本文也算是我们ARM内存系列的一个小小的里程碑,我们介绍了ARM内存管理体系的核心概念和工作的原理,后续还有几篇文章大概就是几个专题性的介绍,例如内存的属性、内存异常机制处理、Stage-2翻译等等,请大家保持关注。

gzh

更多精彩内容,请关注公众号

Reference

[00] <corelink_dmc520_technical_reference_manual_100000_0202_00_en.pdf>
[01] <corelink_dmc620_dynamic_memory_controller_technical_reference_manual_100568_0100_00_en.pdf>
[02] <IP-Controller/DDI0331G_dmc340_r4p0_trm.pdf>
[03] <80-ARM-IP-cs0001_ARMv8基础篇-400系列控制器IP.pdf>
[04] <arm_cortex_a725_core_trm_107652_0001_04_en.pdf>
[05] <arm_cortex_a720_core_trm_102530_0001_04_en.pdf>
[06] <DDI0487K_a_a-profile_architecture_reference_manual.pdf>
[07] <armv8_a_address_translation.pdf>
[08] <cortex_a55_trm_100442_0200_02_en.pdf>
[09] <learn_the_architecture_aarch64_memory_management_guide_101811_0103_03_en.pdf>
[10] <learn_the_architecture_armv8-a_memory_systems_100941_0101_02_en.pdf>
[11] <80-ARM-MM-cs0001_mmu表描述符和块描述符.pdf>
[12] <80-ARM-MM-wx0008_armv8_armv9页表属性page-descriptor的详细介绍.pdf>
[13] <80-ARM-MM-wx0017_深度学习arm-MMU一篇就够了.pdf>
[14] <80-ARM-MM-wx0004_Arm64-MMU及页表映射.pdf>

Glossary

MMU - Memory Management Unit
TLB - translation lookaside buffer
VIPT - Virtual Index Physical Tag
VIVT - Virtual Index Virtual Tag
PIPT - Physical Index Physical Tag
VA - Virtual Address
PA - Physical Address
IPS - Intermediate Physical Space
IPA - Intermediate Physical Address
VMID - virtual machine identifier
TLB - translation lookaside buffer(地址变换高速缓存)
VTTBR_EL2 - Virtualization Translation Table Base Registers(ArmV8 寄存器)
ASID - Address Space Identifier (ASID)
DMC - Dynamic Memory Controller
DDR SDRAM - Double Data Rate Synchronous Dynamic Random Access Memory,双数据率同步动态随机存储器
IA - Input Address
OA - Output Address
VMSA - Virtual Memory System Architecture


http://www.kler.cn/news/356458.html

相关文章:

  • nginx过滤模块怎么生效的
  • c++基础知识1
  • wpf 窗口关闭前 弹出提示窗口
  • CPP-TCP80优化
  • Python知识点:基于Python工具,如何使用Brownie进行智能合约测试
  • R语言复杂抽样调查数据统计描述和分析
  • Vue-admin-box后台管理框架
  • Leetcode 1 的位数
  • 文字跑马灯:实现文字自动滚动策略的原理分析
  • TwinCAT3添加NC轴
  • Text2Video Huggingface Pipeline 文生视频接口和文生视频论文API
  • 【微服务】微服务发现详解:构建高效分布式系统的关键
  • c# 里list和array的应用比较说明
  • SwanLab VSCode插件已发布,附使用教程
  • 不做邮箱投稿的奴隶,要做单位信息宣传考核计分投稿的主人
  • SpringBoot智慧外贸平台
  • 大数据-173 Elasticsearch 索引操作 增删改查 详细 JSON 操作
  • Java - SpringMVC
  • 反走样算法(MSAA、TAA、FXAA、DLSS)
  • HBASE介绍和使用