存储缓冲区和行填充缓冲区如何相互作用?

Dan*_*und 7 x86 cpu-architecture cpu-cache micro-architecture cpu-mds

我正在阅读 MDS 攻击论文RIDL:Rogue In-Flight Data Load。他们讨论了 Line Fill Buffer 如何导致数据泄漏。有关于 RIDL 漏洞和负载的“重放”问题讨论了漏洞利用的微架构细节。

阅读该问题后,我不清楚的一件事是,如果我们已经有了存储缓冲区,为什么还需要行填充缓冲区。

John McCalpin 在WC-buffer 与LFB 有什么关系?中讨论了存储缓冲区和行填充缓冲区是如何连接的在英特尔论坛上,但这并没有真正让我更清楚。

对于存储到 WB 空间,存储数据将保留在存储缓冲区中,直到存储退出之后。退役后,数据可以写入 L1 数据缓存(如果该行存在且具有写入权限),否则会为存储未命中分配一个 LFB。LFB 最终会收到缓存行的“当前”副本,以便它可以安装在 L1 数据缓存中,并且可以将存储数据写入缓存。合并、缓冲、排序和“捷径”的细节尚不清楚......与上述合理一致的一种解释是 LFB 用作缓存行大小的缓冲区,其中存储数据在发送到L1 数据缓存。至少我认为这是有道理的,但我可能忘记了一些事情......

我最近才开始阅读乱序执行,所以请原谅我的无知。这是我关于商店如何通过商店缓冲区和行填充缓冲区的想法。

  1. 存储指令在前端被调度。
  2. 它在存储单元中执行。
  3. 存储请求被放入存储缓冲区(地址和数据)
  4. 无效的读取请求从存储缓冲区发送到缓存系统
  5. 如果未命中 L1d 缓存,则将请求放入行填充缓冲区
  6. Line Fill Buffer 将无效读取请求转发到 L2
  7. 某些缓存接收无效读取并发送其缓存行
  8. 存储缓冲区将其值应用于传入的缓存行
  9. 嗯?行填充缓冲区将条目标记为无效

在此处输入图片说明

问题

  1. 如果存储缓冲区已经存在,我们为什么还需要行填充缓冲区来跟踪超出的存储请求?
  2. 我的描述中事件的顺序是否正确?

Bee*_*ope 9

如果存储缓冲区已经存在,我们为什么还需要行填充缓冲区来跟踪超出的存储请求?

存储缓冲区用于在存储退出之前和退出之后但在提交到 L1 缓存2之前按顺序跟踪存储。从概念上讲,存储缓冲区是一个完全本地的东西,它并不真正关心缓存未命中。商店缓冲区处理各种大小的各个商店的“单位”。像 Intel Skylake 这样的芯片具有50 多个条目的存储缓冲区

该线填充缓冲器初级处理两者的载入和存储是小姐在L1缓存。本质上,它是从 L1 缓存到内存子系统其余部分的路径,并处理缓存行大小的单位。如果加载或存储命中 L1 缓存1 ,我们不希望 LFB 参与其中。像 Skylake 这样的英特尔芯片的 LFB 条目要少得多,可能只有 10 到 12 个。

我的描述中事件的顺序是否正确?

很接近了。以下是我如何更改您的列表:

  1. 存储指令被解码并拆分为存储数据和存储地址微指令,它们被重命名、调度并为它们分配了存储缓冲区条目。
  2. store uops 以任何顺序或同时执行(这两个子项可以以任一顺序执行,主要取决于哪个首先满足其依赖关系)。
    1. 存储数据 uop 将存储数据写入存储缓冲区。
    2. 存储地址 uop 执行 VP 转换并将地址写入存储缓冲区。
  3. 在所有旧指令都已退役的某个时刻,存储指令将退役。这意味着指令不再是推测性的,并且结果可以是可见的。此时,该商店仍保留在商店缓冲区中,称为高级商店。
  4. 存储现在等待直到它位于存储缓冲区的头部(它是最旧的未提交存储),此时它将提交(变为全局可观察)到 L1,如果相关的缓存线存在于 L1 中MESIF 修改或独占状态。(即这个核心拥有线路)
  5. 如果该行不存在于所需状态(完全丢失,即缓存未命中,或存在但处于非排他状态),则必须从内存子系统:如果尚未分配,则为整行分配一个 LFB。这是所谓的所有权请求(RFO),这意味着内存层次结构应该以适合修改的独占状态返回行,而不是仅适合于读取的共享状态(这会使存在于任何其他私有缓存)。

将 Shared 转换为 Exclusive 的 RFO 仍必须等待响应以确保所有其他缓存已使其副本无效。对这种无效的响应不需要包含数据的副本,因为该缓存已经有一个。它仍然可以称为 RFO;重要的部分是在修改一行之前获得所有权。6. 在未命中的情况下,LFB 最终会返回该行的全部内容,该内容已提交给 L1,挂起的存储现在可以提交3

这是该过程的粗略近似。某些或所有芯片上的某些细节可能有所不同,包括不太了解的细节。

作为一个示例,在上述顺序中,直到商店到达商店队列的头部时才提取商店未命中行。实际上,商店子系统可能会实现一种RFO 预取,其中检查商店队列中是否有即将到来的商店,如果 L1 中不存在这些行,则提前启动请求(对 L1 的实际可见提交仍然必须在顺序,在 x86 上,或至少“好像”按顺序)。

因此,请求和 LFB 的使用可能最早在第 3 步完成时发生(如果 RFO 预取仅在商店退役后才适用),或者甚至可能早在 2.2 完成时发生,如果初级商店受到预取。

作为另一个例子,步骤 6 描述了从内存层次结构返回并提交到 L1 的行,然后存储提交。有可能挂起的存储实际上与返回的数据合并,然后写入 L1。即使在未命中的情况下,存储也可能离开存储缓冲区并在 LFB 中等待,从而释放一些存储缓冲区条目。


1在 L1 缓存中命中的存储的情况下,建议实际上涉及 LFB:每个存储在提交到缓存之前实际上进入组合缓冲区(可能只是一个 LFB),这样一系列针对相同缓存行的存储组合在缓存中,并且只需要访问 L1 一次。这尚未得到证实,但在任何情况下,它都不是 LFB 主要用途的一部分(更明显的是,我们甚至无法真正判断它是否正在发生)。

2保存之前和退休前存储的缓冲区可能是两种完全不同的结构,具有不同的大小和行为,但在这里我们将它们称为一种结构。

3所描述的场景涉及在存储缓冲区的头部等待直到相关行返回的存储未命中。另一种情况是将存储数据写入用于请求的 LFB,并且可以释放存储缓冲区条目。这可能允许在发生未命中时处理一些后续存储,但要遵守严格的 x86 排序要求。这可能会增加商店 MLP。

  • 我在条目 5 中添加了一些有关存在但共享(非独占)线路的 RFO 的内容 (2认同)