x86 / x86_64体系结构的每个现代高性能CPU都有一些数据高速缓存层次结构:L1,L2,有时甚至是L3(在极少数情况下,甚至是L4),从/向主RAM加载的数据也被高速缓存在其中一些中。
有时,程序员可能希望某些数据不缓存在某些或所有缓存级别中(例如,当要内存16 GB的RAM并将某些数据保留在缓存中时):对于某些非临时性(NT)指令,就像MOVNTDQA(https://stackoverflow.com/a/37092 http://lwn.net/Articles/255364/)
但是,是否有一种编程方式(对于某些AMD或Intel CPU系列,如P3,P4,Core,Core i *等)完全(但暂时)关闭部分或所有级别的缓存,以更改每个内存的方式访问指令(全局或某些应用程序/ RAM区域)使用内存层次结构?例如:关闭L1,关闭L1和L2?或将每种内存访问类型更改为“未缓存的” 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程序运行起来非常慢。缓存将一直关闭,直到重新启动或使用“撤消”选项启动程序为止。
最佳答案
The Intel's manual 3A,第11.5.3节提供了一种全局禁用高速缓存的算法:
11.5.3防止缓存
要在启用L1,L2和L3高速缓存并收到高速缓存填充后禁用它们,请执行以下步骤:
进入无填充缓存模式。 (将控制寄存器CR0中的CD标志设置为1,将NW标志设置为0。
使用WBINVD指令刷新所有缓存。
禁用MTRR,并将默认内存类型设置为未缓存,或将所有MTRR设置为未缓存的内存
类型(请参见第11.11.2.1节中有关TYPE字段和E标志的讨论,
“ IA32_MTRR_DEF_TYPE MSR”)。
设置CD标志后,必须清除缓存(第2步)以确保系统内存一致性。如果缓存是
如果不刷新,仍将发生读取时缓存命中,并且将从有效缓存行读取数据。
上面列出的三个单独步骤的目的是解决三个不同的要求:(i)中断新数据
替换缓存中的现有数据(ii)确保已经将缓存中的数据逐出到内存中,(iii)确保后续的内存引用遵守UC内存类型语义。不同处理器的缓存实现
控制硬件可以允许这三个要求的软件实现有所不同。请参阅下面的注释。
笔记
设置控制寄存器CR0中的CD标志会修改处理器的缓存行为,如下所示
在表11-5中,但仅设置CD标志可能不足以在所有处理器系列中
强制所有物理内存的有效内存类型为UC也不强制使用严格的内存
由于不同处理器系列之间硬件实现的差异而导致订购。强迫
UC内存类型和所有物理内存上严格的内存顺序,只要满足
将所有物理内存的MTRR编程为UC内存类型或禁用所有MTRR。
对于Pentium 4和Intel Xeon处理器,在完成上述步骤后
执行时,高速缓存行包含WBINVD指令的末尾与
在实际禁用MTRRS之前,可以将其保留在缓存层次结构中。在这里,要从缓存中完全删除代码,必须在执行完之后再执行第二条WBINVD指令。
MTRR已被禁用。
那是一个很长的报价,但归结为这段代码
;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's manual 2在7.6.2节中提供了类似的算法
7.6.2缓存控制机制
AMD64体系结构提供了许多用于控制内存的可缓存性的机制。这些将在以下各节中进行描述。
缓存禁用。 CR0寄存器的第30位是禁用缓存的位CR0.CD。启用缓存
当CR0.CD清除为0时,并且当CR0.CD设置为1时禁用缓存。
禁用,读写访问主存储器。
当缓存仍保留有效数据(或指令)时,软件可以禁用缓存。如果读或写
当CR0.CD = 1时,命中L1数据高速缓存或L2高速缓存,处理器将执行以下操作:
如果高速缓存行处于修改或拥有状态,则将其写回。
使高速缓存行无效。
执行不可缓存的主内存访问以读取或写入数据。
如果在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建立的模式。
这将转换为以下代码(非常类似于Intel的代码):
;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)。