【问题标题】:Is LFENCE serializing on AMD processors?LFENCE 是否在 AMD 处理器上进行序列化?
【发布时间】:2019-01-21 12:22:06
【问题描述】:

在最近的英特尔 ISA 文档中,lfence 指令被定义为对指令流进行序列化(防止其无序执行)。特别是,指令的description 包括这一行:

具体来说,直到所有先前的指令在本地完成后,LFENCE 才会执行,而在 LFENCE 完成之前,后面的指令不会开始执行。

请注意,这适用于所有指令,而不仅仅是内存加载指令,这使得lfence更多不仅仅是一个内存排序栅栏。

虽然这现在出现在 ISA 文档中,但尚不清楚它是“架构的”,即所有 x86 实现都必须遵守,还是英特尔特定的。特别是,AMD 处理器是否也将lfence 视为序列化指令流?

【问题讨论】:

  • lfence 在英特尔上没有“序列化”。该术语具有技术含义,包括完全刷新存储缓冲区。例如cpuidiret 正在序列化。 lfence 只序列化指令流/乱序核心,包括存储缓冲区在内的整个管道。我通常说它是“部分序列化”之类的。
  • @PeterCordes - 请注意,我在问题中第一次使用该术语时写了“序列化指令流”。我不同意英特尔在其手册中始终如一地使用 序列化。他们确实对像cpuid 这样的事情相当一致地使用序列化指令,但他们也对其他事情单独使用序列化,包括那些不是序列化指令。 lfence 部分中直接在我引用的那句话之前的句子在引用lfence 时使用了术语“序列化操作”。
  • 我建议去掉通用的isa标签,加上memory-barriers标签,这样比较贴切。
  • @HadiBrais:我删除了[memory-barriers],因为我们对lfence 的内存屏障效应不感兴趣。我们知道它会这样做,而且它是一个转移注意力的关于它的其他效果的问题。不过,如果您和@Bee 认为该论点没有说服力,我不会坚持再次删除它。
  • @PeterCordes - 是的,但这只是一个标签。我不觉得它分散注意力。事实上,我发现它至少是切线相关的:lfence 至少呈现为内存屏障,而 内存屏障,而这种 OoO 阻塞副作用实际上是实现的结果为其最初的主要功能而设计。如果您对 lfence 作为障碍感兴趣,那么您很可能关心性能,也可能关心这种 OoO 阻塞行为。采取相反的立场:您几乎每次在上下文中出现指令时都提到lfence OoO 行为...

标签: x86 intel cpu-architecture memory-barriers amd-processor


【解决方案1】:

AMD 一直在其手册中将 LFENCE 的实现描述为加载序列化指令

充当强制强内存排序(序列化)的障碍 在 LFENCE 之前的加载指令和加载指令之间 跟随 LFENCE。

LFENCE 的原始用例是订购 WC 内存类型加载。然而,在推测执行漏洞被发现后,AMD 于 2018 年 1 月发布了一份题为“管理 AMD 处理器推测的软件技术”的文件。这是第一个也是唯一一个提到 MSR C001_1029[1] 的文档(在一些 AMD 文档中讨论了 C001_1029 的其他位,但不是第 1 位)。当 C001_1029[1] 设置为 1 时,LFENCE 表现为分派序列化指令(比仅仅加载序列化更昂贵)。由于此 MSR 在大多数较旧的 AMD 处理器上都可用,因此似乎几乎总是支持它。可能是因为他们认为他们将来可能需要在 LFENCE 的行为方面保持与英特尔处理器的兼容性。

栅栏指令和序列化指令以及具有序列化属性的指令的排序规则有例外。这些例外在 Intel 和 AMD 处理器之间略有不同。我现在能想到的一个例子是CLFLUSH 指令。因此,当 AMD 和 Intel 谈论具有序列化属性的指令时,他们的意思略有不同。

我不清楚的一点是 harlod 的回答中引用的以下部分:

AMD 系列 0Fh/11h 处理器始终支持 LFENCE 序列化,但 不支持此 MSR。

此声明含糊不清,因为它没有明确说明 AMD 系列 0Fh 和 11h 上的 LFENCE 是完全序列化(在 AMD 术语中)还是分派序列化(在 AMD 术语中)。但它很可能只是调度序列化。 AMD 系列特定的手册未提及 LFENCE 或 MSR C001_1029。


从 Linux 内核 v4.15-rc8 开始,使用 AMD 处理器上LFENCE 的序列化属性。更改包括两个提交 12。定义了以下宏:

+#define MSR_F10H_DECFG         0xc0011029
+#define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT    1

第一个宏指定 MSR 地址,第二个指定偏移量。在init_amd中添加了以下代码(一些cmets是我的):

