提示
- 该博客主要为个人学习,通过阅读官网手册整理而来(个人觉得阅读官网的英文文档非常有助于理解各个IP特性)。若有不对之处请参考参考文档,以官网文档为准。
- AArch64 memory management学习一共分为两章,这是第二章。第一章见AArch64 memory management学习(一)
注意:这两章只是介绍AArch64 memory management,还有AArch64 memory management examples,AArch64 memory attributes and properties等没介绍
1. 内存管理单元(Memory Management Unit,MMU)
内存管理单元(MMU)负责将软件使用的虚拟地址转换为内存系统中使用的物理地址。
MMU包含以下内容:
- The table walk unit(表行走单元?这里还是用英文,中文翻译感觉有点奇怪,下面涉及到感觉翻译奇怪的都会写英文然后括号中文加上“?”),它包含从内存中读取转换表的逻辑
- Translation Lookaside Buffers (TLBs,转换备用缓冲区?),表示最近缓存使用的转换。
由软件发布的所有内存地址都是虚拟的。这些内存地址被传递给MMU,MMU检查TLBs是否有最近使用的缓存转换。如果MMU没有找到最近缓存的转换,表行走单元将从内存中读取适当的入口,如下图所示:
在进行内存访问之前,一个虚拟地址必须被转换为一个物理地址(因为我们必须知道我们正在访问的是哪个物理内存位置)。这种转换的需求也适用于缓存的数据,因为在Armv6和更高版本的处理器上,数据缓存使用物理地址(经过物理标记的地址)来存储数据。因此,在完成缓存查找之前,必须转换地址。
1.1 表入口(Table entry)
转换表的工作原理是将虚拟地址空间划分为相同大小的块(block),并为每个块提供表入口。
表中的入口0提供块0(block 0)的映射,入口1提供块1(block 1)的映射,以此类推。每个入口包含相应的物理内存块的地址以及访问物理地址时使用的属性。
1.2 查表法(Table lookup)
当发生转换时会发生表查找。当发生转换时,软件发出的虚拟地址将被一分为二,如下图所示:
上图显示了一个单级查找。
图中标记为“哪个条目(Which entry)”的高位告诉你要查看哪个块入口,并且它们被用作表中的索引。此输入块包含该虚拟地址的物理地址。
图中被标记为“块中的偏移量(Offset in block)”的低位,是该块内的一个偏移量,不会因转换而改变。
1.3 多级转换(Multilevel translation)
在单级查找中,虚拟地址空间被分割成相同大小的块。实际上,通常使用多级查找。
第一个表(第1级表)将虚拟地址空间分成大块。这个表中的每个入口都可以指向一个大小相同的物理内存块,也可以指向另一个表,该表将该块细分为更小的块。我们将这种类型的表称为“多级表(multilevel table)”。在这里,我们可以看到一个有三层的多级表的例子:
在Armv8-A中,最大支持4级,级别编号为0到3。
这种多级方法允许描述更大的块和更小的块。大小块的特点如下:
- 大块比小块需要更少的读取级别来转换。此外,大块在TLBs中缓存更有效。
- 小块使软件能够对内存分配进行细粒度控制。然而,小块在TLBs中缓存的效率较低。因为小块需要进行多次级别转换来读取。
为了管理这种权衡,操作系统必须平衡使用较大映射的效率和使用较小映射的灵活性,以获得最佳性能。
处理器在启动表查找时并不知道转换的大小。处理器通过执行表行走(The table walk )来计算正在转换的块的大小。
2. 控制地址转换和转换表格式
下图中,我们可以看到转换表入口所允许的不同格式:
为了清晰起见,此图没有指定位字段的宽度。您可以在 Arm Architecture Reference Manual Armv8找到此信息,用于Armv8-A体系结构配置文件:The VMSAv8-64 translation table format descriptors。
每个入口都是64位,低两位决定了入口的类型。
请注意,某些表入口仅在特定的级别上有效。表的最大级别数是4,这就是为什么没有针对级别3(或第四级)、表的表描述符的原因。类似地,级别0中也没有块描述符或页面描述符。因为0级入口覆盖了很大的虚拟地址空间区域,所以允许块没有意义。
第0-2级的表描述符的编码与第3级的页面描述符相同。这种编码允许“递归表(recursive tables)”,它们指向它们自己。这很有用,因为它便于计算特定页表条目的虚拟地址,以便可以更新它。
3. 转换颗粒
转换颗粒是可以描述的最小的内存块。没有更小的可以描述,只有更大的块,这是颗粒的倍数。
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。程序员面临的一个潜在问题是,这两个字段有不同的编码。
3.1 地址转换的起始级别
颗粒和虚拟地址空间的大小一起控制着地址转换的起始级别。
上一个表总结了每个表层中每个颗粒的块大小(由单个入口所覆盖的虚拟地址范围的大小)。从块的大小中,你可以计算出虚拟地址的哪些位被用来索引表的每个级别。
假设,对于一个配置,你将虚拟地址空间的大小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的颗粒,但地址位发生了变化。
3.2 控制地址转换寄存器
地址转换由以下系统寄存器的组合控制:
- SCTLR_ELx
- M :使能MMU
- C:使能data和统一缓存
- EE:转换表行走(translation table walks)大小端
- TTBR0_ELx 和 TTBR1_ELx
- BADDR:转换表开始位置的物理地址(PA)(或中间物理地址,EL0/EL1)
- ASID:用于非全局转换的地址空间标识符
- TCR_ELx
- PS/IPS:PA或IPA空间的大小,最大输出地址大小
- TnSZ:表中所覆盖的地址空间的大小
- TGn:颗粒度
- SH/IRGN/ORGN-MMU表行走所使用的可访问性和可共享性
- TBln:禁用表行走到一个特定的表
- MAIR_ELx
- Attr:控制阶段1(stage 1)表中的类型和可缓存性
3.3 失能MMU
当在转换阶段禁用MMU时,所有地址都是平面映射的。平面映射表示输入地址和输出地址相同。
4. 转换备用缓冲区维护
转换备用缓冲区(Translation Lookaside Buffers,TLBs)缓存最近使用的转换。这种缓存允许后续查找重用转换,而不需要重读表。
TLBs是转换缓存,而不是转换表缓存。区别是微妙的。有几个寄存器字段控制如何解释转换表入口。TLB入口中包含的是给定在行走表时的配置的转换表入口的解释。在Arm架构参考手册(Arm ARM)中,这样的寄存器字段被描述为“允许在TLB中缓存”。
如果更改了转换表入口或控制影响入口的参数,则需要使TLB中受影响的入口无效。如果您不使这些入口无效,那么处理器可能会继续使用旧的转换。
处理器不允许缓存到导致以下任何故障的TLB的转换:
- 转换fault(未映射的地址)
- 地址大小fault(地址超出范围)
- 访问标志fault
因此,在第一次映射地址时,不需要发出TLB无效。但是,如果您想执行以下任何操作,则需要发出TLB无效: - 取消映射地址
获取一个以前有效的地址或已映射的地址,并将其标记为错误地址。 - 更改地址映射
更改输出地址或任何属性。例如,将地址从只读权限更改为读写权限。 - 更改解释表的方式
这种情况并不常见。但是,如果颗粒度改变了,那么对表的转换也会改变。因此,TLB无效将是必要的。
4.1 TLB操作的格式
TLBI指令用于使TLBs中的入口无效。此指令的语法为:
TLBI < type >< level >{IS|OS} {, < xt >}
- < type > 表示哪些入口无效
ALL:所有入口
VA:在Xt中匹配VA和ASID的入口
VAA:对于任何ASID,在Xt中输入匹配VA的入口
ASID:在Xt中,匹配ASID的任何入口
… - < level > 表示要操作的地址空间
E1 = EL0/1虚拟地址空间
E2 = EL2虚拟地址空间
E3 = EL3虚拟地址空间 - < IS|OS > 表示操作是内部共享(Inner Shareable,IS)还是外部共享(Outer Shareable,OS)
当IS添加到操作时,它将广播到内部共享域中的其他核心。
当操作系统添加到操作时,它将广播到外部共享域的其他核心(在Armv8.4-A中添加)。 - < Xt > 表示操作哪个地址或ASID
仅用于按地址或ASID进行的操作
例如,一个正在更新其内核转换表中的入口的操作系统(OS)。一个典型的TLB无效序列应该是这样的:
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
5. 地址转换指令
地址转换(AT)指令允许软件查询特定地址的转换。转换的结果包括属性,被写入物理地址寄存器PAR_EL1。
AT指令的语法允许您指定要使用的转换机制。例如,EL2可以查询EL0/EL1的转换机制。但是,EL1不能使用AT指令来查询EL2的转换机制,因为这违反了特权。
如果所请求的转换会导致fault,则不会生成异常(exception)。相反,将生成的fault类型将记录在PAR_EL1中。
6. Check your knowledge
-
在地址转换的阶段(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进行标记。
7. 下一步
下一步将介绍
- AArch64 memory management examples
- Memory Model
参考文献
Learn the architecture - AArch64 memory management