概述
内存管理单元(MMU)的一个重要功能是使系统能够运行多个任务,作为独立的程序在它们自己的私有虚拟内存空间中运行。他们不需要了解系统的物理内存映射,也就是硬件实际使用的地址,或者可能同时执行的其他程序。
您可以为每个程序使用相同的虚拟内存地址空间。您还可以使用连续的虚拟内存映射,即使物理内存是碎片化的。这个虚拟地址空间与系统中内存的实际物理映射是分开的。您可以编写、编译和链接应用程序以在虚拟内存空间中运行。
第12-2页的图12-2显示了一个示例系统,说明了内存的虚拟和物理视图。单个系统中的不同处理器和设备可能具有不同的虚拟和物理地址映射。操作系统编程MMU在这两种内存视图之间进行转换。
为此,虚拟内存系统中的硬件必须提供地址转换,即将处理器发出的虚拟地址转换为主存中的物理地址。虚拟地址是指将代码放入内存时,您以及编译器和链接器使用的地址。物理地址是实际硬件系统使用的地址。
MMU使用虚拟地址的最高有效位来索引转换表中的条目,并确定正在访问哪个块。MMU将代码和数据的虚拟地址转换为实际系统中的物理地址。翻译在硬件中自动执行,对应用程序透明。除了地址转换,MMU还控制每个内存区域的内存访问权限、内存顺序和缓存策略。
MMU使任务或应用程序的编写方式要求它们不知道系统的物理内存映射,也不知道可能同时运行的其他程序。这允许您为每个程序使用相同的虚拟内存地址空间。它还允许您使用连续的虚拟内存映射,即使物理内存是碎片化的。这个虚拟地址空间与系统中内存的实际物理映射是分开的。应用程序被编写、编译并链接到虚拟内存空间中运行。
1、The Translation Lookaside Buffer
转换查找缓冲区(Translation Lookaside Buffer,TLB)是MMU中最近访问的转换页面的缓存。对于处理器执行的每次内存访问,MMU都会检查转换是否缓存在TLB中。如果请求的地址转换在TLB中导致命中,则地址转换立即可用。
每个TLB条目通常不仅包含物理地址和虚拟地址,还包含诸如内存类型、缓存策略、访问权限、地址空间ID(ASID)和虚拟机ID(VMID)等属性。如果TLB不包含处理器发出的虚拟地址的有效转换(称为TLB未命中),则执行外部转换表漫游或查找。MMU内的专用硬件使其能够读取内存中的翻译表。然后,如果转换表遍历未导致页面错误,则可以将新加载的转换表缓存在TLB中,以便可能的重用。TLB的具体结构在不同的ARM处理器中有所不同。
如果操作系统修改可能已缓存在TLB中的转换条目,则操作系统有责任使这些过时的TLB条目无效。
当执行A64代码时,TLBI是一个TLB INVALIDE指令:
TLBI < type >< level >{IS} {, < Xt >}
下表给出了类型字段的一些更常见的选择。完整列表见第12-5页表12-1。
每个异常级别(即EL3、EL2或EL1)都有自己的虚拟地址空间,该操作适用于这些地址空间。IS字段指定这仅适用于内部可共享条目。
< level >字段只指定操作应应用于的异常级别虚拟地址空间(可以是3、2或1)。
IS字段指定这仅适用于内部可共享条目。
下面的代码示例显示了写入由内部共享内存支持的转换表的序列:
例如,要更改单个条目,请使用以下说明:
TLBI VAE1, X0
使与寄存器X0中指定的地址相关的条目无效。
TLB可以保存一定数量的条目。通过减少转换表遍历而导致的外部内存访问次数从而获得较高的TLB命中率,实现最佳性能。ARMv8-A体系结构提供了一种称为连续块条目的功能,以有效利用TLB空间。转换表块条目每个都包含一个连续位。设置后,该位向TLB发出信号,表示它可以缓存覆盖多个块的转换表的单个条目。查找可以将任何位置索引到连续块覆盖的地址范围中。因此,TLB可以为定义的地址范围缓存一个条目,从而可以在TLB中存储比其他方式更大范围的虚拟地址。
要使用连续位,连续块必须是相邻的,也就是说,它们必须对应于虚拟地址的连续范围。它们必须从对齐的边界开始,具有一致的属性,并指向同一转换级别的连续输出地址范围。所需的对齐方式是,4KB颗粒的VA[20:16]或64KB颗粒的VA[28:21]对于所有地址都是相同的。需要以下数量的连续块:
- 16×4KB的相邻块,提供一个64KB的入口和4KB的颗粒
- 32×32MB的相邻块为二级描述符提供1GB的条目,128×16KB的相邻块为三级描述符提供2MB的条目(当使用16KB颗粒时)
- 32×64Kb的相邻块提供了一个2MB的条目和一个64Kb的颗粒
若不满足这些条件,则会发生编程错误,这可能会导致TLB中止或查找损坏,可能示例包括:
- 一个或多个表项未设置连续位
- 其中一个条目的输出超出对齐范围
在ARMv8体系结构中,不正确的使用不允许转义EL0和EL1有效地址空间之外的权限检查,也不允许错误地提供对EL3空间的访问。
2、内核和应用程序虚拟地址空间的分离
操作系统通常有多个应用程序或任务同时运行。每一个任务都有自己独特的转换表集,内核在一个任务和另一个任务之间切换上下文的过程中从一个转换到另一个。然而,大部分内存系统仅由内核使用,并且具有固定的虚拟到物理地址映射,其中转换表条目很少更改。ARMv8体系结构提供了许多功能来有效地处理这一需求。
表基址在转换表基址寄存器(TTBR0_EL1)和(TTBR1_EL1)中指定。当VA的高位均为0时,选择TTBR0指向的翻译表。当VA的高位都设置为1时,选择TTBR1。可以启用VA标记以从检查中排除前八位。
从处理器获取指令或访问数据的虚拟地址为64位。但是,您必须在单个48位物理地址内存映射中映射上面定义的两个区域。
EL2和EL3有TTBR0,但没有TTBR1。这意味着:
- 如果EL2正在使用AArch64,则它只能使用0x0到0x0000FFFF_FFFFFFFF范围内的虚拟地址
- EL3同上
图12-4显示了如何将内核空间映射到最重要的内存区域,以及如何将与每个应用程序相关联的虚拟地址空间映射到最不重要的内存区域。然而,这两个都被映射到更小的物理地址空间。
转换控制寄存器TCR_EL1定义了被检查的最高有效位的确切数量。TCR_EL1包含大小字段T0SZ[5:0]和T1SZ[5:0]。字段中的整数给出了必须全部为0或全部为1的最高有效位数。这些字段有指定的最小值和最大值,它们随颗粒大小和起始表级别而变化。因此,必须始终使用这两个空格,并且所有系统中至少需要两个翻译表。没有操作系统的简单裸机系统仍然需要一个只包含故障条目的小上表。
中间物理地址大小(IPS)字段控制最大输出地址大小。如果转换指定的输出地址超出此范围,则访问会出错,000=物理地址的32位,101=48位。两位翻译颗粒(TG)TG1和TG0字段分别给出内核或用户空间的颗粒大小,00=4KB、01=16KB、11=64KB。
您可以配置用于第一次查找的转换表级别。完整的翻译过程可能需要三到四个级别的表格。您不需要实现所有级别。。实际上,第一级查找由颗粒大小和TCR_ELn决定。TxSZ字段。您可以分别为TTBR0_EL1和TTBR1_EL1配置它。
3、将虚拟地址转换为物理地址
当处理器为指令获取或数据访问发出64位虚拟地址时,MMU硬件将虚拟地址转换为相应的物理地址。对于虚拟地址,高16位[63:47]必须全部为0或1,否则该地址会触发故障。
然后,最低有效位用于给出所选部分内的偏移量,以便MMU将来自块表条目的物理地址位与来自原始地址的最低有效位组合,以生成最终地址。
该体系结构还支持标记地址。这是地址的最高有效八位被忽略的地方(被视为不属于地址的一部分)。这意味着这些位可以用于其他用途,例如记录有关指针的信息。
在一个只涉及一级查找的简单地址转换中。假设我们使用的是一个64KB的颗粒和一个42位的虚拟地址。MMU将虚拟地址转换为以下内容:
- 如果VA[63:42]=1,则TTBR1用于第一页表的基址。当VA[63:42]=0时,TTBR0用于第一页表的基址。
- 页表包含8192个64位页表条目,并使用VA[41:29]编制索引。MMU从表中读取相关的2级页面表条目。
- MMU检查页表条目的有效性,以及是否允许请求的内存访问。假设它是有效的,内存访问是允许的。
- 在第12-9页的图12-7中,页面表条目指的是512MB页面(它是一个块描述符)。
- 位[47:29]取自此页表条目,形成物理地址的位[47:29]。
- 因为我们有一个512MB的页面,VA的位[28:0]被用来形成PA[28:0]。见第12-15页翻译表中颗粒大小的影响。
- 返回完整的PA[47:0]以及来自页面表条目的附加信息。
实际上,这样一个简单的翻译过程严重限制了地址空间的划分。第一级表条目也可以指向第二级页面表,而不是只使用第一级翻译表。
通过这种方式,操作系统可以进一步将一大部分虚拟内存划分为更小的页面。对于第二级表,第一级描述符包含第二级页表的物理基址。与处理器请求的虚拟地址相对应的物理地址位于第二级描述符中。
图12-8显示了对于正常的64KB页面从阶段1的level 2开始的64位颗粒的转换示例。
每个二级表都与一个或多个一级条目相关联。可以有多个一级描述符指向同一个二级表,这意味着可以将多个虚拟位置别名到同一物理地址。
第12-10页的图12-8描述了有两个查找级别的情况。同样,这假设一个64KB的颗粒和42位的虚拟地址空间。
- 如果VA[63:42]=1,则TTBR1用于第一页表的基址。当VA[63:42]=0时,TTBR0用于第一页表的基址。
- 页表包含8192个64位页表条目,并通过VA[41:29]索引。MMU从表中读取相关的2级页面表条目。
- MMU检查2级页表条目的有效性,以及是否允许请求的内存访问。假设它是有效的,内存访问是允许的。
- 在第12-10页的图12-8中,2级页面表格条目指的是3级页面表格的地址(它是一个表格描述符)。
- 位[47:16]取自2级页表条目,构成3级页表的基址。
- VA的位[28:16]用于索引3级页面表项。MMU从表中读取相关的3级页面表条目。
- MMU检查3级页表条目的有效性,以及是否允许请求的内存访问。假设它是有效的,内存访问是允许的。
- 在第12-10页的图12-8中,3级页面表条目指的是一个64KB的页面(它是一个页面描述符)。
- 位[47:16]取自3级页面表格条目,用于形成PA[47:16]。
- 因为我们有一个64KB的页面,VA[15:0]被用来形成PA[15:0]。
- 返回完整的PA[47:0]以及来自页面表条目的附加信息。
3.1 安全和非安全地址
从理论上讲,安全和非安全的物理地址空间是相互独立的,并且是并行存在的。一个系统可以设计成两个完全独立的存储系统。然而,大多数实际系统将安全和非安全视为访问控制的属性。正常(不安全)世界只能访问不安全的物理地址空间。安全世界可以访问两个物理地址空间。这也是通过翻译表控制的。
这也有缓存一致性的影响。例如,因为安全0x8000和非安全0x8000在技术上是不同的物理地址,所以它们可能同时在缓存中。
在安全和非安全内存位于不同位置的系统中,不会有问题。他们更有可能在同一地点。理想情况下,内存系统会阻止对非安全内存的安全访问和对安全内存的非安全访问。实际上,大多数人只会阻止对安全内存的非安全访问。同样,这意味着您可能会在缓存中使用相同的物理内存两次,安全和非安全。这总是一个编程错误。为了避免这种情况,安全世界必须始终使用对非安全内存的非安全访问。
3.2 配置和启用MMU
对控制MMU的系统寄存器的写入是上下文切换事件,它们之间没有顺序要求。在发生上下文同步事件之前,这些事件的结果不能保证被看到
这是除了平面映射的要求之外的,平面映射是确保我们知道在写入SCTLR_EL1.M之后直接执行哪个指令。如果我们看到写入的结果,则是VA+4处使用新翻译机制的指令。如果我们看不到结果,它仍然是VA+4处的指令,但其中VA=PA。ISB在这里没有帮助,因为我们不能保证它是执行的下一条指令,除非我们使用平面映射。
3.3 禁用内存管理单元时的操作
当阶段1 MMU被禁用时,对于非安全EL0和EL1,当HCR_EL2.DC位设置为启用数据缓存时,默认内存类型为正常不可共享、内部回写读写分配、外部回写读写分配。
4、ARMv8-A 转换表
ARMv8-A体系结构支持三种不同的翻译表格式:
- ARMv8-AArch64长描述符格式
- ARMv7——一种长描述符格式,例如ARMv7-A体系结构的大物理地址扩展(LPAE),可以在ARM Cortex-A15处理器中找到
- ARMv7短描述符格式
在AARC32状态下,可以使用现有的ARMv7-A长描述符和短描述符格式来运行现有的来宾操作系统和现有的应用程序代码,而无需修改。ARMv7-A短描述符只能用于EL0和EL1阶段1的翻译。因此,虚拟机监控程序或安全监控代码无法使用它们。
始终在AARC64执行状态下使用ARMv8-A长描述符格式。这与ARMv7非常相似,ARMv7是一种具有大型物理地址扩展的长描述符格式。它使用相同的64位长描述符格式,但有一些更改。它引入了一个新的0级表索引,它使用与1级表相同的描述符格式。增加了对最多48位输入和输出地址的支持。输入虚拟地址现在来自64位寄存器。然而,由于体系结构不支持完整的64位寻址,地址的63:48位必须全部相同,即所有0或所有1,或者高八位可用于VA标记。
AArch64支持三种不同的翻译颗粒。它们在翻译表的最低级别定义块大小,并控制正在使用的翻译表的大小。更大的粒度可以减少所需的页表级别,这在使用虚拟机监控程序提供虚拟化的系统中可能成为一个重要的考虑因素。
支持的粒度为4KB、16KB和64KB,这三种粒度中支持哪一种由实现定义。创建页表的代码能够读取系统寄存器ID_AA64MMFR0_EL1,以找出支持的大小。Cortex-A53处理器支持所有三种尺寸,但某些处理器的早期版本并非如此,例如Cortex-A57,它不支持16K颗粒尺寸。可为翻译控制寄存器(TCR_EL1)内的每个翻译表配置大小。
4.1 AArch64描述符格式
可以在表的所有级别(从级别0到级别3)中使用描述符格式。0级描述符只能输出1级表的地址。3级描述符不能指向另一个表,只能输出块地址。因此,第3级的表格格式略有不同。
第12-15页的图12-10显示,表格描述符类型由条目的1:0位标识,可以指:
- 下一级表的地址,在这种情况下,内存可以进一步细分为更小的块
- 可变大小内存块的地址
- 表条目,可标记为错误或无效
4.2 颗粒大小对翻译表的影响
三种不同的颗粒大小可能会影响所需翻译表的数量和大小。
在所有情况下,如果VA输入范围限制为42位,则可以省略表的第一级。根据可能的VA范围的大小,可能会有更少的级别。例如,对于4KB颗粒,如果TTBCR设置为低地址仅跨1GB,则不需要级别0和1,转换从级别2开始,对于4KB页面,转换到级别3。
4KB
当使用4kB粒度时,硬件可以使用4级查找过程。48位地址每级翻译9个地址位,即每个512个条目,最后12位选择直接来自原始地址的4kB内的一个字节。
虚拟地址索引的47:39位放入512条目L0表。每个表项都跨越512 GB的范围,并指向一个L1表。在512个条目的L1表中,位38:30用作索引,以选择一个条目,每个条目指向1GB块或L2表。位29:21索引到512个条目的L2表中,每个条目指向2MB块或下一个表级。在最后一级,位20:12索引到一个512条目的L2表中,每个条目指向一个4kB的块。
16KB
当使用16kB颗粒大小时,硬件可以使用4级查找过程。48位地址每级翻译11个地址位,即每个2048个条目,最后14位选择直接来自原始地址的4kB内的一个字节。0级表只包含两个条目。虚拟地址的第47位从两项L0表中选择描述符。每个表项都跨越128 TB的范围,并指向一个L1表。在2048个条目的L1表中,位46:36用作索引来选择条目,每个条目指向L2表。位35:25索引到2048个条目的L2表中,每个条目指向一个32MB的块或下一个表级。在最后的翻译阶段,位24:14索引到2048个条目的L2表中,每个条目指向一个16kB的块。
64KB
当使用64kB颗粒大小时,硬件可以使用三级查找过程。级别1表仅包含64个条目。虚拟地址的47:42位从64个条目的L1表中选择一个描述符。每个表项都跨越4TB的范围,并指向一个L2表。在8192条目L2表中,位41:29用作索引,以选择条目,每个条目指向512 MB块或L2表。在最后的翻译阶段,位28:16索引到一个8192条目的L3表中,每个条目指向一个64kB的块。
4.3 缓存配置
MMU使用转换表和转换寄存器来控制哪些内存位置是可缓存的。MMU控制缓存策略、内存属性和访问权限,并提供虚拟到物理地址的转换。
软件配置由系统寄存器执行(其中一些在第4章ARMv8寄存器中列出)在一些设计中,外部存储器系统可能包含更多特定于实现的外部存储器缓存。
4.4 缓存策略
MMU转换表还定义了内存系统中每个块的缓存策略。定义为正常的内存区域可能被标记为可缓存或不可缓存。翻译表条目中的位[4:2]指内存属性间接寄存器(MAIR)中的八个内存属性编码之一。然后,“内存”属性编码指定访问该内存时要使用的缓存策略。
这些都是对处理器的提示,由实现定义是否在特定实现中支持所有缓存策略,以及哪些缓存数据被认为是一致的。内存区域可以根据其可共享性属性来定义。
5、翻译表配置
除了在TLB中存储单个翻译外,还可以将MMU配置为在可缓存内存中存储翻译表。这通常比总是从外部存储器读取数据更快地访问表。TCR_EL1有额外的字段来控制这一点。
其他字段指定TTBR0和TTBR1的翻译表的可缓存性和可共享性。相关字段称为SH0/1可共享性、IRGN0/1内部可缓存和ORGN0/1外部可缓存。表12-2显示了可缓存性的允许设置。
对应的内存共享表与翻译表关联。对于设备或强有序内存区域,该值将被忽略。
TCR_EL1中指定的属性必须与存储翻译表的虚拟内存区域中指定的属性相同。缓存翻译表是正常的默认行为。
5.1 虚拟地址标记
翻译控制寄存器TCR_ELn还有一个名为Top Byte Ignore(TBI)的附加字段,提供标记寻址支持。通用寄存器的宽度为64位,但地址的最高有效16位必须全部为0xFFFF或0x0000。任何使用不同位值的尝试都会触发故障。
启用标记寻址支持后,处理器将忽略高八位,即虚拟地址的[63:56]。它在内部将位[55]设置为64位格式的扩展地址格式。然后,可以使用虚拟地址的高八位来传递数据。由于寻址和翻译错误,这些位被忽略。TCR_EL1有单独的EL0和EL1启用位。ARM没有为标记寻址指定或授权特定的用例。
一个示例用例可能是支持面向对象编程语言。除了拥有指向对象的指针外,还可能需要保持一个引用计数,以跟踪引用对象的引用或指针或句柄的数量,例如,这样自动垃圾收集代码就可以取消分配不再引用的对象。该引用计数可以作为标记地址的一部分存储,而不是存储在单独的表中,从而加快创建或销毁对象的过程。
6、EL2和EL3的转换表
ARMv8-A体系结构的虚拟化扩展引入了第二阶段的转换。当系统中存在虚拟机监控程序时,可能存在一个或多个来宾操作系统。如前所述,它们继续使用TTBRn_EL1,MMU操作看起来没有变化。
虚拟机监控程序必须在两个阶段的过程中执行一些额外的转换步骤,以便在不同的客户操作系统之间共享物理内存系统。在第一阶段,虚拟地址(VA)被转换为中间物理地址(IPA)。这通常由操作系统控制。第二阶段由虚拟机监控程序控制,然后执行IPA到最终物理地址(PA)的转换。
hypervisor和Secure monitor也有一组第一阶段的代码和数据转换表,它们直接执行从VA到PA的映射。
图12-15总结了这两个阶段的翻译过程:
第2阶段的转换将中间物理地址转换为物理地址,它使用一组额外的表,由虚拟机监控程序控制。必须通过写入Hypervisor配置寄存器HCR_EL2来显式启用这些功能。此过程仅适用于非安全EL1/0访问。
此阶段2转换表的基址在虚拟化转换表基址寄存器VTTBR0_EL2中指定。它在内存底部指定一个连续的地址空间。支持的地址空间的大小在虚拟化转换控制寄存器VTCR_EL2的TSZ[5:0]字段中指定。
该寄存器的TG字段指定颗粒大小,而SL0字段控制表格查找的第一级。任何超出定义地址范围的访问都会导致转换错误。
虚拟机监控程序EL2和安全监视器EL3有自己的1级表,它们直接从虚拟地址空间映射到物理地址空间。表基址分别在TTBR0_EL2和TTBR0_EL3中指定,从而在内存底部启用一个大小可变的连续地址空间。TG字段指定颗粒大小,SL0字段控制表格查找的第一级。任何超出定义地址范围的访问都会导致转换错误。
安全监视器EL3有自己的专用转换表。表基址在TTBR0_EL3中指定,并通过TCR_EL3进行配置。翻译表能够访问安全和非安全物理地址。TTBR0_EL3仅在安全监视器EL3模式下使用,而不是由受信任的内核本身使用。完成到安全世界的转换后,受信任内核使用EL1翻译,即TTBR0_EL1和TTBR1_EL1所指向的翻译表。由于这些寄存器未存储在AArch64中,安全监视器代码必须为安全世界配置新表,并保存和恢复TTBR0_EL1和TTBR1_EL1的副本。
EL1翻译机制在安全状态下的行为与其在非安全状态下的正常操作不同。翻译的第二阶段被禁用,EL1翻译机制现在可以同时指向安全或非安全的物理地址。安全世界中没有虚拟化,因此IPA始终与最终PA相同。
TLB中的条目被标记为安全或非安全,因此在安全世界和正常世界之间转换时,不需要TLB维护。
7、访问权限
访问权限通过翻译表条目进行控制。访问权限控制一个区域是可读的还是可写的,或者两者都可以,并且可以分别设置为EL0(非特权访问)和EL1、EL2和EL3(特权访问),如表12-4所示。
操作系统内核在执行级别EL1中运行。它定义了转换表映射,内核本身和在EL0上运行的应用程序使用这些映射。需要区分非特权访问权限和特权访问权限,因为内核为自己的代码和应用程序指定了不同的权限。以执行级别EL2运行的虚拟机监控程序和安全监视器EL3只有供自己使用的转换方案,因此不需要特权和非特权的权限划分。
另一种访问权限是可执行属性。块可以标记为可执行或不可执行(从不执行(XN))。您可以分别设置Unprivileged Execute Never(UXN)和Privileged Execute Never(PXN)属性,并使用这些属性来防止应用程序代码以内核权限运行,或试图在非特权状态下执行内核代码。设置这些属性可防止处理器对内存位置执行推测性指令回迁,并确保推测性指令回迁不会意外地访问可能受到这种访问干扰的位置,例如先进先出(FIFO)页面替换队列。因此,设备区域必须始终标记为从不执行。
您可以使用SCTLR寄存器中的以下位,将处理器配置为将可写区域视为从不执行:
- SCTLR_EL1.WXN。在EL0处可写的区域在EL0和EL1处被视为XN。在EL1处可写的区域在EL1处被视为XN。
- SCTLR_EL2 and 3.WXN。在ELn上可写的区域在ELn上被视为XN。
- SCTLR.UWXN。在EL0可写的区域在EL1被视为XN。这只适用于AArch32。
SCTLR_ELn各个位可以缓存在TLB条目中。因此,改变SCTLR中的位可能不会影响TLB中已经存在的条目。当修改这些位时,TLB无效化和ISB序列是必需的。关于ISB的更多信息参考13章Barriers
8、操作系统中转换表描述符的使用
描述符中的另一个内存属性位,访问标志(AF),指示何时首次使用块条目。
- AF = 0。尚未被使用
- AF = 1。已被使用
操作系统使用访问标志位来跟踪正在使用的页面。软件管理旗帜。首次创建页面时,其条目的AF设置为0。第一次通过代码访问页面时,如果页面的AF为0,则会触发MMU故障。页面错误处理程序记录当前正在使用该页面,并手动设置表项中的AF位。例如,Linux内核在ARM64上使用PTE_AF的[AF]位(AARC64的Linux内核名称),用于检查是否访问过页面。这会影响一些内核内存管理选择。例如,当页面必须从内存中调出时,就不太可能调出当前正在使用的页面。
描述符的位[58:55]标记为保留供软件使用,可用于在翻译表中记录操作系统特定的信息。例如,Linux内核使用这些位之一将条目标记为干净或脏。脏状态记录页面是否已写入。如果页面后来被换出内存,则可以简单地丢弃干净的页面,但脏页面必须先保存其内容。
有关指定内存类型及其可缓存性和可共享性属性的其他内存属性的信息,请参阅第13章内存顺序。
9、安全和MMU
ARMv8-A体系结构定义了两种安全状态:安全和非安全。它还定义了两个物理地址空间:安全和非安全,这样正常世界只能访问非安全的物理地址空间。安全世界可以访问安全和非安全的物理地址空间。在非安全状态下,将忽略转换表中的NS位和NSTable位。只能访问非安全内存。在安全状态下,NS位和NSTable位控制虚拟地址转换为安全或非安全物理地址。你可以使用SCR_EL3.CIF以防止安全世界从任何转换为非安全物理地址的虚拟地址执行。此外,在安全的环境中,您可以使用SCR.CIF位,用于控制是否可以将安全指令取到非安全物理内存中。
10、上下文切换
实现ARMv8-A体系结构的处理器通常用于运行复杂操作系统的系统中,该系统具有许多并发运行的应用程序或任务。每个进程在物理内存中都有自己独特的转换表。当应用程序启动时,操作系统为其分配一组翻译表条目,这些条目将应用程序使用的代码和数据映射到物理内存。例如,内核随后可以修改这些表,以便在额外的空间中进行映射,并在应用程序不再运行时删除这些表。
因此,内存系统中可能存在多个任务。内核调度器周期性地将执行从一个任务转移到另一个任务。这称为上下文切换,需要内核保存与进程相关的所有执行状态,并恢复下一个要运行的进程的状态。内核还将转换表条目切换到下一个要运行的进程的条目。当前未运行的任务的内存完全不受正在运行的任务的影响。
不同的操作系统需要保存和恢复的内容各不相同,但流程上下文切换通常包括保存或恢复以下部分或全部元素:
- 通用寄存器X0-X30。
- 高级SIMD和浮点寄存器V0-V31
- 一些状态寄存器
- TTBR0_EL1 和TTBR0。(译注:转换表基址寄存器。进程不同,转换表不同,该寄存器的值就不同)
- 线程处理ID (TPIDxxx)寄存器
- 地址空间(ASID)
对于EL0和EL1,有两个翻译表。TTBR0_EL1为虚拟地址空间的底部(通常是应用程序空间)提供转换,TTBR1_EL1覆盖虚拟地址空间的顶部(通常是内核空间)。这种拆分意味着操作系统映射不必在每个任务的转换表中复制。
翻译表条目包含非全局(nG)位。如果为特定页面设置了nG位,则它与特定任务或应用程序相关联。如果位标记为0,则该条目是全局的,适用于所有任务。
对于非全局表项,当TLB被更新且表项被标记为非全局表项时,除了正常的转换信息外,还会在TLB表项中存储一个值。这个值称为地址空间ID (ASID),这是一个由操作系统分配给每个单独任务的数字。后续的TLB查找只在当前ASID与存储在条目中的ASID匹配时才匹配该条目。这允许为标记为非全局的特定页面提供多个有效的TLB条目,但具有不同的ASID值。换句话说,做上下文切换时我们不需要刷新TLB。
在AArch64中,这个ASID值可以指定为8位或16位的值,由TCR_EL1.AS位控制。当前的ASID值在TTBR0_EL1或TTBR1_EL1。TCR_EL1控制哪一个TTBR持有ASID,但它通常是TTBR0_EL1,因为这对应于应用程序空间。
此外,ARMv8-A架构还提供了线程ID寄存器供操作系统软件使用。它们没有硬件意义,通常被线程库用作每线程(per-thread)数据的基指针。这通常被称为线程本地存储(Thread Local Storage, TLS)。例如,pthreads库使用了这个特性,并包含以下寄存器:
- 用户读写线程ID寄存器(TPIDR_EL0)。
- 用户只读线程ID寄存器(TPIDRRO_EL0)
- 线程ID寄存器,只允许特权访问(TPIDR_EL1)。
11、使用用户权限做内核访问
有一些指令允许在EL1(例如操作系统)上执行的代码使用EL0或应用程序权限执行内存访问。例如,这可以用于对系统调用提供的指针做解引用,并使操作系统能够检查是否只访问了应用程序可访问的数据(译注:防止应用程序访问非法的数据)。这可以通过使用LDTR或STTR指令来实现。当在EL1执行时,这些指令执行加载或存储,就像在EL0执行一样。在所有其他异常级别上,LDTR和STTR的行为类似于常规LDR或STR指令。有通常的大小、有符号和无符号的变体作为正常的加载和存储指令,但只有较小的偏移量和受限的索引选项。