/* LFENCE always requires SSE2 */
if (cpu_has(c, X86_FEATURE_XMM2)) {
    unsigned long long val;
    int ret;

    /* The AMD CPU supports LFENCE, but there are three cases to be considered:
     * 1- MSR C001_1029[1] must be set to enable the dispatch 
     *    serializing behavior of LFENCE. This can only be done 
     *    if and only if the MSR is supported.
     * 2- The MSR is not supported (AMD 0Fh/11h). LFENCE is by 
     *    default at least dispatch serializing. Nothing needs to 
     *    be done.
     * 3- The MSR is supported, but we are running under a hypervisor
     *    that does not support writing that MSR (because perhaps
     *    the hypervisor has not been updated yet). In this case, resort
     *    to the slower MFENCE for serializing RDTSC and use a Spectre
     *    mitigation that does not require LFENCE (i.e., generic retpoline).


    /*
     * A serializing LFENCE has less overhead than MFENCE, so
     * use it for execution serialization.  On families which
     * don't have that MSR, LFENCE is already serializing.
     * msr_set_bit() uses the safe accessors, too, even if the MSR
     * is not present.
     */
    msr_set_bit(MSR_F10H_DECFG,
            MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT);

    /*
     * Verify that the MSR write was successful (could be running
     * under a hypervisor) and only then assume that LFENCE is
     * serializing.
     */
    ret = rdmsrl_safe(MSR_F10H_DECFG, &val);
    if (!ret && (val & MSR_F10H_DECFG_LFENCE_SERIALIZE)) {
        /* A serializing LFENCE stops RDTSC speculation */
        set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
        /* X86_FEATURE_LFENCE_RDTSC is used later to choose a Spectre
           mitigation */
    } else {
        /* MFENCE stops RDTSC speculation */
        set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
    }
}

从v5.4-rc1开始,MSR写入验证码被移除。于是代码变成了:

    msr_set_bit(MSR_F10H_DECFG,
            MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT);
    set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);

commit message 中讨论了此更改背后的原因。 (总而言之,它大多是不需要的,它可能不起作用。)

该文件还说:

所有 AMD 系列 10h/12h/14h/15h/16h/17h 处理器都支持此 MSR。 LFENCE 支持由 CPUID 函数 1 EDX 位 26,SSE2 指示。 AMD 系列 0Fh/11h 处理器始终支持 LFENCE 序列化,但确实如此 不支持这个 MSR。

但似乎尚未更新任何 AMD 手册以提及对 C001_1029[1] 的支持。

AMD 在该文件中表示:

AMD 计划支持此 MSR 并为所有未来访问此位 处理器。

这意味着 C001_1029[1] 应被视为未来 AMD 处理器上的架构(相对于 2018 年 1 月)。

【讨论】:

    【解决方案2】:

    有一个 MSR 可以配置该行为:

    描述:在处理器中设置一个 MSR,以便 LFENCE 是一个调度序列化指令,然后 在码流中使用 LFENCE 来序列化调度(LFENCE 比同样调度的 RDTSCP 快 序列化)。可以通过设置 MSR C001_1029[1]=1 来启用这种 LFENCE 模式。

    效果:当 MSR 位设置时遇到 LFENCE,调度将停止,直到 LFENCE 指令成为机器中最旧的指令。

    适用性:所有 AMD 系列 10h/12h/14h/15h/16h/17h 处理器都支持此 MSR。 LFENCE 支持是 由 CPUID 函数 1 EDX 位 26,SSE2 指示。 AMD 系列 0Fh/11h 处理器支持 LFENCE 作为序列化 始终但不支持此 MSR。 AMD 计划支持此 MSR 并为所有未来访问此位 处理器。

    (source)

    【讨论】:

    • 这个寄存器是最近的发明,还是在旧的 AMD 型号上也存在?如果它是旧东西会显得很奇怪,因为它可能是为了减轻 Spectre 而添加的。
    • @BeeOnRope AMD 系列 10h 是 K10,0Fh(没有 MSR,但有序列化 LFENCE)是 K8,AFAIK 任何更老的东西甚至都没有 SSE2,所以根本没有 LFENCE
    • 和 Windows / Linux / *BSD 都设置了启用 Spectre 缓解的 MSR?因此,如果我们可以假设更新的内核,现在可移植使用lfence; rdtsc 是最安全的?
    • (请注意,英特尔的手册并没有承诺rdtscp 会停止执行后面的指令,它只承诺在所有较早的指令完成之前不会对时间进行采样。所以它在定时间隔的开始。另见lfence;rdtsc;lfence 在定时间隔的底部给出更一致的结果:clflush to invalidate cache line via C function
    猜你喜欢
    • 2011-03-22
    • 2013-12-17
    • 2019-06-27
    • 1970-01-01
    • 2010-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多