注意:这两章只是介绍AArch64 memory management,还有AArch64 memory management examples,AArch64 memory attributes and properties等没介绍
内存管理单元(MMU)负责将软件使用的虚拟地址转换为内存系统中使用的物理地址。
MMU包含以下内容:
转换表的工作原理是将虚拟地址空间划分为相同大小的块(block),并为每个块提供表入口。
表中的入口0提供块0(block 0)的映射,入口1提供块1(block 1)的映射,以此类推。每个入口包含相应的物理内存块的地址以及访问物理地址时使用的属性。
当发生转换时会发生表查找。当发生转换时,软件发出的虚拟地址将被一分为二,如下图所示:
上图显示了一个单级查找。
图中标记为“哪个条目(Which entry)”的高位告诉你要查看哪个块入口,并且它们被用作表中的索引。此输入块包含该虚拟地址的物理地址。
图中被标记为“块中的偏移量(Offset in block)”的低位,是该块内的一个偏移量,不会因转换而改变。
在单级查找中,虚拟地址空间被分割成相同大小的块。实际上,通常使用多级查找。
第一个表(第1级表)将虚拟地址空间分成大块。这个表中的每个入口都可以指向一个大小相同的物理内存块,也可以指向另一个表,该表将该块细分为更小的块。我们将这种类型的表称为“多级表(multilevel table)”。在这里,我们可以看到一个有三层的多级表的例子:
在Armv8-A中,最大支持4级,级别编号为0到3。
这种多级方法允许描述更大的块和更小的块。大小块的特点如下:
为了管理这种权衡,操作系统必须平衡使用较大映射的效率和使用较小映射的灵活性,以获得最佳性能。
处理器在启动表查找时并不知道转换的大小。处理器通过执行表行走(The table walk )来计算正在转换的块的大小。
下图中,我们可以看到转换表入口所允许的不同格式:
为了清晰起见,此图没有指定位字段的宽度。您可以在 Arm Architecture Reference Manual Armv8找到此信息,用于Armv8-A体系结构配置文件:The VMSAv8-64 translation table format descriptors。
每个入口都是64位,低两位决定了入口的类型。
请注意,某些表入口仅在特定的级别上有效。表的最大级别数是4,这就是为什么没有针对级别3(或第四级)、表的表描述符的原因。类似地,级别0中也没有块描述符或页面描述符。因为0级入口覆盖了很大的虚拟地址空间区域,所以允许块没有意义。
第0-2级的表描述符的编码与第3级的页面描述符相同。这种编码允许“递归表(recursive tables)”,它们指向它们自己。这很有用,因为它便于计算特定页表条目的虚拟地址,以便可以更新它。
转换颗粒是可以描述的最小的内存块。没有更小的可以描述,只有更大的块,这是颗粒的倍数。
AArch64支持三种不同的颗粒尺寸: 4KB、16KB和64KB。
处理器所支持的颗粒大小是由ID_AA64MMFR0_EL1定义并报告的实现。所有的Arm Cortex-A处理器都支持4KB和64KB。所选的颗粒是在最新级别表中可以描述的最小块。也可以描述更大的块。下表显示了基于所选颗粒的每个级别表的不同块大小:
在引入Armv9.2-A和Armv8.7-A之前,对使用52位地址有限制。当所选颗粒为4KB或16KB时,最大虚拟地址区域大小为48位。同样地,输出物理地址被限制为48位。只有当使用64KB的颗粒时,才能使用完整的52位。
TCR_EL1有两个独立的字段来控制内核空间的颗粒大小和用户空间的虚拟地址范围。这些字段对于内核空间称为TG1,对于用户空间称为TG0。程序员面临的一个潜在问题是,这两个字段有不同的编码。
颗粒和虚拟地址空间的大小一起控制着地址转换的起始级别。
上一个表总结了每个表层中每个颗粒的块大小(由单个入口所覆盖的虚拟地址范围的大小)。从块的大小中,你可以计算出虚拟地址的哪些位被用来索引表的每个级别。
假设,对于一个配置,你将虚拟地址空间的大小TCR_ELx.T0SZ设置为32。然后,以地址位表示的虚拟地址空间的大小计算为:
64 - T0SZ = 32-bit address space (address bits 31:0)
如果我们再看前面的4KB颗粒图,0级被47:39位索引。对于一个32位的地址空间,你就没有这些位了。因此,您配置的初始转换级别是第1级。
接下来,假设您将T0SZ设置为34:
64 - T0SZ = 30-bit address space (address bits 29:0)
此时,您没有任何其他用于索引第0级表或第1级表的位,因此您的配置的起始转换级别是第2级。
如上图所示,当虚拟地址空间的大小减小时,您需要更少级别的表来描述它。
这些例子是基于使用4KB颗粒。同样的原理也适用于使用16KB和64KB的颗粒,但地址位发生了变化。
地址转换由以下系统寄存器的组合控制:
当在转换阶段禁用MMU时,所有地址都是平面映射的。平面映射表示输入地址和输出地址相同。
转换备用缓冲区(Translation Lookaside Buffers,TLBs)缓存最近使用的转换。这种缓存允许后续查找重用转换,而不需要重读表。
TLBs是转换缓存,而不是转换表缓存。区别是微妙的。有几个寄存器字段控制如何解释转换表入口。TLB入口中包含的是给定在行走表时的配置的转换表入口的解释。在Arm架构参考手册(Arm ARM)中,这样的寄存器字段被描述为“允许在TLB中缓存”。
如果更改了转换表入口或控制影响入口的参数,则需要使TLB中受影响的入口无效。如果您不使这些入口无效,那么处理器可能会继续使用旧的转换。
处理器不允许缓存到导致以下任何故障的TLB的转换:
TLBI指令用于使TLBs中的入口无效。此指令的语法为:
TLBI < type >< level >{IS|OS} {, < xt >}
STR X1, [X5] // Write to translation table entry
DSB ISH // Barrier instructions - not covered in this guide
TLBI VAAE1IS , X0 // Invalidate VA specified by X0, in EL0/1
// virtual address space for all ASIDs
DSB ISH // Barrier instructions - not covered in this guide
ISB // Synchronize context on this processor
地址转换(AT)指令允许软件查询特定地址的转换。转换的结果包括属性,被写入物理地址寄存器PAR_EL1。
AT指令的语法允许您指定要使用的转换机制。例如,EL2可以查询EL0/EL1的转换机制。但是,EL1不能使用AT指令来查询EL2的转换机制,因为这违反了特权。
如果所请求的转换会导致fault,则不会生成异常(exception)。相反,将生成的fault类型将记录在PAR_EL1中。
在地址转换的阶段(stage)和级别(level)之间有什么区别?
一个阶段是将输入地址转换为输出地址的过程。对于第一阶段,这是从VA到IPA的过程,第二阶段从IPA到PA
一个级别指的是在一个给定的转换阶段中的表。这也是如何将一个更大的块细分为更小的块。
物理地址的最大大小是多少?
物理地址空间的最大大小是由实现定义(IMPLEMENTATION DEFINED),最多52位(从Armv8.2-A开始)。
哪个寄存器字段控制虚拟地址空间的大小?
TCR_ELx.TnSZ, or VTCR_EL2.T0SZ for Stage 2.
什么是转换颗粒,支持的大小是多少?
它是可以描述的最小的内存块。支持的size分别为4KB、16KB和64KB。
TLBI中的ALLE3是做什么的?
它会使EL3虚拟地址空间中的所有TLB入口无效。
导致转换fault的转换表入口能否缓存在TLBs中?
它不能存储在TLBs中
在禁用MMU时,如何映射地址?
地址是平面映射的,因此输入地址和输出地址是相同的。
什么是ASID?TLB入口何时包含ASID?
ASID是一个地址空间标识符,它标识与转换关联的应用程序。非全局映射(nG=1)在TLBs中用ASID进行标记。
下一步将介绍
Learn the architecture - AArch64 memory management