繁体   English   中英

如何在现代 x86/amd64 芯片上关闭 L1、L2、L3 CPU 缓存?

[英]How can the L1, L2, L3 CPU caches be turned off on modern x86/amd64 chips?

x86/x86_64 架构的每个现代高性能 CPU 都有一些数据缓存层次结构:L1、L2,有时还有 L3(在极少数情况下是 L4),从主 RAM 加载/向主 RAM 加载的数据缓存在其中一些缓存中。

有时程序员可能希望某些数据不缓存在某些或所有缓存级别(例如,当想要 memset 16 GB 的 RAM 并将某些数据仍在缓存中时):有一些非临时 (NT) 指令用于这就像 MOVNTDQA ( https://stackoverflow.com/a/37092 http://lwn.net/Articles/255364/ )

但是是否有一种编程方式(对于某些 AMD 或 Intel CPU 系列,如 P3、P4、Core、Core i* 等)来完全(但暂时)关闭部分或所有级别的缓存,以更改每个 memory访问指令(全局或对于 RAM 的某些应用程序/区域)使用 memory 层次结构? 例如:关闭L1,关闭L1和L2? 或者将每个 memory 访问类型更改为“未缓存”UC(CR0 的 CD+NW 位??? SDM vol3a 第423 424、425页和“第三级缓存禁用标志, IA32_MISC_ENABLE MSR 的第 6 位(仅适用于基于Intel NetBurst 微架构)— 允许禁用和启用 L3 缓存,独立于 L1 和 L2 缓存。”)。

我认为这样的行动将有助于保护数据免受缓存侧通道攻击/泄漏,例如窃取 AES 密钥、隐蔽缓存通道、Meltdown/Spectre。 尽管这种禁用将产生巨大的性能成本。

PS:我记得很多年前在某个技术新闻网站上发布过这样的程序,但现在找不到了。 它只是一个 Windows exe 将一些神奇的值写入 MSR 并让每个 Windows 程序在它之后运行非常慢。 缓存被关闭,直到重新启动或使用“撤消”选项启动程序。

英特尔手册 3A 的第 11.5.3 节提供了一种全局禁用缓存的算法:

11.5.3 防止缓存

要在启用并收到缓存填充后禁用 L1、L2 和 L3 缓存,请执行以下步骤:

  1. 进入无填充缓存模式。 (将控制寄存器 CR0 中的 CD 标志设置为 1,将 NW 标志设置为 0。
  2. 使用 WBINVD 指令刷新所有缓存。
  3. 禁用 MTRR 并将默认内存类型设置为未缓存或为未缓存的内存类型设置所有 MTRR(请参阅第 11.11.2.1 节“IA32_MTRR_DEF_TYPE MSR”中对 TYPE 字段和 E 标志的讨论)。

设置 CD 标志后必须刷新缓存(步骤 2)以确保系统内存一致性。 如果缓存未刷新,读取时仍会发生缓存命中,并且将从有效缓存行读取数据。

上面列出的三个独立步骤的意图解决了三个不同的要求:(i) 停止用新数据替换缓存中的现有数据 (ii) 确保将缓存中已有的数据驱逐到内存中,(iii) 确保后续内存引用观察 UC 内存类型语义。 缓存控制硬件的不同处理器实现可能允许这三个要求的软件实现的一些变化。 请参阅下面的注释。

注意在控制寄存器 CR0 中设置 CD 标志会修改处理器的缓存行为,如表 11-5 所示,但单独设置 CD 标志可能不足以在所有处理器系列中强制所有物理内存的有效内存类型为 UC 或由于不同处理器系列的硬件实现差异,它是否会强制执行严格的内存排序。 要在所有物理内存上强制使用 UC 内存类型和严格的内存排序,将所有物理内存的 MTRR 编程为 UC 内存类型或禁用所有 MTRR 就足够了。

对于奔腾 4 和英特尔至强处理器,在执行上述步骤序列后,包含 WBINVD 指令结束和 MTRRS 实际禁用之前的代码的缓存行可能会保留在缓存层次结构中。 此处,要从缓存中完全删除代码,必须在禁用 MTRR 后执行第二条 WBINVD 指令。

这是一个很长的引用,但归结为这段代码

;Step 1 - Enter no-fill mode
mov eax, cr0
or eax, 1<<30        ; Set bit CD
and eax, ~(1<<29)    ; Clear bit NW
mov cr0, eax

;Step 2 - Invalidate all the caches
wbinvd

;All memory accesses happen from/to memory now, but UC memory ordering may not be enforced still.  

;For Atom processors, we are done, UC semantic is automatically enforced.

xor eax, eax
xor edx, edx
mov ecx, IA32_MTRR_DEF_TYPE    ;MSR number is 2FFH
wrmsr

;P4 only, remove this code from the L1I
wbinvd

其中大部分不能从用户模式执行。


AMD 的手册 2在第 7.6.2 节中提供了类似的算法

7.6.2 缓存控制机制
AMD64 架构提供了许多用于控制内存可缓存性的机制。 这些将在以下部分中描述。

缓存禁用 CR0 寄存器的第 30 位是缓存禁用位 CR0.CD。 CR0.CD 清零时启用缓存,CR0.CD 设置为1 时禁用缓存。禁用缓存时,读取和写入访问主内存。

软件可以在缓存仍然保存有效数据(或指令)时禁用缓存。 如果在 CR0.CD=1 时读取或写入命中 L1 数据缓存或 L2 缓存,则处理器执行以下操作:

  1. 如果缓存行处于已修改或拥有状态,则将其写回。
  2. 使缓存行无效。
  3. 执行不可缓存的主内存访问以读取或写入数据。

如果在 CR0.CD=1 时指令获取命中 L1 指令缓存,则某些处理器型号可能会读取缓存的指令而不是访问主内存。 当 CR0.CD=1 时,L2 和 L3 缓存的确切行为取决于模型,并且可能因不同类型的内存访问而异。

当 CR0.CD=1 时,处理器也会响应缓存探测。 命中缓存的探测会导致处理器执行第 1 步。仅当代表内存写入或独占读取执行探测时,才会执行第 2 步(缓存行失效)。

直写禁用 CR0 寄存器的第 29 位是非直写禁用位 CR0.NW。 在早期的 x86 处理器中,CR0.NW 用于控制缓存直写行为,CR0.NW 和 CR0.CD 的组合决定了缓存操作模式。

[...]

在 AMD64 架构的实现中,CR0.NW 不用于限定由 CR0.CD 建立的缓存操作模式。

这转化为以下代码(与英特尔的非常相似):

;Step 1 - Disable the caches
mov eax, cr0
or eax, 1<<30
mov cr0, eax

;For some models we need to invalidated the L1I
wbinvd

;Step 2 - Disable speculative accesses
xor eax, eax
xor edx, edx
mov ecx, MTRRdefType  ;MSR number is 2FFH
wrmsr

缓存也可以在以下位置有选择地禁用:

  • 页面级别,具有属性位 PCD(页面缓存禁用)[仅适用于 Pentium Pro 和 Pentium II]。
    当两者都清楚时,使用相关的 MTTR,如果设置了 PCD,则疼痛
  • 页面级别,具有PAT(页面属性表)机制。
    通过使用缓存类型填充IA32_PAT并使用位 PAT、PCD、PWT 作为 3 位索引,可以选择六种缓存类型(UC-、UC、WC、WT、WP、WB)之一。
  • 使用 MTTR(固定或可变)。
    通过将特定物理区域的缓存类型设置为 UC 或 UC-。

在这些选项中,只有页面属性可以暴露给用户模式程序(例如参见this )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM