9.The Memory Management Unit
内存管理单元(MMU)的一个重要功能是使您能够管理任务,作为独立的程序在其自己的私有虚拟内存空间中运行。这种虚拟内存系统的一个关键特征是地址重定位,或将处理器发出的虚拟地址转换为主内存中的物理地址。ARM MMU 负责将代码和数据的地址从内存的虚拟视图翻译为真实系统中的物理地址。该翻译由 MMU 硬件完成,对应用程序是透明的。此外,MMU 控制每个内存区域的内存访问权限、内存顺序和缓存策略。
在多任务嵌入式系统中,我们通常需要一种方法来划分内存映射并为这些内存区域分配权限和内存属性。在运行更复杂的操作系统(如 Linux)的情况下,我们需要对内存系统有更大的控制权。
MMU 使任务或应用程序能够以一种不需要了解系统物理内存映射或可能同时运行的其他程序的方式编写。这使您能够为每个程序使用相同的虚拟内存地址空间。即使物理内存是碎片化的,它也允许您使用连续的虚拟内存映射。这个虚拟地址空间与系统中实际的物理内存映射是分开的。应用程序是在虚拟内存空间中编写、编译和链接的。虚拟地址是您、编译器和链接器在将代码放入内存时使用的地址,而物理地址是实际硬件系统使用的地址。
操作系统负责编程 MMU,以在这两种内存视图之间进行转换。下图示例展示了一个系统,说明了内存的虚拟视图和物理视图。在单个系统中,不同的处理器和/或设备可能具有不同的虚拟和物理地址映射,例如,一些多核板和 PCI 设备。
当 MMU 被禁用时,所有虚拟地址直接映射到相应的物理地址(平坦映射)。如果 MMU 无法转换某个地址,它会在处理器上生成中止异常,并向处理器提供有关问题的信息。此功能可用于按需映射内存或设备,一次映射一页。
9.1 Virtual memory
MMU 使您能够构建具有多个虚拟地址映射的系统。每个任务可以拥有自己的虚拟内存映射。操作系统内核将每个应用程序的代码和数据放置在物理内存中,但应用程序本身不需要知道其位置。
MMU 执行的地址转换是通过转换表进行的。这些是由软件在内存中创建的树状表数据结构,MMU 硬件通过遍历这些结构来完成虚拟地址转换。
注意:在 ARM 架构中,通用计算机术语中称为页表的概念具有更具体的含义。ARM 架构使用多级页表,并将转换表定义为所有这些的通用术语。转换表中的每个条目包含将虚拟内存中的一页转换为物理内存中的一页所需的所有信息。遍历的具体机制和表的格式是由软件配置的,稍后会进行解释。
转换表条目按虚拟地址组织。除了描述该虚拟页到物理页的转换外,它们还提供了该页所需的访问权限和内存属性。
核心生成的地址是虚拟地址。当 MMU 启用时,核心发出的所有内存访问都经过它。MMU 本质上用其他值替换该虚拟地址的最高有效位,以生成物理地址(有效地定义一块内存的基地址)。相同的转换表用于定义适用于指令获取和数据访问的转换及内存属性。MMU 内部的专用硬件使其能够读取内存中的转换表。这个过程称为转换表遍历。
9.1.1 Configuring and enabling the MMU
在启用 MMU 之前,必须将转换表写入内存。TTBR 寄存器必须设置为指向这些表。接下来可以使用以下代码序列来启用 MMU:
在启用 MMU 时,如果改变了当前正在执行代码的区域的地址映射,则必须谨慎处理。可能需要设置屏障以确保正确操作。
9.2 The Translation Lookaside Buffer
备缓冲区(TLB)是 MMU 中最近执行的页翻译的缓存。在进行内存访问时,MMU 首先检查该翻译是否已缓存于 TLB 中。如果请求的翻译可用,则发生 TLB 命中,TLB 会立即提供物理地址的翻译。如果 TLB 中没有该地址的有效翻译,则发生 TLB 未命中,需要进行外部转换表遍历。新加载的翻译可以被缓存到 TLB 中以便可能的重用。
TLB 的具体结构在不同的 ARM 处理器实现之间有所不同。以下是一个典型系统的描述,但具体实现可能会有所不同。TLB 中有一个或多个微 TLB,它们位于指令和数据缓存附近。与微 TLB 中命中的条目对应的地址无需额外的内存查找,也不会产生周期惩罚。然而,微 TLB 的映射数量很少,通常在指令侧有八个,在数据侧也有八个。这一结构由一个更大的主 TLB 支持(通常有 64 个条目),但在微 TLB 未命中而主 TLB 命中的情况下,访问可能会产生一些惩罚。下图显示了每个 TLB 条目包含物理地址和虚拟地址,还包括属性(如内存类型、缓存策略和访问权限)以及可能的地址空间标识符(ASID)值。
TLB 类似于其他缓存,因此具有 TLB 行替换策略,但这对用户来说实际上是透明的。如果转换表条目是有效的,则整个页或段的虚拟地址、物理地址和其他属性将作为 TLB 条目存储。如果转换表条目无效,则 TLB 不会被更新。ARM 架构要求 TLB 中只缓存有效的转换表描述符。
9.2.1 TLB coherency
当操作系统更改转换表条目时,TLB 可能会包含过时的转换信息。操作系统必须采取措施使 TLB 条目失效。CP15 提供了多种操作,可以全局使 TLB 失效或删除特定条目。由于推测性指令获取和数据读取可能会导致转换表访问,因此在更改有效的转换表条目时,使 TLB 失效是至关重要的。无效的转换表条目不能缓存到 TLB 中,因此可以在不使其失效的情况下进行更改。
Linux 内核有多个函数使用这些 CP15 操作,包括 flush_tlb_all() 和 flush_tlb_range()。这些函数通常不被设备驱动程序所需要。
9.3 Choice of page sizes
页大小基本上由操作系统控制,但在选择大小时值得注意相关考虑。较小的页大小可以更精细地控制内存块,并可能减少页中的未使用内存量。如果一个任务需要 7KB 的数据空间,分配两个 4KB 页相比于分配一个 64KB 页或一个 1MB 段,会有更少的未使用空间。较小的页大小还允许对权限、缓存属性等进行更细致的控制。
然而,随着页大小的增加,TLB 中的每个条目将引用更大块的内存。因此,任何访问都更可能发生 TLB 命中,从而减少对外部内存的转换表访问。出于这个原因,可以将 16MB 超区用于不需要详细映射的大块内存。此外,每个 L2 转换表需要 1KB 的内存。
9.4 First level address translation
考虑在 ARM 核心上使用一级转换表条目将虚拟地址转换为物理地址的过程。第一步是定位与虚拟地址关联的转换表条目。
转换的第一阶段使用单个一级转换表,有时称为主转换表。L1 转换表将 32 位核心的完整 4GB 地址空间分为 4096 个相等大小的部分,每个部分描述 1MB 的虚拟内存空间。因此,L1 转换表包含 4096 个 32 位(字大小)条目。
每个条目可以保存指向二级转换表基地址的指针,或者用于转换 1MB 部分的转换表条目。如果转换表条目正在转换由编码确定的 1MB 部分,则它提供物理内存中 1MB 页的基地址。
两个地址的低位部分相同(定义从基地址到物理内存的偏移量)。ARM MMU 支持具有两级转换表的多级转换表架构,分别为一级(L1)和二级(L2)。除非实现了大物理地址扩展,否则 L1 和 L2 转换表都使用短描述符转换表格式,具有以下特征:
L1 转换表的基地址称为转换表基地址,存储在 CP15 c2 中。它必须对齐到 16KB 边界。转换表位置由转换表基寄存器(TTRB0 和 TTRB1)定义。
当 MMU 执行转换时,请求的虚拟地址的高 12 位作为转换表的索引。
以一个简单的例子为例,如上图所示,假设 L1 转换表存储在地址 0x12300000。处理器发出虚拟地址 0x00100000。高 12 位 [31:20] 定义了正在访问的 1MB 虚拟地址空间。在这种情况下是 0x001,因此 MMU 必须读取表条目 1。要获取表中的偏移量,必须将条目编号乘以条目大小:0x001 * 4 字节 = 偏移地址 0x004 MMU 从中读取物理地址的条目的地址为 0x12300000 + 0x004 = 0x12300004。现在您已经确定了转换表条目的位置,可以用它来确定物理内存地址。图 9-5 显示了 CP15 c2 中 L1 转换表条目的格式。
一级转换表包含一级描述符。L1 转换表条目可以是四种可能类型之一:
1MB 段转换条目,将 1MB 区域映射到物理地址。
指向 L2 转换表的条目。这使得 1MB 的内存可以细分为多个页。
16MB 超区。这是一种特殊类型的 1MB 段条目,需要在转换表中占用 16 个条目,但可以减少为该区域分配的转换后备缓冲区中的条目数量。
生成中止异常的错误条目。这可以是预取中止或数据中止,具体取决于访问类型。这有效地指示未映射的虚拟地址。
条目中最低的两个有效位 [1:0] 定义了该条目是错误条目、转换表条目还是段条目。位 [18] 用于区分普通段和超区。
超区是 16MB 的一块内存,其虚拟和物理基地址都必须对齐到 16MB 边界。由于 L1 转换表条目每个描述 1MB,因此需要在表中连续的 16 个相同条目来标记一个超区。在第 9-6 页中关于页大小的选择说明了超区的实用性。
下图显示了最简单的情况,其中 1MB 段的物理地址直接由 L1 转换表中单个条目的内容生成。
段(或超区)的转换表条目包含用于转换虚拟地址的物理基地址。转换表条目中还包含许多其他位,包括访问权限(AP)和可缓存(C)或可缓冲(B)类型。这是访问相应物理地址所需的所有信息,在这些情况下,MMU 不需要查看 L1 表以外的内容。
下图总结了由 L1 转换表中的段条目翻译的地址的转换过程。
在 1MB 内存段的转换表条目中,转换表条目的高 12 位在生成物理地址时替代虚拟地址的高 12 位。
9.5 Level 2 translation tables
L2 转换表有 256 个字大小(4 字节)的条目,需占用 1KB 的内存空间,并且必须对齐到 1KB 边界。每个条目将 4KB 的虚拟内存块转换为物理内存中的 4KB 块。转换表条目可以提供 4KB 或 64KB 页的基地址。
L2 转换表中使用三种类型的条目,具体由条目中最低的两个有效位的值来识别:
下图显示了 L2 转换表条目的格式。
与 L1 转换表条目一样,L2 转换表条目也给出了物理地址,以及有关页面的其他信息。类型扩展(TEX)、可共享(S)和访问权限(AP、APX)位用于指定 ARMv7 内存模型所需的属性。与 TEX 一起,C 和 B 位控制由转换表条目管理的内存的缓存策略。nG 位定义该页面是全局(适用于所有进程)还是非全局(仅用于特定进程)。
在上图,我们看到所需的 L2 转换表条目的地址是通过取 L2 转换表的基地址(由 L1 转换表条目给出,已对齐到 1KB)并使用虚拟地址的 8 位(位 [19:12])在 L2 转换表的 256 个条目中进行索引来计算的。
下图总结了使用两层转换表时的地址转换过程。虚拟地址的位 [31:20] 用于索引 4096 个条目的 L1 转换表,其基地址由 CP15 TTB 寄存器给出。L1 转换表条目指向一个包含 256 个条目的 L2 转换表。虚拟地址的位 [19:12] 用于选择其中一个条目,该条目随后提供页面的基地址。最终的物理地址通过将该基地址与虚拟地址的剩余位结合生成。
9.6 Memory attributes
我们已经看到转换表条目如何使 MMU 硬件将虚拟地址转换为物理地址。然而,它们还指定了与每个页面相关的一些属性,包括访问权限、内存类型和缓存策略。
9.6.1 Memory Access Permissions
转换表条目中的访问权限(AP 和 APX)位给出了页面的访问权限。请参见下表。
没有必要权限的访问(或发生错误)将被中止。在数据访问中,这将导致精确的数据中止异常。在指令获取时,访问将标记为中止,如果在执行之前该指令没有被刷新,将会发生预取中止异常。由外部访问生成的错误通常不会是精确的。
关于错误位置的地址和错误原因的信息存储在 CP15 中(错误地址和错误状态寄存器)。然后,中止处理程序可以采取适当的措施,例如修改转换表以解决问题,然后返回到应用程序重试访问。或者,生成中止的应用程序可能存在问题,必须终止。
9.6.2 Memory types
早期的 ARM 架构版本允许通过配置缓存和写缓冲区是否可以用于特定位置来指定页面的内存访问行为。这种简单的方案不足以满足今天更复杂的系统和处理器的需求,在这些系统中,可以有多个级别的缓存、在多个共享内存的处理器之间进行硬件管理的连贯性,以及能够进行指令和数据的推测性获取的处理器。ARMv6 和 ARMv7 架构中新增的内存类型旨在满足这些要求。
ARM 架构定义了三种相互排斥的内存类型。所有内存区域均配置为这三种类型之一:
这些用于描述内存区域。内存类型的总结见下表。
下表显示了转换表条目中的 TEX、C 和 B 位如何用于设置页面的内存类型以及使用的缓存策略。
表中的最后一个条目需要更多解释。对于普通可缓存内存,TEX 字段的两个最低有效位用于提供外部缓存策略(可能是针对第 2 或第 3 级缓存),而 C 和 B 位则给出内部缓存策略(针对第 1 级缓存和任何其他被视为内部缓存的缓存)。这使您能够为内部和外部缓存指定不同的缓存策略。对于 Cortex-A15 和 Cortex-A8 处理器,转换表条目设置的内部缓存属性适用于 L1 和 L2 缓存。在一些较旧的处理器上,外部缓存可能支持写分配,而 L1 缓存可能不支持。当然,这些处理器在运行请求此缓存策略的代码时仍必须正确运行。
9.6.3 Execute Never
当设置时,转换表条目的执行不可(XN)位会阻止从特定内存位置进行推测性指令获取,如果尝试从该内存位置执行,将导致发生预取中止。通常,设备内存区域会标记为不可执行,以防止意外从这些位置执行,并防止可能由推测性指令获取引发的不良副作用。
9.6.4 Domains
ARM 架构有一个独特的特性,允许将内存区域标记为域 ID。硬件提供了 16 个域 ID,CP15 c3 中包含域访问控制寄存器(DACR),该寄存器保存每个域号的 2 位权限集合。这使得每个域可以标记为无访问、管理模式或客户端模式。无访问会导致对该域中任何页面的访问中止,无论页面权限如何。管理模式会忽略所有页面权限,允许完全访问。客户端模式则使用标记为该域的页面的权限。
注意 :
在 ARMv7 架构中,域的使用已被弃用,最终会被移除,但为了强制执行访问权限,仍然需要将域号分配给一个段,并确保该域的权限位设置为客户端。通常,您会将所有域 ID 字段设置为 0,并将 DACR 中的所有字段设置为“客户端”。
9.7 Multi-tasking and OS usage of translation tables
在使用 Cortex-A 系列处理器的大多数系统中,您将会有多个应用程序或任务同时运行。每个任务可以在物理内存中拥有自己独特的转换表。通常,内存系统的组织方式是虚拟地址到物理地址的映射是固定的,转换表条目不会改变。这通常用于包含操作系统代码和数据,以及各个任务使用的转换表。
每当启动一个应用程序时,操作系统会为其分配一组转换表条目,以将应用程序使用的代码和数据映射到物理内存中。如果应用程序需要映射代码或额外的数据空间(例如通过 malloc() 调用),内核可以随后修改这些表。当一个任务完成且应用程序不再运行时,内核可以移除任何关联的转换表条目,并将空间重新用于新的应用程序。通过这种方式,多个任务可以驻留在物理内存中。在任务切换时,内核会切换到下一个要运行的线程的转换表条目。此外,处于休眠状态的任务完全受到运行任务的保护。这意味着 MMU 可以防止运行任务访问其他任务的代码或数据。
9.7.1 Address Space ID
当我们描述第二级转换表中的转换表位时,提到了一个称为 nG(非全局)的位。如果某个页面的 nG 位被设置,则该页面与特定应用程序相关联。当 MMU 执行转换时,它同时使用虚拟地址和 ASID 值。
ASID 是操作系统分配给每个任务的一个数字,该值的范围是 0-255,当前任务的值存储在 ASID 寄存器中(通过 CP15 c13 访问)。当 TLB 被更新且条目被标记为非全局时,ASID 值将与正常的转换信息一起存储在 TLB 条目中。后续的 TLB 查找仅在当前 ASID 与存储在条目中的 ASID 匹配时才会匹配。因此,对于特定页面(标记为非全局),您可以有多个有效的 TLB 条目,但 ASID 值不同。这显著减少了上下文切换的软件开销,因为它避免了刷新片上 TLB 的要求。ASID 是一个更大的(32 位)进程 ID 寄存器的一部分,可用于任务感知的调试。
注意
上下文切换指的是调度程序将执行从一个进程转移到另一个进程。这通常需要保存当前进程的状态,并恢复下一个等待运行的进程的状态。
下图明了这一点。在这里,您有多个应用程序(A、B 和 C),每个应用程序都链接到虚拟地址 0 运行。每个应用程序在物理内存中位于一个独立的地址空间中。与每个应用程序相关联的 ASID 值使您在任何特定时间都可以在 TLB 中拥有多个条目,这些条目对虚拟地址 0 是有效的。
9.7.2 Translation Table Base Register 0 and 1
管理多个应用程序及其各自的转换表时,另一个潜在的困难是可能存在多个 L1 转换表,每个应用程序一个。这些表的大小都是 16KB。大多数条目在每个表中都是相同的,因为通常只有一块内存区域是特定于任务的,而内核空间在每种情况下都是不变的。此外,如果要修改全局转换表条目,则需要在每个表中进行更改。
为帮助减少这些问题的影响,提供了第二个转换表基址寄存器。CP15 包含两个转换表基址寄存器,TTBR0 和 TTBR1。一个控制寄存器(TTB 控制寄存器)用于编程一个范围在 0 到 7 之间的值。该值(用 N 表示)告诉 MMU 需要检查虚拟地址的高位有多少位,以确定使用哪个 TTB 寄存器。
当 N 为 0(默认值)时,所有虚拟地址都使用 TTBR0 进行映射。当 N 在 1-7 的范围内时,硬件查看虚拟地址的最高有效位。如果 N 个最高有效位都是零,则使用 TTBR0;否则使用 TTBR1。
例如,如果 N 设置为 7,那么内存底部的 32MB 地址将使用 TTBR0,而其余内存将使用 TTBR1。因此,指向 TTBR0 的应用程序特定转换表将仅包含 32 个条目(128 字节)。全局映射则在指向 TTBR1 的表中,只需维护一个表。
当使用这些功能时,进行上下文切换通常需要操作系统通过 CP15 指令更改 TTBR0 和 ASID 值。然而,由于这两个操作是独立的、非原子性的,因此需要小心,以避免使用一个寄存器的新值与另一个寄存器的旧值共同发生投机访问的问题。使用这些功能的操作系统程序员应熟悉 ARM 架构参考手册中建议的顺序。
9.7.3 The Fast Context Switch Extension
快速上下文切换扩展(FCSE)是在 ARMv4 架构中添加的,但自 ARMv6 起已被弃用。它允许多个独立任务在虚拟内存空间底部的固定重叠区域运行,而无需在上下文切换时清理缓存或 TLB。它通过将进程 ID 值替换到虚拟地址的最高七位来修改虚拟地址(但仅在该地址位于底部 32MB 内存时)。一些 ARM 文档将修改后的虚拟地址(MVA)与虚拟地址(VA)区分开。这种区分在使用 FCSE 时是有用的。
(广告时间)
Arm架构类课程:
安全热销大课程:
安全类经典课程:
其它课程:
铂金VIP课程介绍
之最介绍
招牌课程:Truszone标准版、Trustzone高配版
销量前三课程:ARM三期、Secureboot、Android15安全架构
持续更新的课程:ARM三期、铂金VIP
非常好非常好但又被忽视的课程:CA/TA开发
近期更新/力推的课程/重点课程:optee系统架构从入门到精通
说点心里话:
1、不要再说课贵了,你看看咱这是啥课?别家的能比不?请不要拿通用的linux、android、python、C语言和咱这专业课比。
2、咱们的VIP是数十门课程的集合。不要拿别人一门课程的价格对标咱这20门课程价格。
3、这些知识很多人都会,但能拿出来讲的有多少人? 愿意拿出来讲的有多少人?会讲的又有多少人?
4、价格都是认真计算的,并非随意定价。都是根据内容质量、核心知识点、时长和节数计算而来。从来不无缘无故涨价(涨价是需要理由的,如课程内容增加了....)。咱靠的是内容质量和长期服务,而不是运营和营销(无脑涨价)。
5、如果你刷到此处,可能是老粉/铁粉,记得点赞、评论哦。感谢您的支持。