ver0.3
前言
前文我们对SMMU的系统架构和基本功能做了简要的介绍,现在大家大致对SMMU在基于ARM体系的系统架构下的总线位置和产品形态有了基本的了解。这里我们还是简单做个前情回顾,从总线架构角度看过去:
(1) CPU内部就有MMU他要统扩整个VMSA空间,管理好VA到IPA再到PA的各个空间,重要性就没法形容了。
(2) 越来越多的总线IP也在内部集成SMMU,典型如GPU。这样在驱动程序的配合下,GPU自身就可以管理离散内存,实现整个系统性能提升和功能扩展。要说缺点就是贵,毕竟是独占的,哈哈。
(3) 还有就是常见的一种形态存在,各个IP-Core共享的模态存在。这种架构模态下,可以让总线上的各个功能单元共享,可以有效降低成本,就是会增加软件维护的工作量。
无论以哪种种模态出现,SMMU和MMU的核心功能都是地址翻译,它们的很多Feature都是围绕着“地址翻译”展开,那么本文也会围绕着SMMU的地址翻译做一些准备工作,介绍下SMMU的页表架构:一座假设在设备和物理内存之间的桥梁。
正文
1.1 MMU页表的架构
读到这里的小伙伴对页表没有任何经验的话,那你就是没感觉,和谈对象一样,没感觉是不行的,先看看前序文章吧。
(1)[A-10]ARMv8/ARMv9-Memory-页表的概念和使用场景
(2)[A-11]ARMv8/ARMv9-Memory-多级页表架构
(3)[A-12]ARMv8/ARMv9-Memory-页表描述符(Translation table descriptor)
这里我们只会简单地回顾一下。
ARM的VMSA体系下,规定了处理器无论是处于何种安全等级(Secure\Normal\Root\Non-Secure)、任何权限等级(EL3\EL2\EL1\EL0)的程序都必须使用虚拟地址VA和CPU打交道。CPU拿到虚拟地址后,根据虚拟地址的类型(Device/Normal)通过MMU变成物理地址,然后发起总线操作完成对物理地址空间的访问。物理地址空间的资源是有限的,表现为:A进程用了,B进行就不能用;kernel 用了,Userspace就不能用;VM1用了,VM2就不能用;Secure用了,Non-Secure就不能用。虽然高权限等级的软件模块,会对低权限的等级内存产生干预,但也是有底线有原则的。那么VMSA就把地址空间划片(Page、Block),一片虚拟地址空间的内存对应着一片物理地址空间的内存。这个对应关系是需要记录下来的,就是系统在运行时要维护一本账,通过这个账本连接起内存的虚拟地址空间和物理地址空间,如图1-1所示。
图1-1 VMSA页表模型
这个对应关系,VMSA设计了一套数据结构:TranslationTable(页表)、Page(页描述符)、Block(块描述)。这些数据结构的每一项的格式,都是ARM规定好,OS的内存管理模块在内存中创建页表的时候,就要按照这个格式填充数据,方便MMU进行遍历和访问。这里我们举一个页描述符的格式供大家参考,如图1-2所示。
图1-2 VMSA页描述符
有了这些描述符之后,OS软件就可以通过级联的方式将它们关联到一起。这里面就有一个问题了,怎么关联,是串联还是并联还是串并联。ARM采用的是多级页表级联的方式组织页表架构,如图1-3所示。
图1-3 VMSA Stage-1多级页表架构
采用这种多级页表架构的重要原因是现代处理器的地址空间实在是太大了。如果采用单级页表,在64bit空间下,光是存储页表的要消耗的内存空间就非常恐怖,这个我们前面算了一笔细账,大家可以自行阅读了解相关的背景。采多级页表架构后,这种情况就得到了很大的改善,辅之以OS软件管理模块的帮助,可以大大的节约管理数据所消耗的内存。当CPU拿到虚拟地址后,在MMU的帮助下可以快速的遍历多级页表从而找到物理地址,进而发起访问物理地址空间的操作。当然,现代处理器的肯定要越快越好,那么Cache机制和TLBs的机制的运用会大大提高地址翻译的效率。
对MMU的页表相关回顾就到这里,相信大家已经有了一定的感觉了,下面我们进入SMMU页表的世界。
1.2 SMMU的使用场景
前面的章节,我们简要地回顾了MMU页表的多级架构模型。如果说MMU使用的页表是架设在PE-Cores和被访问内存的之间的一座桥梁,那么SMMU使用的页表就是架设在设备和被访问内存之间的一座桥梁,如图1-4所示。
图1-4 DMA使用场景
我们先来看一张系统拓扑来理顺一下SMMU工作的场景,看看我们会有哪些发现:
(1) 我们这个例子是播放一个音频文件的场景。
(2) CPU中执行音频相关的应用程序播放一个音频文件,首先应用程序要在内存中加载相关的音频数据。这个过程也是创建页表,记录分配物理内存的一个过程。
(3)如果是虚拟话的GuestOS中的应用程序的话,那么还需要通过异常处理机制,跳跃到Hypervisor中在Stage-2阶段的异常处理机制分配到真实的物理内存,这也就是为什么图1-4下面画了两个Stage的页表布局。
(4)当然,如果不是虚拟化架构下的VM中执行的应用程序,直接在Stage-1阶段就可以分配到物理内存,并装载Audio数据。
(5)如果音频数据是压缩格式的话,那么就需要根据Audio子系统的配置策略采用软解码(CPU)或者是硬件加速解码(ADSP)。如果是不需要解码的PCM数据的话,那么直接就是可以播放的状态了。
(6)万事具备了,开始干活吧。应用层通过发出指令让Audio子系统的驱动开始搬运数据了,为啥要搬运数据呢?现在的数据还是数字信号,离散的状态,得把这些数据搬运到一个DA转化的控制器变成连续输出的模拟信号,然后让模拟信号在经过功放(模拟放大器)和喇叭才能让人们的耳朵听到。
(7)驱动程序可是跑在CPU上的,这个搬运可是涉及到IO操作的,内部总线还好说,外部的总线那个速度可不好保证。为了不让当前的驱动程序的执行效率,通常这种情况的做法是,搬运的体力活是外包给力工干的。这个力工就是DMA控制器,驱动只需要告诉它,要搬运的东西在哪儿,有多少东西要搬就行了。
(8)DMA控制器拿到了地址要干活了,可是这个地址学问就大了。驱动程序是工作在VMSA体系下的,这里面的地址包括VA、IPA、PA,拿到PA还能好一点,拿到了VA可咋整?DMA在江湖中可没有CPU这个大哥地位,配一个专属带刀护卫MMU。它只能去求助别人,放眼望去,求谁呢?求CPU,CPU立马让他滚蛋。只能求总线架构了,在构造soc的时候就得考虑这种情况。于是SMMU就诞生了,系统MMU就是帮助类似DMA这种弱势群体的,帮助他们做地址翻译的。
(9)SMMU拿到DMA送过来的地址后,经过一个翻译的过程,给DMA一个可用的物理地址PA(总线地址),这个时候DMA就开始干活了。
上面的SMMU的一个工作场景墨迹完了,我们来思考几个问题:
(1) SMMU作为系统的MMU是为整个系统上的设备服务的,那么找他办事肯定得记录一下吧,也就是所有连接在SMMU上的设备是怎么管理的。
(2) QQ音乐可以播放视频,驱动得靠着DMA搬运音频数据。导航也要提示在路口转弯,也要播放视频,也得驱动去通知DMA搬运音频数据。这两个应用程序的音频数据在内存内部可是隔离的,也就是说DMA同样是搬运数据,它要SMMU翻译的地址可不是一样的,这种情况下SMMU又是怎么管理的。
(3) 被访问的数据在内存中是CPU和DMA共享的,CPU已经通过驱动程序按照VMSA的体系的要求组织过一次页表的结构了,那么SMMU肯定是没有必要再搞一套,那也太浪费了。通过图1-3可以发现,CPU可以启动的通过系统寄存器TTBR_ELx就可以轻松找到页表在内存中的位置,让MMU轻松的遍历下去。那么SMMU又是如何找到图1-4中页表的呢?
下面的章节,我们就通过展开SMMU的页表架构的设计,找到这些问题的答案,并通过这些答案勾勒出SMMU的页表架构。
1.3 设备管理
1.3.1 StreamID
通过前面文章的分析,我们了解到SMMU上会连接多个设备。SMMU的驱动程序首先就要在SMMU初始化的时候对这些设备做区分管理,先看一下手册中的描述:
The StreamID is how the SMMU distinguishes different client devices. At its simplest, one device can have one StreamID. However, a device might be able to generate multiple StreamIDs, with different translations applied based on the StreamID. For example, for a DMA engine that supports multiple channels, different StreamIDs might be applied to different channels.
Because the StreamIDs associated with a physical device are system-specific, the system softwarepresents StreamIDs to the OS as part of firmware descriptions for each device. Both the ACPI table and devicetree can present StreamIDs to the OS for each device.
简单归纳一下:
(1) ARM体系下通过StreamID区分系统中使用SMMU的设备。
(2) 这些设备的StreamID是需要在系统发版前就预先配置好的,而不是在运行时动态生成。
1.3.2 SubStreamID
前面的例子中提到CPU这边不同的进程使用的是不同空间的页表结构索引的内存和DMA这个设备共享的。一个进程对应一个进程的地址空间的数据,如果要对他们做区分的话,就需要引入新的数据结构。手册中举了一个虚拟化架构的例子更能说明这个问题:
Consider a VM running multiple applications. You might want to have one DMA channel used by one application, and another DMA channel used by a different application. These applications are within the same VM, so they have the same stage 2 translation. However they have different stage 1 translation. SMMUv3 enables each stream to have multiple substreams. All the substreams share the same stage 2 translation, but each substream has it own stage 1 translation. For example, if a DMA engine with a fixed StreamID has multiple channels, different SubstreamIDs might be applied to different channels.
为了应对区分不同Stage 1阶段的内存空间,ARM引入了SubstreamIDs这个概念,如图1-5所示。值得注意的是,这个SubStreamID不是SMMU架构中必须存在的Feature,具体要结合使用SMMU的设备的能力以及驱动的架构和实现方式。
图1-5 SubStreamID使用场景
1.3.3 Stream table
StreamID可以用来区分连接到SMMU上的设备,那么这些设备又是如何被SMMU管理的呢?
The SMMU uses a set of data structures in memory to locate translation data. See Translation process overview. SMMU_(*_)STRTAB_BASE hold the base address of the initial structure, the Stream table. A Stream Table Entry (STE) contains stage 2 translation table base pointers. It also locates stage 1 configuration structures, which contain translation table base pointers.
The StreamID of an incoming transaction, qualified by SEC_SID , determines which Stream table is used for lookup, and locates the STE.
通过手册的描述,简单归纳如下:
(1) SMMU的驱动程序通过初始化一段连续的内存将它连接的所有设备组织到Stream Table中进行管理。
(2) 每个设备的相关信息通过一个Stream Table Entry(STE)进行进行保存,STE中保存的最终的信息就是指向两级地址翻译所要使用的页表的基地址的指针。
(3) 运行时,SMMU通过StreamID进行索引。
StreamTable组织STE的形式,分为两种。
方式一:线性组织
这种方式结构简单,如图1-6所示,寄存器中的地址架构StreamID的便宜就行了。
图1-6 STE线性组织方式
方式二:两级组织
这种方式就是稍微复杂一点,将StreamID拆分成两级然后在索引到相应的STE,如图1-7所示。
图1-7 2级STE组织方式
对于见识过多级页表架构的我们来说,这个就非常简单,很好理解了,这里不展开讨论了。2级管理除了可以解除单级连续物理内存的限制之外,其他优势参考手册的描述,这里不展开讨论。
The 2-level Stream table is useful to software where the StreamID width is large, and either it cannot easily allocate that much contiguous memory or the distribution of StreamIDs is relatively sparse. For example, for a use-case like PCIe, the maximum of 256 buses are supported, and the RequesterID or StreamID space is at least 16-bits.
到这里我们大致清楚了,SMMU是如何区分并管理设备的。最核心的一点就是有了STE之后,就可以通过STE内部的指针,继续索引内存中的页表了(Stage-1 and Stage-2)。
1.4 上下文管理
1.4.1 Stage-1 上下文
设备的管理搞定了,那么接下来就要考虑CPU不同上下文(App、Kernel、Hypervisor...)发送过来的设备访问内存请求时如何管理地址翻译工作的,先看一下手册中的描述:
A CD(Context Descriptor) stores all the settings related to stage 1 translation. Each CD is 64-bytes. The pointer to a CD comes from an STE, not from a register. A CD is only required when stage 1 translation is performed. For a stream with only stage 2 translation, or bypass, only the STE is needed.
The CD associates the StreamID with stage 1 translation table base pointers, to translate a VA into an IPA, for each stage 2 configuration. If substreams are in use, multiple CDs indicate multiple stage 1 translations, one for each substream. Transactions with a SubstreamID are terminated when stage 1 translation is not enabled.
简单归纳如下:
(1) SMMU架构中引入了一个新的数据结构CD负责管理来自不同CPU上下文发送过来的设备访问内存请求的地址翻译请求工作。
(2) CD是一个特定格式的数据结构,它包含了指向Stage 1地址翻译表的基地址指针。
(3) CD还包含了内存属性、翻译控制信息、异常控制信息以及Page Table Walk(PTW)的起始地址。
根据SMMU的实现方式,CD的实现也有两种实现方式:
方式一:Single CD
这种方式结构简单,如图1-8所示:
图1-8 单级CD组织结构
Stage-1页表可以和图1-4的Stage-1页表相对应,上下文切换的时候需要驱动深度参与更新TTB0和TTB1。如果系统架构支持SubStreamID的话,单级CD结构的组织形式会有一些变化,索引不同上下文CD的方式也会有变化,如图1-9所示。
图1-9 单级CD(支持SubStreams)组织结构
方式二:Single CD
两级CD组织结构,如图1-10所示。
图1-10 2级CD组织结构
与单级CD结构相比,明显的优势还是可以避免一次申请不到足够的连续内存,其他的方面不展开讨论了,感兴趣的小伙伴可以自行翻阅手册。
1.4.2 Stage-2 上下文
前面的文章已经告诉我们了在虚拟化架构下,CPU使用的地址要经历MMU两级地址翻译才能够找到物理地址(PA)。在EL2层面每个VM都有一个专属自己的地址空间,也有自己的一套页表架构级联起来索引内存,类似图1-3那种,这是基地址寄存器变成了VTTBR_EL2。SMMU架构下的CD可以链接到Stage-1阶段的页表的基地址上,那么Stage-2阶段的页表基地址怎么索引呢,如图1-11所示。
图1-11 STE索引Stage-2上下文页表
Stage-2的上下文中的页表索引就比较容易理解了,STE中通过VMID标识虚拟机VM,通过S2TTB直接指向了Stage-2页表的基地址。SMMU
将Stage-1阶段找到IPA(图1-4中的Outpud Address)作为输入直接遍历Stage-2阶段的页表就可以了。
1.5 SMMU页表架构
到这里SMMU的页表架构似乎就呼之欲出了,因为前面的章节我们已经做了大量的准备工作,汇总一下:
(1) SMMU通过STE管理设备;
(2) 通过StreamID所以STE;
(3) STE通过索引CD,然后通过CD索引Stage-1阶段的页表;
(4) STE直接索引Stage-2页表。
经过上面的过程后,我们就可以勾勒出,SMMU在翻译地址时所要用的页表架构了,如图1-12所示:
图1-12 SMMU多级页表架构
结合MMU的多级页表架构,我们归纳如下:
(1) Stage-1和Stage-2的Translation Tables是与MMU共享的。
(2) MMU需要通过CPU内部的寄存器TTBR和VTTBR才能索引到不同上下文的页表。
(3) SMMUy要先通过内部的寄存器STRTAB_BASE索引到STE的所在的页表,然后再通过STE中的字段所以到和CPU共享的Stage-1和Stage-2的页表。
结语
本文我们首先简要回顾了MMU的页表架构的基础知识,然后通过一个SMMU使用场景的例子引出了SMMU在工作过程中需要的必要的管理工作,这些工作包括设备的管理和上下文管理。最后将前面的内容串联起来后,揭开了SMMU多级页表架构的神秘面纱。本期的内容主要是为我们接下来介绍SMMU的地址翻译流程打下基础,要彻底理解还是建立在VMSA下MMU所使用的多级页表架构的基础上,希望大家花一些时间阅读一下前序文章。本文就到这里,谢谢大家,请保持关注、阅读、点赞、转发,再次感谢。
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>
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