内存管理单元MMU的一个重要功能是使系统可以运行多个任务,让这些独立的程序可以运行在各自的私有虚拟内存空间。它们不需要知道系统的物理内存映射,即地址由硬件进行访问,或其他程序可能在同时执行。 你可以对每个程序使用相同的虚拟内存地址。即使物理内存粹片化,你仍可以工作在一个连续的虚拟内存映射。系统中虚拟地址映射与实际上的物理内存映射是分开的。你可以在虚拟内存空间进行写,编译,和编译应用。 在下图中显示了一个例子,系统中描述了虚拟和物理内存的视角。在单个系统中不同的处理器和设备可能有不同虚拟和物理地址映射。OS对MMU编程来在这两种内存视角中进行转换。 为实现它,虚拟内存系统中的硬件必须提供地址转换,该转换由处理器发起的虚拟地址转化为主存中的物理地址。 当在内存中放置代码时,你(编译器和链接器)使用的是虚拟地址。实际的物理系统使用的是物理地址。 MMU使用虚拟地址的最高位来在转换表中索引页表项,并建立访问哪个块。MMU将代码的虚拟地址转化为实际系统中的物理内存。转换自动在硬件中进行并对应用透明。除了地址转换,MMU控制内存访问权限,内存顺序和内存每个区域的cache策略。 MMU使任务或应用能够不用知道系统的物理内存映射,或其他程序可以在同时执行。这让你可以对多个程序使用相同的虚拟内存地址空间。 即使物理内存不连续,它让你可以工作在连续的虚拟物理内存映射。虚拟地址和实际的物理内存映射使分开的。应用被写,编译和链接都运行在虚拟内存空间。 1.1 TLBTLB是MMU中最近访问的页转换的缓存。对于处理器的每次内存访问,MMU检查TLB中转换是否缓存。如果请求的地址转换在TLB中命中,地址转换立即有效。 每个TLB项通常不仅包含物理和虚拟地址,也包含属性如内存类型,cache策略,访问权限,ASID,和VMID。如果TLB不包含处理器发出的虚拟地址的有效转换(TLB未命中),发出一个外部的转换表walk或转换表查找。MMU中的硬件使其读取内存中的转换表。如果转换表walk没有导致page fault,最新加载的转换可能被缓存在TLB中。TLB的具体结构根据ARM处理器的实现存在差异。 如果OS修改了TLB中缓存的转换表项,OS负责无效化stale TLB项。 当执行A64代码,TLBI为TLB无效化指令。 TLBI <type><level>{IS}{,<Xt>} 下列list给出type域的一些公共选择。 ALL 所有TLB项 VMALL 所有TLB项。当前guest OS的stage1 VMALLS12 所有TLB项。当前guest OS的stage1和stage2 ASID 在Xt中匹配ASID项 VA Xt中VA和ASID指定的项 VAA Xt中VA指定的项,任意ASID EL3,EL2,EL1的异常级别的操作应用于自己的虚拟地址空间。IS域指明了这仅应用于inner shareable项。 NOTE: 看Context Switching关于ASID和转换表配置。 <level>域简单的指明了操作应用的异常级别虚拟地址空间。 IS域指明了这仅用于inner shareable项。
下面的代码例子显示了写一个由inner shareable内存后置转换表的时序: <writes to translation tables>DSB ISHSTTLBI ALLE1DSB ISHISB 比如,修改转换表项,使用指令: TLBI VAE1,X0 这将无效化X0寄存器指定的地址相关的转换表项。 TLB能够缓存的转换表项是固定的。你可以通过最小化转换表遍历造成的外部内存的访问并获取更高的TLB命中率来获取更高的性能。ARMv8-A架构提供了contiguous block特性来有效的使用TLB空间。每个转换表block项包含一个contiguous位。当设置时,这个位告诉TLB它可以仅缓存一个表项来覆盖多个block。一次查找索引到一个contigous块覆盖的地址范围。因此TLB可以位一个定义的地址范围缓存一个表项,使其能够在TLB中存储更大范围的虚拟地址。 为了使用contiguous位,这些连续的block必须相连,即它们必须与虚拟地址的连续范围相关。它们必须起始于对齐的边界,有一致性的属性,并指向转换的同一级别的连续的输出地址范围。要求的对齐为4KB粒度的VA[20:16]或64KB粒度的VA[28:21]对于所有地址都相同。下列要求: (1)16*4KB相连的块给出了4KB粒度的64KB项; (2)32*32MB相连的块给出了L2描述符的1GB表项,128*16KB给出了当使用16KB时L3描述符的2MB表项; (3)32*64KB相连的块给出了64KB粒度的2MB表项。 如果这些条件都满足时,一个程序错误产生,这会导致TLB abort或查找奔溃。这些错误包括: (1)一个或多个表项不包含contiguous位; (2)其中一个表项的输出超过对齐的范围。 对于ARMv8架构,错误的使用不允许EL0和EL1有效的地址范围的权限的检查,或EL3空间的错误访问。 2 内核和应用虚拟地址空间的分开操作系统通常有多个应用或任务异步运行。每个应用都有自己唯一的转换表且内核从一个转换表切换到另一个,这作为两个任务进行上下文切换的一部分。但是,大多数内存系统仅被内核使用且有固定的虚拟到物理地址的映射,转换表项很少修改。ARMv8架构提供了一些特性来有效处理这个要求。 转换表基地址有TTBR0_EL1和TTBR1_EL1指定。当VA的高位全为0时,选择TTBR0指向的转换表,当VA的高位为1时,选择TTBR1选择的转换表。你可以使能VA tagging不用对高8位做检查。 处理器的指令获取或数据访问的虚拟地址为64位。但是你必须在48位物理地址内存映射中映射两个定义的区域。 EL2和EL3只有TTBR0,没有TTBR1,这意味着: (1)如果EL2使用AArch64,它仅使用范围0x0~0x0000ffffffffffff的VA; (2)如果EL3使用AArch64,它仅使用范围0x0~0x0000ffffffffffff的VA; 下图显示了内核空间被映射到内存的最高区域并且虚拟地址空间被映射到内存的最低区域。但是,两者都被映射到一个更小的物理地址空间。 转换控制寄存器TCR_EL1定义了需要检查的最高位的数目。TCR_EL1包含T0SZ[5:0]和T1SZ[5:0]。这个域的数字给出了全0或全1的最高位的数目。这里指定了这些域的最小值和最大值,根据granule大小和起始表级别不同。因此,你必须一直使用两个空间,在所有系统中至少要求两个转换表。简单的裸系统没有OS仍要求包含fault项的表。 TCR_EL1控制着EL1和EL0的其他内存管理特性。上图仅显示了控制地址范围和graunule大小的域。 IPS域控制着最大输出地址大小。如果转换指定的输出地址超出了范围,访问出现错误,000=32位物理地址,101=48位。两bit TG1和TG0域给出了内核或用户空间的粒度,00=4KB,01=16KB,11=64KB。 你可以配置用于第一次查找的转换表级别。完整的转换过程要求三级或四级页表。你不需要实现所有级别。查找的第一级别由粒度大小和TCR_ELn.TxSZ域决定。你可以分开配置TTBR0_EL1和TTBR1_EL1。 3 将虚拟地址转换位物理地址当处理器发出64位虚拟地址用于指令获取或数据访问,MMU硬件将虚拟地址转化为对应的物理地址。对于虚拟地址的高16位[63:47]必须为全0或全1,否则地址会触发fault。 最低位用于给出选择的区域的偏移,因此MMU联合物理地址从最低位的块表entry和原始地址的最低位来产生最后地址。 架构也支持taggged地址。这时地址的最高8位会被忽略(不再作为地址的一部分)。这意味着这些位用于其他,比如,记录指针的信息。 简单的地址转换仅涉及一级的查找。它假定我们使用42位虚拟地址,16KB粒度。MMU转换一个虚拟地址如下: (1)若VA[63:42]=1时,TTBR1用于第一个页表的基地址。当VA[63:42]=0时,TTBR0用于第一个页表的基地址。 (2)页表包含8192个64位的页表项,通过VA[41:29]来索引。MMU从页表读取level2相关的页表项。 (3)MMU检查页表项并验证要求的内存访问是否允许。假设它是有效的,内存访问是允许的。 (4)在上图中,每个页表项涉及一个512M的页(block描述符)。 (5)从页表项中bit[47:29]取出并形成物理地址的bit[47:29]。 (6)因为我们由512M页,虚拟地址的bit[28:0]被取出形成虚拟地址[28:0]。 (7)返回PA[47:0],伴随着从页表项的其他信息。 实际上,这个简单的转换过程限制了你是如何切分你的地址空间。取代仅使用一级转换表,第一级页表项也可以指向第二级页表。 这样一个OS可以将大块的虚拟内存切分为更小的页。对于二级页表,第一级描述符包含二级页表的物理基地址。与处理器要求的虚拟地址对应的物理地址在第二级描述符中找到。 下图显示了一个64位起始于stage1,二级的64KB页的转换。 每个二级表与一个或多个一级项相关。你可以有多个一级描述符,它们指向相同的二级页表,这意味着你将几个虚拟位置别名到相同的物理地址。 上图描述了两级查找的情况。同样,它假设64KB粒度和42位虚拟地址空间: (1)若VA[63:42]=1时,TTBR1用于第一个页表的基地址。当VA[63:42]=0时,TTBR0用于第一个页表的基地址。 (2)页表包含8192个64位的页表项,通过VA[41:29]来索引。MMU从页表读取level2相关的页表项。 (3)MMU检查页表项并验证要求的内存访问是否允许。假设它是有效的,内存访问是允许的。 (4)在上图中,level2页表项涉及level3页表的地址(table描述符)。 (5)从level2页表项的VA[47:16]取出并形成level3页表的基地址。 (6)虚拟地址的VA[28:16]用于索引level3页表项。MMU从页表中读取相关的level3页表项。 (7)MMU检查level3页表项并检验要求的内存访问是否被访问。假设它是有效的,内存访问时允许的。 (8)在上图中,level3页表项涉及64KB页(page描述符)。 (9)从level3页表项取bit[47:16]并用于形成PA[47:16]。 (10)因为我们使用64KB页,VA[15:0]形成PA[15:0]。 (11)返回完整的PA[47:0],伴随着从页表项的其他信息。 3.1 安全和非安全地址理论上安全和非安全物理地址空间是分开的,且并行存在的。系统可以被设计位有两个完全分开的内存系统。但是,大多数真实的系统将安全和非安全作为访问控制的属性。正常world(非安全)可以访问非安全物理地址空间。安全world可以访问连个物理地址空间。这也是通过转换表来控制的。 这也有cache一致性的暗示。比如,因为安全0x8000和非安全0x8000为不同的物理地址,它们可能同时在cache中。 在安全和非安全内存在不同的位置的系统中,这也没有问题。它们更可能在相同的位置。最理想的一个内存系统将阻塞安全访问到非安全内存和非安全访问到安全内存。实际上大多数仅阻塞非安全访问到安全内存。这意味着相同的物理内存在cache中可能有两个,安全和非安全。这通常为编程错误。为避免这个,安全world必须通常使用非安全访问到非安全内存。 3.2 配置和使能MMU写系统寄存器来控制MMU,没有顺序要求。这些事件的结果只有在上下文同步事件时才可见。 MSR TTBR0_EL1, X0MSR TTBR1_EL1, X1MSR TCR_EL1, X2ISBMRS X0, SCTLR_EL1ORR X0, X0, #1MSR SCTLR_EL1, X0ISB 这是flat映射的需求,它使我们知道在写SCTLR_EL1.M后哪个指令直接运行。如果我们看到写的结果,它为使用新的转换区域。如果我们没有看到写的结果,它仍在执行指令VA+4,这时VA=PA。ISB在这里没有帮助因为我们不能保证它是下一个指令。 3.3 当MMU禁用时的操作当MMU stage1禁用时,当HCR_EL2.DC位被设置使能数据cache时,对于非安全EL0和EL1,默认的内存类型为正常non-shareable,inner Write-back Read-write allocation,outer Write-back READ-write allocate。 4 ARMv8-A的转换表ARMv8-A架构提供了三种不同转换表格式的支持: (1)ARMv8-A AArch64 长描述符格式 (2)ARMv7-A长描述符格式如LPAE,ARM Cortex-A15处理器 (3)ARMv7-A短描述符 在AArch32中,你可以使用已经存在的ARMv7-A长和短描述符格式来执行已经存在的操作系统以及没有修改的应用代码。ARMv7-A短描述符仅用于EL0和EL1 stage1转换。因此他们不能被hypervisor或安全monitor代码。 通常在AArch64中使用ARMv8-A长描述符格式。它与ARMv7-A长描述符格式LPAE类似。它使用64位长描述符格式,但有些修改。它引入了新的level0表索引,它使用与level1表相同的描述符格式。这支持48位输入和输出地址。输入虚拟地址来自于64位寄存器。但是,因为架构不支持完全64位地址,bit 63:48必须相同,全0或全1,或高8位用于虚拟地址tagging。 AArch64支持三种不同转换粒度。这定义了转换表的最小级别块大小且控制转换表的大小。更大的粒度大小减少了要求的页表级别数目,且这也在使用hypervisor提供虚拟化的系统中重要的考虑。 支持的粒度为4KB,16KB和64KB,并且由实现定义支持这三种。创建页表的代码可以读取系统寄存器ID_AA64MMFR0_EL1来找到支持的大小。Cortex-A53处理器支持这三种大小,但这不是处理器早期版本的情况,比如Cortex-A57,不支持16K粒度。每个转换表配置在大小在TCR_EL1。 4.1 AArch64描述符格式你可以 使用页表所有级别(从level0到level3)的描述符格式。Level0描述符只能输出level1表的地址。Level3描述符不会指向另外的页表且只输出块地址。因此表的格式在level3上有些不一样。 下图描述了table描述符类型,这通过bit1:0定义:
NOTE:上图并没有指定这些域的位宽。 4.2 粒度对转换表的影响三种不同的粒度可以影响要求的转换表的数目和大小。 NOTE: 对于所有情况,如果虚拟地址的范围限制在42位时,你可以忽略页表的第一级。 依赖于可能虚拟地址的范围大小,这可以更少的级别。对于4KB粒度,比如,如果TTBCR被设置,低地址可跨1GB,level0和level1不需要且转换表从level2开始,对4KB页可以走到level3。 4KB:当你使用4KB粒度大小时,硬件可以使用4级查找过程。48位地址对每个级别有9个地址位,即512个转换项,用直接从原始地址的最后12位在4KB内选择byte。 虚拟地址的bit 47:39索引L0表的512个页表项。这些页表项的每个都跨512GB且指向L1表。在512个L1表项中,bit38:30用于索引选择一个页表项,每个页表项指向1GB块或L2表。Bit 29:21索引到L2表的512项,每个页表项指向2MB块或下一级表。在最后一级中,bit 20:12索引L3表的512项,每个页表项指向4KB块。 64KB:当你使用64KB粒度,硬件可以使用3级查找过程。Level1表仅包含64个页表项。 虚拟地址的bit 47:42用于从L1表的64个页表项选择描述符。这些页表项的每个跨4TB范围且指向L2表。在L2表中的8192页,bit 41:29用于索引选择一个页表项且每个页表项指向512MB块或L2表。在最后转换阶段,bit 28:16索引L3表的8192个页表项,每个页表项指向64KB块。 4.3 cache配置MMU使用转换表和转换寄存来控制哪个内存位置被缓存。MMU控制cache策略,内存属性,和访问权限,并提供虚拟地址到物理地址的转换。 由系统寄存器发出软件配置。 在一些设计中,外部内存系统可能包含外部内存的实现特定的cache。 5 转换表配置除了在TLB中存储单个指令外,你可以配置MMU来在可缓存的内存中存储转换表。这通常提供对页表更快的访问而不是从外部内存读取。TCR_EL1有其他域来控制这些。 这些域指定转换表的TTBR0和TTBR1的cacheability和shareability。相关域称为SH0/1 shareability,IRGN0/1 Inner Cacheability,ORGN0/1 Outer Cacheability。下表呈现了允许的cacheability的设置。
相关表中内存的shareability与转换表walk相关。 对于设备或强时序内存区域,该值被忽略。
TCR_EL1中指定的属性必须与虚拟内存区域(转换表存储)指定的属性一样。缓存转换表为正常的默认行为。 5.1 虚拟地址tagging转换控制寄存器TCR_ELn有增加的域称为TBI,它提供tagged addressing支持。通用寄存器为64位宽,但最高16位必须为0xffff或0x0。任何其他的值将触发fault。 当tagged addressing使能时,高8位,即虚拟地址的[63:56],会被处理器忽略。虚拟地址的高8位可以用来传递数据。这些位被地址或转换fault忽略。TCR_EL1对EL0和EL1有分开的使能位。ARM没有指定或强制tagged addressing的特别使用情况。 一个使用的例子用于支持面向对象编程语言。因为有一个指针指向object,它有必要保持引用计数来跟踪引用的数目或指针,比如,因此自动垃圾收集代码可以释放object。引用计数可以被保存作为tagged address,而不用单独的表,加速了创建或销毁object的过程。 6 EL2和EL3的转换ARMv8-A架构的虚拟化扩展引入了转换的第二stage。当系统中存在hypervisor时,可能存在一个或多个guest操作系统。它们如之前描述的仍使用TTBRn_EL1且MMU操作不会变化。 hypervisor必须在两stage过程中发出一些额外的转换步骤来共享不同guest操作系统中的物理内存系统。在第一stage中,VA被转化为IPA,这通常由OS控制。第二stage中,由hypervisor控制,发起由IPA到最后PA的转换。 hypervisor和安全monitor也有它们的代码和数据的stage1转换表,它发起从VA到PA的直接映射。 NOTE:架构手册使用Translation Regime来表示不同的转换表。 下图总结了两stage转换过程。 stage2转换,将IPA转换为PA,使用hypervisor控制的额外一组表。这须通过写HCR_EL2明确的使能。这个过程仅应用于non-secure EL1/0访问。 stage2转换表的基地址由VTTBR0_EL2指定。它指定了在内存下部的一个单独连续地址空间。支持的地址空间大小由VTCR_EL2的TSZ[5:0]域指定。 寄存器的TG域指定了granule大小,SL0域控制页表查找的第一级。超出指定地址范围的访问会造成转换fault。 hypervisor EL2和安全monitor EL3由各自的level1表,它直接将虚拟地址空间映射到物理地址空间。TTBR0_EL2和TTBR0_EL3指定表基地址,并在内存下部使能了一块连续的地址空间。TG域指定granule大小,SL0域控制了表查找的第一level。任何超出定义的地址范围会造成转换fault。 安全monitor EL3有自己的转换表。该表基地址由TTBR0_EL3指定并通过TCR_EL3配置。转换表有能力访问安全和非安全物理地址。TTBR0_EL3仅用于安全monitor EL3模式,但不被trusted内核使用。当对安全world的转换完成时,trusted内核使用EL1转换,即转换表由TTBR0_EL1和TTBR1_EL1指定。因为这些寄存器在AArch64 not bank,安全monitor代码必须配置安全world的新表且保存TTBR0_EL1和TTBR1_EL1的拷贝。 与非安全状态的正常操作相比,EL1转换regime在安全状态行为不一样。转换的第二stage被禁用,EL1转换regime可以指向安全和非安全物理地址。在安全world没有虚拟化,因此IPA通常与最后的PA相同。 TLB中的页表项被标记为安全或非安全,因此当你在安全和正常world进行转换时不需要TLB维护。 虚拟内存名词解释转换粒度(translation granule) 执行物理页和虚拟页之间转换的最小粒度(物理页大小) 内存页(Page) 内存页一般指转换粒度 内存块(block) 内存块一般指多个连续的内存页组成的一块内存,当然把一个内存页也称为内存块也是可以的 页表目前64位架构的MMU通常使用4级页表(level 0,1,2,3),支持最大48位有效地址。页表项可以指向下一级页表(table descriptor)或者指向内存块/页(block descriptor, 下图中page descriptor也是block descriptor的一种,区别在于Page Descritpor仅表示最后一级页表的页表项),其中leve3页表只能指向内存页,level0级页表只能指向下一级页表,页表项基本结构如下图所示。
upper attributes占用高14位(对于table descriptor占用高12位),其和address字段之间的部分保留用于支持52bit的物理地址。 address字段占用中间36位(bit[47:12], 以4kb为粒度则地址的低12bit均为0,无需存放,因此address为实际48位物理地址的高36位),如果我们使用大内存页(即转换使用的最后一级页表<3),则address字段的低位字节将被忽略,具体来说,如果使用level 2级别页表作为最后一级,其一个页表项指向2MB的内存页,因此address字段中低9bit被忽略;如果使用level 1级别页表最为最后一级页表,其一个页表项指向1GB内存,,因此address字段低18bit将被忽略。 lower attribute占用bit[11:2],bit[1]表示该页表项的类型(0表示block descriptor,指向最终内存块;1表示table descriptor,指向下一级页表),bit[0]表示该表项是否有效(0表示该表项无效,1表示该表项有效),关于upper attributes和lower attribute,见页表项属性小节。
页表项属性Block descriptorLower attributes
下表为
MAIR寄存器
外设内存MMIO
关于G、R、E的说明如下
普通内存
R表示Read-Allocate policy, W表示Write-Allocate policy
Upper attributes
Table Descriptor
配置虚拟内存地址长度通过设置 通常有效的48bit用户空间地址(
|
|