ver0.2
前言
前序的文章中,我们介绍了SMMU页表的架构,为我们进一步研究SMMU的工作流程打下了基础。SMMU的核心作用还是帮助总线上接入它的Master进行地址翻译。这个翻译的过程就是找到一个物理地址(总线地址)返回给设备,让它拿着这个地址访问内存。这个过程和CPU的工作流程是一样的,只是CPU的PE-Core交给MMU的总是虚拟地址,而SMMU的情况就复杂了,这个我们也会在下文中都聊到。还是希望大家在阅读本文之前建立起对页表映射、地址翻译的感觉,然后再看SMMU的页表映射过程就很容易接受了。先看看前序文章吧,再进入正文:
(1) [A-13]ARMv8/ARMv9-Memory-虚拟地址翻译(页表映射过程)
(2) [A-20][V-07]ARMv8/v9-内存虚拟化(Stage-2 Translation)
正文
1.1 SMMU的工作模式
先看一下SMMU地址翻译的大致流程,搞清楚SMMU可以工作在哪些模式下,如图1-1所示。
图1-1 High-Level SMMU地址翻译流程
1.1.1 两级翻译模式
这种模式下,设备输入的虚拟地址(VA)会经历全部的地址翻译过程,从VA-IPA-PA,返回给设备PA进行总线操作访问到自己想要交互的物理内存,图1-1左侧部分。我们后面的的章节也会对这种模式做重点讨论。
1.1.2 Bypass模式
第二种模式就是Bypass模式了,图1-1右边的绿色部分,之所以和红色部分重叠,原因是这种模式下会对两级翻译模式产生交叉影响。先来看看手册中对Bypass模式的介绍:
In bypass mode, the SMMU does not have to translate the addresses of incoming transactions. A stream or entire Security state can be set to bypass. This means the output address is equivalent to the input address. However, the other input transaction attributes, for example cacheability, can still optionally be overridden. There are three types of bypass:
Global bypass
When translation is bypassed for one Security state, all transactions are bypassed translation for that Security state. Software can set SMMU_(*_)CR0.SMMUEN to 0 to enable global bypass. Software can also optionally set SMMU_(*_)GBPA to override input attributes.
Stream bypass
This type of SMMU bypass is available when SMMU_(*_)CR0.SMMUEN = 1 . This is when a StreamID selects an STE configured to bypass(STE.Config). For a stream-based bypass, the attributes are configured using STE fields. STE.
{MTCFG,MemAttr,ALLOCCFG,SHCFG,NSCFG,PRIVCFG,INSTCFG} can override any attribute before the transaction is passed to the memory system
Stage bypass
When translation is enabled, bypass is configured separately for each stage of translation, this is also controlled by STE.Config :
• Stage 1 bypass: STE.Config[0]
• Stage 2 bypass: STE.Config[1]
This is almost the same as disabling a stage of translation in the VMSA architecture.
If an SMMU does not implement one of the two stages of translation, it behaves as though that stage is configured to permanently bypass translation. Other restrictions are also relevant, for example it is not valid to configure a non-present stage to translate. An SMMU must support at least one stage of translation.
结合手册我们对Bypass模式做一下总结:
(1) SMMU的Bypass模式是一种特殊的设置,在这种模式下,SMMU不对设备请求的地址进行转换,而是直接透传这些地址。这意味着设备可以直接使用物理地址进行DMA操作,而无需经过SMMU的地址转换流程。
(2) Bypass模式可以细分为三种:Global Bypass、Stream Bypass、 Stage Bypass。
• Global Bypass模式下,相当于是使能SMMU的总开关,这种模式下输入的地址会直接当成输出地址进行输出。
• Stream Bypass模式下,相当于直接限制设备,SMMU使用StreamID来标识不同的设备或数据流。通过配置特定StreamID对应的STE,可以将该Stream设置为Bypass模式。这样,只有特定Stream的数据流才会绕过地址转换。
• Stage bypass模式下,则是限制地址翻译的阶段了,这个要结合VMSA的工作模式去横向对应了,如果VMSA被设置成只工作在某一个Stage,那么SMMU也要做对应的设置。
(3) 通过描述可以看出,Bypass模式的最大好处就是可以简化配置和减少地址翻译阶段的工作,从而达到优化SMMU性能的目的。
(4) 虽然Bypass模式下可以一定程度上改善SMMU性能,但是还是要注意,这是相对的。以ARM体系为例,地址不是在SMMU内部翻译了,就要在别的地方(总线上的其他Master)进行翻译,总之肯定要有一个节点干这个事儿,虽然SMMU性能提升了,但是不代表整个系统的负荷会下降。另外还有一点就是安全性,SMMU不光是翻译地址还会伴随着一些内存属性、配置、权限等检查,可以抛出一些非法访问的异常(中断信号)给CPU,如果选择Bypass了,就要通过软件的方式进行更加精细的控制才会避免出错。
1.1.3 SMMU的寄存器
通过上一个小节的描述,我们会发现软件对SMMU内部寄存器的配置会直接影响SMMU在运行时的行为(后面的章节还是会提到寄存器的关键作用),这个和CPU内部的寄存器是一样,如图1-2所示。
图1-2 SMMU相关寄存器
这部分内容不会展开讨论,需要的时候大家可以自行查阅相关手册即可,比如GPBA寄存器就是长这个样子,如图1-3所示:
图1-3 SMMU寄存器GPBA格式
虽然寄存器紧贴硬件,但是了解和熟悉寄存器对于很多写底层代码的农民工来说还是非常重要的。如果对寄存器感到陌生,比如寄存器基础概念,驱动程序如何配置总线Master上的寄存器,建议大家看看前序文章:
(1)[V-04] 虚拟化基础-寄存器集(基于AArch64)
(2)[A-14]ARMv8/ARMv9-Memory-内存模型的类型(Device & Normal)
1.2 SMMU页表遍历的钥匙
我们在讲述VMSA体系下的虚拟地址翻译的时候,通过一把钥匙找到了我们要进行虚拟地址映射的页表的位置。现在我们对设备使用的虚拟地址进行映射,自然也要找到这把钥匙去打开锁着设备页表的那扇门。对于已经了解了SMMU多级页表架构的我们来说这并不是难事,如图1-4所示。
图1-4 SMMU多级页表架构
上图是一个典型的SMMU工作在两级地址翻译模式下的多级页表架构,与ARM的MMU相比,SMMU要找到这把钥匙就要费事一些。
MMU那是真的很潇洒,CPU在执行Kernel的代码进行上下文切换的时候,顺手就把系统寄存器TTBRn里面“钥匙”给切换了,这样MMU拿着钥匙打开页表的大门干活就行了,如图1-5所示。
图1-5 VMSA地址空间映射
通过上图可以看出,ARM的PE-Cores可以根据不同的上下文(安全状态、权限等级、地址空间)下系统寄存器TTBR进行地址虚拟地址空间到物理地址空间的映射。而通过图1-4可以看出,SMMU要找到设备要使用的页表地址的大门却不是那么的容易,因为这把钥匙被分成了3段(虽然不是特别严谨,但是为了能帮助大家理解,还是厚着脸皮这么写。借用著名的、伟大的明朝宰相赵阁老一句名言:再苦一苦读者,骂名我也不担。)。
1.2.1 钥匙第一段(SMMU_(S_)STRTAB_BASE)
SMMU驱动程序在初始化的时候,就要把所有它所有的能Cover的设备根据StreamID的先后顺序初始化一段连续的内存,存放设备的第一手配置信息。初始化成功之后,就要把这段内存的起始地址放在 SMMU的寄存器STRTAB_BASE中,如图1-6所示。
图1-6 SMMU_(S_)STRTAB_BASE格式
我们已经知道了这段内存的地址了,再看一看这段内存里面放着啥。前序文章中,我们已经讲过了,这段内存中放着STEs,如图1-7所示。
图1-7 SMMU STE格式
一个STE好多个字节啊,不过想想应该,毕竟描述的是一个总线上的设备。这部分不展开讨论了,感兴趣的小伙伴可以自行阅读手册。
1.2.2 钥匙的第二段 : Context Descriptor (CD)
CD中存放的是Stage-1阶段设备页表的基地址,这个地址需要在PE-Cores执行的设备驱动程序在建立完相应的页表后,借助SMMU的驱动程序框架提供的服务接口在运行时进行及时的更新。那么CD长什么样子呢?如图1-8所示。
图1-8 SMMU CD格式
一个CD也是好多个字节啊,不过想想也应该,毕竟描述的是VMSA Stage-1阶段一个地址空间的上下文。这部分也不展开讨论了,感兴趣的小伙伴可以自行阅读手册。这里面需要提一句关于TTB0和TTB1如何选择,如何理解,需要一定的基础(主要涉及到ARM的Feature,特别是执行状态、地址空间的划分等等),建议大家读一读前序文章,自然就能够理解了(如果一点基础没有,自然理解起来有点费劲,还是建议一篇一篇的读下来,功到自然成),特别是:
(1)[A-09]ARMv8/ARMv9-Memory-内存地址空间(Translation Regimes)
1.2.3 钥匙的第三段 : VMID & S2TTB
通过VMID和S2TTB就能够找到SMMU需要在Stage-2阶段进行地址翻译的页表的基地址。VMID(Virtual Machine Identifier)和S2TTB(Address of Translation Table base)需要运行在ARM异常模型的EL2等级的SMMU驱动程序进行运行时的上下文的维护。
1.2.4 钥匙合体
严格说,钥匙的第二段和第三段都是STE的延伸,VMID和S2TTB直接就是STE内部的字段,如图1-9所示。
图1-9 SMMU STE中的关键字段
结合图1-4,钥匙的合体就很好理解了,这一部分就不展开说了,现在我们总算拿到了设备需要使用的页表的基地址了。来吧,打开那扇门,开始干活。
1.3 虚拟地址翻译
前面铺垫了半天就是为了这一个激动人心的时刻,如图1-10所示。
图1-10 SMMU地址翻译流程图
按照上图我们把设备使用的虚拟地址翻译过程分成四个阶段:
(1) 准备阶段
这个阶段主要是设备和SMMU的驱动程序在忙,两个目的,
• 第一个是将SMMU相关寄存器和内存中的状态数据切换成正确的上下文,这个和MMU工作的原理是一致的。
• 第二个目的,就是准备好如下信息:设备信息(StreamID)、PE-Core的上下文信息(SubstreamID)、地址信息(VA)。
(2) 检查配置
SMMU拿到上一个阶段传递来的信息后,就开始进行设备基本信息的检查,看看有没有违规、越权、越界的地方。如果有的话,直接抛出异常通知CPU让驱动程序端正态度,好好干活。驱动程序死不悔改,态度恶劣的,不能及时纠正配置错误信息的,直接升级处理不给机会。如果能顺利通过检查,那么就可以拿到相应的信息(ASID、PE-Core上下文的一些状态信息、地址)进入下一个阶段。
(3)遍历页表
这个阶段就要完成虚拟地址到物理地址的转换,但是过程和MMU的工作流程是一致的,也分成两个阶段:
• 前文中讲述SMMU系统架构的时候,我们已经清楚了,SMMU内部也是TLB的,也就是会缓存之前的地址翻译的结果的,目的就是为了提高SMMU地址翻译的效率。那么SMMU就可以根据前一个阶段传递来的信息,首先进行TLB内部的遍历,如果命中,直接返回PA就可以了,这是最理想的情况。
• 如果TLB未命中,那就得老老实实的进行访问物理内存的操作,进行页表遍历找出对应虚拟地址映射的物理地址了,这个过程如图1-11所示。这个过程和MMU的虚拟地址翻译的核心思想是一致的,所不同的就是部分配置信息获取的位置不一样(看看前面章节中讲述的那把钥匙)。
图1-11 SMMU页表遍历流程
(4)内存访问
设备拿到了VA对应的物理地址后,就可以发起对物理地址空间的访问了,终于达到目的了。胜利!!!。
1.4 异常处理
上面的地址翻译过程看上去还是比较顺利的,实则不然。和VMSA体系下访问内存一样,也是一路要谨小慎微的。SMMU在这个过程中要时刻关注地址映射的这个过程并随时向系统的指挥官CPU报告,如图1-12所示。
图1-12 SMMU异常处理流程
这一部分不展开说了,只截取一段供大家感受一下:
If a valid configuration is located so that the translation tables can be accessed, the translation process begins. Other faults can occur during this phase. When a transaction progresses as far as translation, the behavior on encountering a fault becomes configurable. The following fault types that constitute Translation-related faults when they are generated at either stage 1 or stage 2:
• F_TRANSLATION
• F_ADDR_SIZE
• F_ACCESS
• F_PERMISSION
These fault types correspond to the fault types in VMSA as:
• Translation fault
• Address Size fault
• Access Flag fault
• Permission fault
其实笔者还在规划VMSA下的异常处理的文章,写了几稿都不太满意,主要原因还是笔者对VMSA的理解还是不够深刻,还需要进一步的深入研究推敲。
结语
关于SMMU虚拟地址翻译的话题,我们就聊到这里。本文我们从SMMU的工作模式说起,又对SMMU页表架构中的相应的数据结构串联在一把钥匙上给大家做了展示,然后介绍了SMMU地址翻译的各个阶段,最后简单带过SMMU工作过程中的一些异常处理流程。对于SMMU地址翻译的背景信息,工作流程的介绍,本文的颗粒度还是很粗的,很多地方都没有展开来写。这里只是帮大家建立起一个基本的框架,细节的部分希望读者根据自己的兴趣点慢慢发掘,慢慢研究了。谢谢大家,请保持点赞、评论、转发。再次感谢,请保持关注。
Reference
[00] <aarch64_virtualization_100942_0100_en.pdf>
[01] <Armv8-A-virtualization.pdf>
[02] <learn_the_architecture_aarch64_virtualization.pdf>
[03] <DDI0487K_a_a-profile_architecture_reference_manual.pdf>
[04] <DEN0024A_v8_architecture_PG.pdf>
[05] <learn_the_architecture_aarch64_memory_model.pdf>
[06] <80-LX-SMMU-IOMMU-cs0005_linux-DMA-API使用指导.pdf>
[07] <80-V-KVM-k0005_Linux虚拟化KVM-Qemu分析(五)-内存虚拟化.pdf>
[08] <80-LX-SMMU-IOMMU-cs0001_Linux-iommu和vfio概念空间解构.pdf>
[09] <learn_the_architecture_aarch64_memory_management.pdf>
[10] <learn_the_architecture_smmu_software_guide.pdf>
[11] <QNX_SMMUMAN_Users_Guide.pdf>
[12] <IHI0070G.a-System_Memory_Management_Unit_Architecture_Specification.pdf>
[13] <80-ARM-SMMU-wx0001_SMMU学习这一篇就够了(软件硬件原理_模型导读).pdf>
[14] <80-ARM-SMMU-cs0001_ARM-SMMU学习笔记.pdf>
[15] <corelink_mmu600_system_memory_management_unit_trm.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
ASID - Address Space Identifier (ASID)
SMMU - System Memory Management Unit
STE - Stream Table Entry
CD - Context Descriptor
GPC - Granule Protection Checks
GPT - Granule Protection Table
ATS - Address Translation Services
ATC - Address Translation Cache
DPT - Device Permission Table
PRI - Page Request Interface
PPRs - PRI Page Requests (PPRs)
VMS - Virtual Machine Structure
CMO - Cache Maintenance Operation
IWB - inner Write-Back
OWB - Outer Write-back
ISH - Inner shareable
PASID - Process Address Space Identifier
ACS - Access Control Services
ITS - Interrupt Translation Service
MSI - Message-Signaled Interrupts
SVA - Shared Virtual Addressing
BA - Bus Address
GBPA - Global ByPass Attribute