我最近了解了行锤攻击。为了执行这种攻击,程序员需要为特定数量的地址刷新 CPU 的完整缓存层次结构。
我的问题是:为什么在 x86 中需要CLFLUSH?如果所有 L* 缓存都透明地运行(即不需要显式缓存失效),那么使用该指令的原因是什么?除此之外:CPU 不是可以自由推测内存访问模式,从而完全忽略指令吗?
我认为主要用例是非易失性 DIMM,尤其是英特尔的 Optane DC PM。它通常映射为 WB-cacheable,因此需要显式刷新(或movnt
)以确保数据持久保存到非易失性存储中。
(但clflush
与 SSE2 同时引入,早在 Pentium 4 天。我不知道那里的想法是什么;可能出于性能原因显式缓存控制,例如与预取相反。)
Skylake 引入了弱排序的高性能 CLFLUSHOPT,因为它对于直接连接到内存层次结构的非易失性存储很有用。刷新缓存确保数据写入实际内存,而不是在 CPU 中仍然脏。
另请参阅此SuperUser 答案,了解有关 Optane DC PM(持久内存)的一些链接和背景。它是物理地址空间中的非易失性存储,而不仅仅是具有软件技巧的虚拟地址空间中。
Dan Luu 的文章clwb
很pcommit
有趣:让操作系统不妨碍访问存储的好处,详细介绍了英特尔当时针对 clflush / clwb 及其内存排序语义的计划。它是在英特尔仍计划在pcommit
此过程中需要一条名为(持久提交)的指令时编写的,但英特尔后来决定删除该指令:Deprecating the PCOMMIT Instruction (from Intel)有一些有趣的信息,关于为什么以及如何事情在引擎盖下工作。
如果在 x86 中可以做到这一点,它对于设备的非缓存一致 DMA 也可能很重要。(但 x86 一直有缓存一致的 DMA,因为第一个带有缓存的 x86 CPU,以避免破坏现有软件。)
显然,不可能将 MMIO / PCIe 设备内存区域映射为可写回 (WB) 缓存。 如何为可缓存的 PCIe BAR 做 mmap 可能 P4 架构师在引入它时正在考虑这种未来的可能性。
在之前的链接中,Bandwidth 博士提到了一个部分解决方法,实际上需要 CLFLUSH 来保持正确性:
将 MMIO 范围映射两次——一次用于使用写组合 (WC) 存储器类型从处理器到 FPGA 的存储操作,一次用于使用写保护 (WP) 或直写 (WT) 从处理器读取到 FPGA ) 类型。当您在“只写”区域中写入该行的别名时,您将需要通过在“只读”区域中的缓存行上使用 CLFLUSH 手动保持一致性。
因此,除了 NV-DIMM 之外,您可能还需要 clflush。