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

时间:2018-01-20 19:26:43

标签: x86 intel cpu-cache memory-access msr

x86 / x86_64架构的每个现代高性能CPU都有一些数据缓存层次结构:L1,L2,有时是L3(在极少数情况下是L4),从/到主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 *,......)完全(但暂时)关闭部分或全部级别的缓存,以进行更改每个内存访问指令(全局或某些应用程序/ RAM区域)如何使用内存层次结构?例如:关闭L1,关闭L1和L2?或者将每个内存访问类型更改为“未缓存”UC(CR0的CD + NW位??? SDM vol3a页423 424425和“三级缓存禁用标志,IA32_MISC_ENABLE MSR的第6位(仅在基于英特尔NetBurst微体系结构的处理器中可用) - 允许禁用和启用L3缓存,独立于L1和L2缓存。“)。

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

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

1 个答案:

答案 0 :(得分:10)

The Intel's manual 3A,第11.5.3节,提供了全局禁用缓存的算法:

  

11.5.3防止缓存

     

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

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

    在设置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高速缓存,处理器执行以下操作:

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

    如果在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)。