如何在 x86 上读取陈旧值

How to read stale values on x86

我的目标是在没有缓存一致性的情况下读入陈旧和过时的内存值。我曾尝试使用 prefetchnta 执行非临时加载,但未能获取过时的值。我正在研究执行某种流式内存到内存直接内存访问,但由于继续我当前的项目所需的大量背景知识,我遇到了一些麻烦。目前我正试图弄乱 udmabuf 但即便如此进展缓慢。应该注意的是,理想情况下我想忽略 all CPU 缓存的内容,包括当前的 CPU.

提供我的理由:我正在开发可用于证明为非易失性存储器编写的程序的正确性的软件。由于 CPU 缓存是易失性的,CPU 的回写缓存仍然是易失性的,需要观察它们如何写回内存的任意性。

如果有人能给我一些如何进行的指示,我将不胜感激。我不介意深入研究 Linux 内核,事实上我现在正在这样做,也不介意修改它,我只需要一些正确方向的指导。

我没有玩过这个,但我从文档中了解到,对于加载(与 NT 存储不同),没有什么可以绕过缓存或覆盖内存类型的强排序,如普通 WB(回写) .甚至 NT 存储也会驱逐已经缓存的数据,因此它们不会破坏这个或另一个具有您正在编写的行的缓存数据的核心的一致性。

您可以从 WC(写组合)内存区域(使用 prefetchnta 或 SSE4 movntdqa)执行弱顺序加载,但它们在物理地址级别可能仍然是一致的。

@MargaretBloom 评论

IIRC Intel warns the developer about multiple mapping with different cache types, which may indeed be good in this case.

所以也许您实际上可以通过同一物理页面的多个虚拟映射来绕过缓存一致性。


我不知道是否仍然可以使用 PCI / PCIe 设备执行非一致性 DMA,但这可能是您在不通过缓存的情况下获取实际 DRAM 内容的唯一希望。 (现代 x86 系统上的大多数(?)DMA 是缓存一致的,这对性能有好处并且可能是因为内存控制器内置于 CPU。所以在英特尔 CPU 上,系统代理可以在向内存控制器发送请求的同时窥探 L3 标签,以查看某行是否缓存在芯片上的任何位置。)


您感兴趣的过程有 an INVD instruction which invalidates all caches without doing write-back first, but I think that includes the shared L3 cache, and probably the private caches of all other cores. So you can't practically use it on a Linux system where other cores are potentially in the middle of doing stuff; you'd potentially corrupt kernel data structures by using it, as well as simulating power failure on a machine with NVDIMMs

也许如果你以某种方式使所有其他 CPU 核心脱机,并在一个仍在运行的核心上禁用中断

然后重新启用中断。如果在 wbinvdinvd.

之间处理任何中断,中断处理程序可能会以一些内核数据缓存和一些在内存中结束,或者使设备驱动程序与硬件不同步

更新:确实有人尝试这样做:

  • - invd 工作得很好,它在错误设计的尝试中破坏了 printk 所做的一些商店。