ver 0.2
前言
任何人和组织的发展都需要空间,比如我们这个伟大的国家,幅员辽阔、大好河山决定了我们的发展潜力。这么大国土空间,不是随意无须的在发展,都是处于主动的规划(有形的手)或者自然的形成(无形的手)的功能划分,江浙的税、东北的粮和航母、山西的煤炭、新疆的棉花和石油…不同的地域、大家各司其职,而且在不同的历史条件下(状态下),作用也会有所调整,比如当年火热的大三线建设,这个和我们要讲解如何管理内存空间的理念是相通的,分类之后再分割、然后根据不同的状态再做细分调整。上一篇文章,我经过对Soc架构的分析,了解到如何通过接口、总线、内存控制器、PHY、DDR(SDRAM)构建"宏伟"的内存“帝国”。这里,我们将通过一片文章分析这广袤的内存空间要如何的做区域划分,以及划分的机制等课题。
正文
1. 地址空间
我们今天讨论的核心议题是内存空间的区域划分,这个也可以参考地理空间的划分,这里是东经,那里是北纬,两个数值确定下来,就可以确定地球上的一个点。同理内存空间也可以通过定量的形式精确的描述,那就是给内存空间从逻辑层面和物理层面进行编码(地址),逻辑地址可以简单的理解为虚拟地址,而物理层面的地址就是物理地址了,哈哈哈,好像是废话。按照前言中叙述的逻辑,ARM架构体系下同样会根据处理器的状态以及特殊的功能需求对内存做区域划分,其实也就是对内存的地址空间做划分。那么,我们需要了解在做这些划分的时候要考虑的基本要素有哪些,在这个基础上再对虚拟地址空间和物理地址空间做细分,呈现出地址空间的大致轮廓。
1.1 异常模型与安全状态
在ARM体系下,对于地址空间的区域划分,最重要的两个考虑因素就是异常模型与安全状态。我们在写虚拟化相关的文章的时候,曾有专门的文章分析了ARM的异常模型(时间充裕的同学可以去回顾一下),而ARM安全相关的内容也是另外一个重要领域,后期也会有专门的文章分析安全计算相关的课题。这里我们只做简要的介绍,帮大家扫除一些概念上的阅读障碍。
安全问题在任何层面、任何领域、任何时候都是核心议题,而且都是越安全越好,也是开发和使用其他的功能的基础。我们可以想到最基础的安全措施就是进程之间的资源隔离,A进程在没有经过B进程的允许是不能访问B进程的资源,那么这些资源包括内存资源也包括文件资源等,安全措施包括DAC策略,SeLinux策略等等,这些都是操作系统层面的安全设计。随着攻击者的手段升级,软件层面的安全策略也在不断的的升级,但是有的时候难免也有力不从心的时候,于是软件工程师和硬件的工程师主动打了个招呼:“我有一个根证书,放到哪里都不放心;我有一个指纹信息,放到哪里我都不放心;我有一个秘钥的校验计算过程,在我的系统上跑怎么也不放心,我担心我的代码都被篡改了…”。硬件工程师看着软件工程师充满焦虑的脸,来了一句:“既然软的不行,我们再给他们来点硬的”。于是在芯片设计和SOC架构在向前迭代的时候,安全相关的因素也逐渐被考虑了进来,如图1-1所示。
通过图1-1,我们可以看到要构建一个安全的Soc世界,核心的大脑肯定是需要改造的,至少要清楚啥时候是安全的(Secure),而那些需要被保护的资源要有硬件的机制保证安全的同时,有能力向系统提供接口和系统其他Master节点(主要是CPU)沟通安全状态和接收执行安全指令和数据交互。那么,有了硬件之后,软件的世界自然也就有了重构的基础,如图1-2所示。
如图1-2所示,在ARM的架构下,软件的世界被分成了:安全(Secure)和非安全(Non-Secure)两种状态,对应的空间分成了受信(Trusted)世界和正常(Normal)世界。普通安全等级的功能,如看个电影,听个音乐,打个游戏的场景,就放在正常的操作系统的非安全状态下执行就可以了,但是涉及到支付、访问证书、秘钥配对特殊资源和计算需要高安全等级的场景下,就需要通过特殊的机制放在受信的操作系统的安全环境下去执行。
上面我们细分了安全和非安全的执行环境,处理器是如何在两种执行环境下进行切换呢?那就要依靠ARM体系的异常机制了,注意异常的机制并不仅仅服务于这一个场景。异常机制可以从两个维度简单理解,第一个维度就是执行的上下文,如果不引入异常机制,我的系统工作模式将会是单调而机械的,当一个任务占用了CPU之后,它会一直执行,除非它自己主动退出,早期的计算机系统还真是这样工作的,但是对于这个花花世界,显然不能满足人们的需要的,在手机上通过社交软件和朋友聊天的同时,听一首怀旧的歌曲体验肯定会更好的,而这时候老板有紧急的事情找你,打个电话不过分吧。这些场景都要靠异常机制来满足,就是能够接受一个更高等级的系统模块的调度使用CPU资源,以及接受不可预期的其他任务中断。第二个维度就是特权等级了,这个社会的资源一样是有限的也是大家共享的,因此每个人都要让渡一部分权力出来形成公权力,搞一个实体出来让这个实体帮助大家管理这些资源,公平的让每一个人使用,并且阻止那些想多吃多占的人,并对响应违规的行为做出惩罚,那么映射到一个计算系统也是如此。在ARM体系下的计算机系统,引入了异常等级制度,如图1-3所示。
通过图1-3可以看到,异常等级越高,响应的特权等级越高,可以访问和控制的资源也就越多。那么异常模型是如何体现出自己的特权地位执行权限的抓手又是什么呢?就是通过Soc的内存子系统的内存管理机制(包括MMU),大概的逻辑就是,soc节点上所有资源都会被抽象成内存资源和CPU进行交互,那么这些资源灾备抽象的过程中都会被赋予响应的属性,最简单的比如读写属性、共享属性、Cache属性等,CPU通过地址访问这些资源的时候,MMU就会检查这些属性和当前的异常等级和安全状态做一下匹配,合法就继续,非法就抛出异常转向规定好的上下文进行批评教育。当然,除了SOC上资源外(CPU外资源),CPU内部的资源也是进行管控的,而CPU内部的大部分资源对软件都是透明不可见的,唯有寄存器(特别是系统寄存器)和运行指令(敏感指令),那么CPU在执行相关指令和访问相关的寄存器资源的时候也要做权限检查。
鲁迅先生说过:这个世界唯一没有变化的规律,就是这个世界时钟处于变化之中。前面的介绍我们了解到,高等级的软件模块拥有了绝对的权力,他们控制了资源的分配,还拥有了窥探资源被使用过程的途径,也就是对于低等级的软件模块没有了丝毫的隐私,如果高等级的软件被攻破了或者被别有用心的家伙埋雷了,那么后果也是不可想象的。等到ARMv9-A上,ARM的设计理念中对高等级的软件不再100%信任,从而引入了Realms,如手册的描述。
The Arm Confidential Compute Architecture (Arm CCA) enables the construction of protected execution environments called Realms. Realms allow lower-privileged software, such as application or a Virtual Machine to protect its content and execution from attacks by higher-privileged software, such as an OS or a hypervisor.
Higher-privileged software retains the responsibility for allocating and managing the resources that are utilized by a Realm, but cannot access its contents, nor affect its execution flow.
同样Realms也是软硬一体的解决方案,先看硬的一面,如图1-4典型的基于ARMv9-A的系统架构。
通过图ARMv9a的系统架构,可以看到如果要支持RME(Realm Management Extension) Feature,芯片厂商还要在设计芯片的时候加上额外的逻辑电路,这肯定会增加芯片的设计复杂度和制作复杂度,当然也会推升芯片的经济成本,所以笔者接触的最新一代的量产芯片虽然很多都是基于ARMv9a,但是都没有支持RME。RME硬的一面我们看完了,下面来看看RME软的一面,如图1-5所示。
ARMv9的RME机制对ARMv8的安全框架做了扩展,安全状态从两种变成了4种:Secure state、Non-secure state、 Realm state、Root state。各个安全状态与Exception Level(异常)等级的映射关系如图1-5所示。下面我们对四种状态做一下解释:
(1) Secure state 和 Non-Secure state 与ARMv8兼容。
(2) Realm state 可以在realms环境下执行,隔离了Hypervisor和Secure 状态下 软件模块。
(3) Root state,ARMv9将EL3等级整体抽象为Root 状态。
同样安全状态的切换依靠的是异常机制,这一点没有改变如图1-6所示。
为了讲清楚地址空间的相关内容,这里我们对重要的预备知识做了简要的介绍,如果有感性的课题,大家可以自行阅读相关的手册,这里我们不展开讨论了,安全相关的内容涉及的软硬件知识、还涉及到安全科学的背景知识,是一个重要的领域,搞好了可以变成独角兽公司,大口吃肉、大碗喝酒,大家努力,哈哈哈哈,这里我们只关注和内存相关的背景知识就可以了。
1.2 虚拟地址(Virtual address)与物理地址(Physical address)
我们讨论地址空间的基础就是虚拟地址和物理地址,如图1-7所示,我们后面的讨论也会仅仅围绕这两个维度去展开。
前面我们讨论的时候说过,对于内存子系统,我们要搞清楚的核心议题就是地址翻译,就是怎么将虚拟地址映射成物理地址,从而实现软件和硬件的结合。这里可以看到,物理地址空间划分的最顶层单位是安全状态,不同的安全状态下,物理内存的空间是不同的,后面我们逐一讨论。而虚拟地址空间就有意思了,或者说让人头大了,结合具体的上下文(异常等级、翻译机制、虚拟化环境的配置等)可以组合出10几种情况,如图1-8所示的ARMv8体系下,不考虑Secure状态下的EL0、EL1等级的情况下就已经很复杂了,后面我们会挑一些典型的常用的场景进行讲解,中间还会引出新的概念,以期抛砖引玉。
1.2.1 物理地址空间(PAS)
多级物理地址空间
手册上在讲解地址空间空间相关的内容都是先讲的虚拟内存的空间,而笔者认为:水是有源的,树是有根的,虚拟内存之所以复杂是有原因的。我们前面排除了异常等级和安全状态的障碍,现在吧物理内存先讲明白,再讲虚拟内存空间是比较妥当的,如图1-9所示。
由于ARMv9向前兼容ARMv8,所以这里我们直接以ARMv9进行讲解,ARM的真实的内存地址空间由于安全机制的需要被进一步划分为4个区域:
• Non-secure PAS0
• Secure PAS
• Realm PAS (Armv9-A only)
• Root PAS (Armv9-A only)
图1-9大家可能会有一点奇怪,为什么物理地址不是唯一的呢?显然按照上面的华发,物理地址是会有重叠的。物理地址肯定是唯一的,DDR-PHY访问的LPDDR的时候肯定使用的HPAS,这里的不同安全状态下的物理地址是怎么用的,这里给大家看一下TLB的格式一下子就明白了,如图1-10所示。
通过图1-10可以看出,和虚拟地址映射的物理地址是有前缀的表明自己所在的物理内存空间。为啥要这样设计,这里面其实有一个和硬件芯片设计的相关的课题,那就是是否要讲不同安全状态下的物理内存做物理层面的隔离还涉及到SOC的一致性总线架构设计,这个课题我们这里不展开讨论了,让芯片厂商去头疼吧。
物理地址空间尺寸(PAS Size)
搞清楚了物理空间的划分的架构之后,我们需要搞清楚物理空间的区域尺寸了,对于物理空间而言,其实就是到底能支持多大的物理内存空间。首先需要明确的一点,虽然AMVv8后期开始支持64位的地址空间,但是物理内存空间缺不能支持64位,而是和具体的实现有关,如图1-11所示。
这里我们直接看下手册中的表述,不做过多解释,主要还是依赖芯片厂商的设计。
The size of a physical address is IMPLEMENTATION DEFINED , up to a maximum of 52 bits. The ID_AA64MMFR0_EL1 register reports the size that is implemented by the processor.
• For Arm Cortex-A processors, this will usually be 40 bits or 44 bits.
• In Armv8.0-A, the maximum size for a physical address is 48 bits. This was extended to 52 bits in Armv8.2-A.
• If the implemented PA size is greater than 48 bits, then FEAT_LPA is required.
• A PA size greater than 52 bits is only supported by the VMSAv9-128 translation system.
• If the VMSAv8-64 translation system is used in an implementation that supports the VMSAv9-128 translation system, then PA bits [55:52] are set to 0b0000 .
1.2.2 虚拟地址空间(VAS)
Translation Regimes
手册中有这样的一段描述:
Each of these virtual address spaces is independent, and has its own settings and tables. We often call these settings and tables ‘translation regimes’.
A translation regime determines how a VA is mapped to a PA. The translation regime is affected by the current Security state, the current Exception level, the enabled Exception levels, HCR_EL2 settings, and implemented features.
The architecture defines all of the following translation regimes:
• Non-secure EL1&0 translation regime.
• Secure EL1&0 translation regime.
• Realm EL1&0 translation regime.
• Non-secure EL2&0 translation regime.
• Secure EL2&0 translation regime.
• Realm EL2&0 translation regime.
• Non-secure EL2 translation regime.
• Secure EL2 translation regime.
• Realm EL2 translation regime.
• EL3 translation regime.
虚拟地址的空间的划分是相互独立的,并且都伴随特定设置和属于自身空间的页表,ARM中把这些空间的划分以及相关的设置等元素统称为翻译机制translation regimes。那么我们确定了ARM中有多少种翻译机制也就确定了ARM中有多少内存空间了。显然,虚拟地址空间中总共有10种虚拟地址空间,这里我们以安全状态为依据分类进行讲解。
(1)VAS(Non-Secure EL1&0 、Non-Secure EL2 、 EL3)
先介绍第一大类,如图1-12所示,这是我们经常遇到的系统配置,ARMv8和ARMv9通用的架构。典型配置可以是,EL1/0可以配置为Linux系统(Kernel+Userspace),EL2配置为Hypervisor如KVM,EL3一般为固定芯片厂商固定安全Firmware。
(2)VAS(Realm EL1&0 、Realm EL2 、 Realm EL2&0)
我们再来介绍第二大类,如图1-13所示,Realm状态下的地址空间可以有两种配置,以Linux+KVM的虚拟化架构为例,当我们没有打开ARM虚拟化扩展这个feature(HCR_EL2.E2H = 0)时,此时Realm EL1&0可以配置为Linux的kernel原始组件和Userspace空间进程,而Realm EL2可配置为Hypervisor(KVM)。当激活ARM的虚拟化扩展feature(HCR_EL2.E2H = 1),此时EL2&0可以配置为(Linux Kernel整体运行在EL2,Userspace运行在EL0),此时没有EL1运行状态,EL1相关的寄存器的访问等会被映射到EL2层,相关的中断也可以根据配置路由到EL2进行优先处理后,再注入相关的虚拟中断到EL1原来的中断向量例程中接力处理。(None Secure EL2&0的配置和Realm EL2&0原理想通,只是安装状态不一致。)
当然这里面还需要注意一点的是,Realm状态下的虚拟内存空间可以映射到Non-secure的物理地址空间。
(3)VAS(Secure EL1&0 、Secure EL2 、 Secure EL2&0)
在了解了Non-Secure和Realm状态下内存空间配置后,我们不需要做过多的解释,如图1-14所示。同样,Secure 虚拟地址空间同样可以映射到Non-secure的物理地址空间。这个后面我们还会有一个归纳总结。
虚拟地址空间尺寸(VAS Size)
同样虚拟地址空间的尺寸和物理地址空间的尺寸一样,也不是64位的,而且由于虚拟地址空间的尺寸要求彼此独立,在ARM系统下的典型空间尺寸配置如图1-15所示。
我们可以发现示例中高位地址是有区别的,要么全部为1,要么全部为0。上面这个配置可以覆盖所有的安全状态和异常等级,而这样设计一个直接的好处是方便MMU进行非法空间的检查,比如在EL0登记下要访问高位为1的虚拟地址,直接就可以判断为非法访问了。那么高位就多少位为配置为1或者是0呢?怎么做到的呢?答案是通过系统寄存器TCR_ELx,如图1-16所示。关于系统寄存器各个字段的配置,大家可以自行查阅手册,这里不再赘述。
1.2.3 中间物理地址空间(IPS)
上面的讲解中,大家可能早就发现了,有的地址空间需要进行两级翻译才能是VA被翻译成PA,中间要经过一个IPA( Intermediate Physical Space)进行中转,如图1-17,这是以为虚拟化的缘故。由于两级地址翻译属于虚拟化技术的核心技术点之一,后面会有专门的文章进行分析,这里只做一个简单介绍,不做详细分析。
中间物理地址空间同样涉及到size问题,同PAS的情况一样也是需要看实现时的设计,具体可以配置的范围如图1-18所示。
1.2.4 一些重要的规则
前面我们已经讲解完了虚拟地址空间、物理地址、中间物理地址空间(两级地址翻译),我们发现很多时候都需要配置以及遵守一些规则。这里我们做一个小小的总结,有两个重要的点需要关注。
映射规则
手册中的描述如下:
Which physical address space, or spaces, a virtual address can be mapped to depends on the current Security state of the processor. The following list shows the Security states with its corresponding virtual address mapping destinations:
• Non-secure state: virtual addresses can only map to Non-secure physical addresses.
• Secure state: virtual addresses can map to Secure or Non-secure physical addresses.
• Realm state: virtual addresses can map to Realm or Non-secure physical addresses
• Root state: virtual address can map to any physical address space.
Root Stat状态最不讲理,它可以映射到任何物理地址空间。而Non-Secure状态下的虚拟地址空间只能映射到自己对应的物理地址空间。常见的映射关系如图1-19所示。
配置规则
要实现上面的映射过程,是需要对系统的相关寄存器等进行配置并结合具体的运行等级配置才能够实现,这里列出典型的配置选项,如图1-20、1-21所示,详细信息,感兴趣的同学可以自行查阅手册,这里不再赘述。
结语
如果要想游戏玩的好,首先就要熟悉游戏的规则,而熟悉游戏规则的前提就是要搞清楚游戏的构成要素。我们想搞清楚ARM体系的内存管理,就要先搞清楚ARM内存相关的基本概念。本文用了很大的篇幅讲解了物理地址空间和虚拟地址空间,这两个内存管理的核心要素。并且介绍了相关的背景知识,异常等级、安全状态等。相信大家会有所收获,网上很多的大牛讲到这里,要么是机械照搬手册,要么是陷入到对寄存处配置介绍,而我们结合两者的优缺点,从更高的维度帮助大家梳理清楚,物理地址空间和虚拟地址空间。实话是说,内存管理这部分实在是复杂,需要花费一点时间仔细研究手册,这里算是抛砖引玉。下一篇文章,我们会介绍地址翻译的相关内容,请保持关注。
Reference
[00] <DEN0024A_v8_architecture_PG.pdf>
[01] <corelink_dmc520_technical_reference_manual_100000_0202_00_en.pdf>
[02] <corelink_dmc620_dynamic_memory_controller_technical_reference_manual_100568_0100_00_en.pdf>
[03] <DDI0331G_dmc340_r4p0_trm.pdf>
[04] <80-ARM-IP-cs0001_ARMv8基础篇-400系列控制器IP.pdf>
[05] <arm_cortex_a725_core_trm_107652_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_DDR内存介绍.pdf>
[12] <80-ARM-MM-HK0001_一文搞懂DDR-SDRAM工作原理.pdf>
[13] <80-ARM-MM-wx0016_ARMv8-aarch64的虚拟内存(mmu_tlb_cache)介绍.pdf>
[14] <DEN0129A_d-RME_sys_arch.pdf>
[15] <learn_the_architecture_realm_management_extension_den0126_0100_02_en.pdf>
[16] <learn_the_architecture_aarch64_exception_model_102412_0103_01_en.pdf>
[17] <learn_the_architecture_trustzone_for_aarch64_102418_0101_03_en.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,双数据率同步动态随机存储器
TBI - Top Byte Ignore
VMSA - AArch64 Virtual Memory System Architecture
LPAE - Large Physical Address Extension
MPMC - MultiPort Memory Controller
RME - Realm Management Extension
CCA - Confidential Compute Architecture