英特尔的手册3A,第11.5.3节提供了一个算法来全局禁用缓存:
11.5.3 防止缓存
在启用并填充缓存之后,要禁用L1、L2和L3缓存,请执行以下步骤:
- 进入无填充缓存模式。(将控制寄存器CR0中的CD标志设置为1且NW标志设置为0)。
- 使用WBINVD指令刷新所有缓存。
- 禁用MTRRs并将默认内存类型设置为不带缓存,或将所有MTRRs设置为不带缓存的内存类型(有关TYPE字段和E标志的讨论,请参见第11.11.2.1节,“IA32_MTRR_DEF_TYPE MSR”的讨论)。
必须在设置CD标志后刷新缓存(步骤2),以确保系统内存一致性。如果不刷新缓存,则读取时会发生缓存命中,并且数据将从有效的缓存行中读取。
上述三个单独步骤的意图分别解决了三个不同的要求:(i)停止新数据替换缓存中的现有数据(ii)确保缓存中已有的数据被逐出到内存,(iii)确保随后的内存引用遵循UC内存类型语义。不同处理器实现的缓存控制硬件可能允许对这三个要求进行某些软件实现的变化。见下面的注释。
注释
在控制寄存器CR0中设置CD标志会修改处理器的缓存行为,如表11-5所示,但仅设置CD标志可能不足以跨所有处理器系列强制使所有物理内存的有效内存类型为UC,也不能强制执行严格的内存顺序,由于不同处理器系列之间的硬件实现差异。要在所有物理内存上强制使用UC内存类型和严格的内存顺序,可以将所有物理内存的MTRRs编程为UC内存类型或禁用所有MTRR。
对于Pentium 4和Intel Xeon处理器,在执行上述步骤序列之后,包含WBINVD指令结束前和MTRRS禁用之前的代码的缓存行实际上可能仍保留在缓存层次结构中。为了完全从缓存中删除代码,必须在禁用MTRRs之后执行第二个WBINVD指令。
这是一段冗长的引用,但归结为以下代码:
mov eax, cr0
or eax, 1<<30
and eax, ~(1<<29)
mov cr0, eax
wbinvd
xor eax, eax
xor edx, edx
mov ecx, IA32_MTRR_DEF_TYPE
wrmsr
wbinvd
大部分代码不可从用户模式执行。
AMD手册2在第7.6.2节中提供了一个类似的算法。
7.6.2缓存控制机制
AMD64架构提供了许多控制内存可缓存性的机制。这些机制在以下各节中描述。
缓存禁用。CR0寄存器的第30位是缓存禁用位,CR0.CD。当CR0.CD被设置为1时,禁用缓存;当CR0.CD清除为0时,则启用缓存。禁用缓存时,读取和写入将直接访问主存。
即使在缓存仍然保存有效数据(或指令)时,软件也可以禁用缓存。如果CR0.CD=1时,读取或写入命中L1数据缓存或L2缓存,处理器会执行以下操作:
- 如果缓存行处于修改或拥有状态,则将缓存行写回。
- 使缓存行失效。
- 执行非可缓存的主存访问以读取或写入数据。
如果指令获取命中L1指令缓存时,CR0.CD=1,某些处理器型号可能会读取缓存指令而不是访问主存。当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的代码非常相似):
mov eax, cr0
or eax, 1<<30
mov cr0, eax
wbinvd
xor eax, eax
xor edx, edx
mov ecx, MTRRdefType
wrmsr
缓存也可以在以下情况下进行选择性禁用:
- 页面级别,使用属性位PCD(页面缓存禁用)[仅适用于Pentium Pro和Pentium II]。
当两者均未设置时,相关的MTTR将被使用。如果PCD被设置,则不进行缓存。
- 页面级别,使用PAT(页面属性表)机制。
通过将IA32_PAT
填充为缓存类型并使用PAT、PCD、PWT位作为3位索引,可以选择六种缓存类型之一(UC-、UC、WC、WT、WP、WB)。
- 使用MTTR(固定或可变)。
将缓存类型设置为UC或UC-以针对特定的物理区域。
其中,只有页面属性选项可以暴露给用户模式程序(例如请参阅此处)。