我的目标是在没有缓存一致性的情况下读取陈旧和过时的内存值。我尝试使用 prefetchnta
执行非临时加载,但未能获取过时的值。我正在考虑执行某种流式内存到内存直接内存访问,但由于继续我当前的项目所需的大量背景知识,我遇到了一些麻烦。目前我正在尝试搞乱 udmabuf但即便如此,进展也很缓慢。应该注意的是,理想情况下我想忽略所有 CPU 缓存的内容,包括当前的 CPU。
提供我的理由:我正在开发可用于证明为非 volatile 存储器编写的程序的正确性的软件。由于CPU缓存是 volatile 的,CPU的回写式缓存仍然是 volatile 的,并且需要观察它们如何写回内存的任意性质。
如果有人能给我一些如何继续的指示,我将不胜感激。我不介意深入研究 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 是缓存一致的,这对性能有好处。为了保持与没有缓存的 386 及更早版本 CPU 的向后兼容性,第一批带有缓存的 x86 CPU 具有缓存一致性 DMA,直到后来的几代才引入缓存控制指令,因为现有操作系统不使用它们。在现代系统中,内存 Controller 内置于 CPU 中。因此,在 Intel CPU 上,系统代理可以监听 L3 标签,以查看某行是否缓存在芯片上的任何位置,同时将请求发送到内存 Controller 。或者,Xeon 可以直接 DMA 进入 L3 缓存,而无需数据通过 DRAM 反弹,这对于高带宽 NIC 很有好处。
<小时/>有an INVD
instruction这会使所有缓存失效而不首先进行写回,但我认为这包括共享的L3缓存,可能还包括所有其他核心的私有(private)缓存。因此,您实际上无法在 Linux 系统上使用它,因为其他内核可能正在执行任务;使用它以及使用 NVDIMMs 模拟机器上的电源故障可能会损坏内核数据结构。对于您感兴趣的过程。
也许如果您以某种方式使所有其他 CPU 核心脱机,并禁用仍在运行的一个核心上的中断
- 你可以
wbinvd
(write-back+invalidate)刷新所有缓存 - 然后运行一些测试代码
- 然后
invd
看看是什么让它进入了 DRAM
然后重新启用中断。如果在 wbinvd
和 invd
之间处理任何中断,中断处理程序最终可能会缓存一些内核数据,而另一些则存储在内存中,或者导致设备驱动程序与硬件不同步。 .
更新:有人确实尝试过这样做:
- How to run "invd" instruction with disabled SMP support?
- How to explicitly load a structure into L1d cache? Weird results with INVD with CR0.CD = 1 on isolated core with/without hyperthreading -
invd
工作得非常好,它在错误设计的试图记录相关内容的尝试中摧毁了printk
所做的一些存储。
关于linux - 如何读取 x86 上的过时值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53142617/