页面着色是为 MMU 分配页面的一种技巧,以便让页面以特定的顺序保存在缓存中。这种技巧有时用作优化(也不是专用于 ARM);但作为缓存架构的结果,有些 ARMv6 处理器实际上要求分配程序使用一些页面着色。部分 ARMv7 处理器也有相关(尽管没那么严格)的限制。本文将阐述为何缓存架构要施加这一限制,以及它在实践中意味着什么。 请注意,极少情况下才需要在内核中的物理内存分配程序(或其他特权短代码)之外考虑此限制。典型的用户空间代码或许不必直接对此进行处理,但理解页面着色有所帮助,例如可以解释为何某些 mmap 调用在 ARMv7 上可行,却在 ARMv6 上失败。 该限制的源头在于许多 ARMv6 处理器使用 VIPT 缓存。VIPT 表示“虚拟索引,物理标记(virtually indexed, physically tagged)”。如果你不熟悉缓存术语,这可能意义不大,但我会试着用举例的方式来说明。 通常情况下,ARMv7 不会受到 ARMv6 页面着色限制的影响。但是,ARMv7 也有 VIPT 指令缓存,因此一些限制依然适用,即使在用户空间中也是如此。 虚拟和物理寻址 请思考处理器需要进行简单内存存取的情形。存取的原因无关紧要;例如,可以是处理器加载要执行的下一指令,或者是加载或存储指令导致的数据传输。不管怎样,我们假设请求的地址是 0x12345678。这是一个虚拟地址,其背后的实际内存中可能有不同的物理地址,而且 MMU()将需要使用分页表来执行该转译。许多操作系统使用这一机制来同时运行多个应用程序,尽管应用程序预期会从同一地址运行:每一应用程序可以认为其入口点位于 0x8000,但物理内存很有可能是不同的。这一过程对用户空间应用程序实际上是透明的。 ARMv6 MMU 中内存映射的最细粒度是 4KB 页面1。虚拟地址的底部 12 位与基础物理地址的底部 12 位完全匹配。这是因为 12 位可以对 4KB 页面中的任何偏移进行寻址(因为 212 = 4096),而且在虚拟和物理内中页面是自然对齐2 的。因此,虚拟地址转译可以按照如下所示查看3:
使用 4KB 页面的 32 位寻址的虚拟到物理地址转译。 为清楚起见,我用绿色来表示虚拟地址部分,用蓝色表示物理地址部分。低 12 位(灰色)通常不会与虚拟和物理部分分开表示,但我已尽量表明它们在转译过程中不会更改,因为此属性与页面着色相关。在本例中,MMU 已配置为将虚拟地址 0x12345678 映射到物理地址 0x9abcd678。 VIPT 缓存查找 理想状态下,内存存取将导致缓存查找,因为缓存存取的速度比内存存取快得多。“VIPT”属性对于缓存查找的运作方式给了一个提示: - 虚拟地址用于构建缓存索引。这就是“VIPT”中“VI”所代表的含义。缓存索引是标记列表中的偏移(或“存储tag的RAM”),其中每个标记与一个缓存行关联,指明该行中缓存了什么内存(若有)。在本例中,每一缓存行保存个字节。
- 虚拟地址转译为物理地址。
- 物理地址用于构建缓存标记。这就是“VIPT”中“PT”所代表的含义。
- 缓存索引用于从缓存中提取标记,将它与从物理地址计算的缓存标记比对。如果匹配,则缓存中“命中”该查找,从缓存中提取相关的数据。否则,将从下一层缓存(或从内存)中提取。
该过程在某种程度上做了简化描述,但对该过程的说明应该已足够了解页面着色。 下图对上述步骤可能有更清晰一些的说明:
VIPT 缓存中简化的缓存查找。 有些有趣的要点值得注意: - 在本例中,字节索引为字节长,因为本例中的缓存行长度为字节,需要位才能对给定缓存行中的每一字节进行寻址。例如,ARM1136 和上就是这样。
- MMU 转译可与缓存行索引查找并行进行。
- 缓存索引中的两个位来自虚拟地址,但缓存索引可以引用的标记则全都从物理地址派生而来。
缓存路数 ARM1136 和 ARM1176 使用 4 路组相联缓存。当内存位置存储在缓存中时,从其地址生成的索引允许其存储在四路中的任意一路。这种机制用来提高缓存效率。我不准备更加深入地阐述缓存路数,但如果你感兴趣的话,维基百科上有不错的介绍(撰写本文时)。 路数对页面着色的影响仅仅在于它们会影响缓存行索引中位的数量。在 4 路 64KB 缓存中(这是 ARM1136 和 ARM1176 的限制),每一路将有 64/4 = 16KB 可寻址空间。因此上图中的缓存显示了单路 16KB 缓存。 VIPT 缓存查找:重复映射问题 如果每个虚拟地址和物理地址之间存在一对一映射,那么上述 VIPT 缓存查找能够完美运作。但事实常常不是这样。即使具体的应用程序没有请求重复的映射,也会由于使用共享内存和操作系统中的管理原因而出现重复映射。请思考物理地址 0x9abcd678 同时映射到 0x12345678 和 0xfedcb678 的情形:
0x12345678 和 0xfedcb678 的缓存行索引。 上图中的两个虚拟地址被配置为映射到我们示例中的同一物理地址。不过,请注意缓存行索引是不同的。因此,有可能相关内存已存在于具有不同虚拟索引的缓存行中。如果缓存行是未清除的(表示数据已被更改并且尚未写到内存中),那么对另一别名所做的更改可能丢失,或者可能会屏蔽原来的更改。这种重复映射甚至不必同时处于活动状态就能造成此问题,因为在分页表更新之后上次活动进程中的一些数据可能依然保存在缓存之中。无论出现什么情况,都不好,所以操作系统必须对内存分配实施页面着色限制。 解决方案:页面着色限制 页面着色为每一内存页面分配一个颜色。颜色可分配给虚拟地址和物理地址,但此处的问题是虚拟地址。(此处的“颜色”用作一种说明工具。)虚拟内存中的每一页面按照顺序被分配一种颜色,如下所示:
页面颜色,表明颜色如何映射到地址的第 12 和 13 位。同时也显示了两个示例虚拟地址,表明它们拥有不同的颜色。 实际选择用于代表各个页面的颜色无关紧要。不过,请注意这两个示例地址拥有不同的颜色。在拥有 4KB 页面和 16KB 缓存路数的示例系统中,虚拟地址的第 12 和第 13 位决定页面颜色。它们是 VIPT 查找示意图中缓存索引所使用的两个位。请注意,这里有四种页面颜色,因为缓存索引中有虚拟地址的两个位,而 22 = 4。 因此,页面着色限制要求页面分配程序将任何给定的物理页面限定到单个虚拟颜色。 |