lfence
指令被定义为序列化指令流(防止它跨越乱序执行)。特别地,在描述该指令时包括了以下内容:
请注意,这适用于所有指令,而不仅仅是内存加载指令,使得
lfence
不会执行,直到所有先前的指令都已本地完成,且在lfence
完成之前没有后续指令开始执行。
lfence
比内存排序栅还要更加强大。尽管此说明现已出现在ISA文档中,但仍不清楚它是否是“架构级”的,即要被所有x86实现遵守,还是只有Intel专用。特别地,AMD处理器是否也将
lfence
视为序列化指令流?
lfence
指令被定义为序列化指令流(防止它跨越乱序执行)。特别地,在描述该指令时包括了以下内容:
请注意,这适用于所有指令,而不仅仅是内存加载指令,使得
lfence
不会执行,直到所有先前的指令都已本地完成,且在lfence
完成之前没有后续指令开始执行。
lfence
比内存排序栅还要更加强大。lfence
视为序列化指令流?
AMD在其手册中一直将LFENCE
的实现描述为一个加载序列化指令。
作为一种屏障,强制内存顺序(序列化)在LFENCE之前的加载指令和在LFENCE之后的加载指令之间执行。
LFENCE
最初的使用案例是对WC内存类型加载进行排序。然而,在发现了漏洞后,AMD在2018年1月发布了一份名为“管理AMD处理器推测的软件技术”的文件。这是唯一一份提到MSR C001_1029 [1]的文档(其他位于C001_1029的位数在某些AMD文档中讨论,但不是第1位)。当设置C001_1029 [1]为1时,LFENCE
将作为调度序列化指令(比仅仅是加载序列化更昂贵)。由于该MSR在大多数旧版AMD处理器上可用,因此似乎它一直得到支持。也许是因为他们认为他们未来需要与英特尔处理器保持兼容性,以便使LFENCE
的行为相同。
fence指令、序列化指令和具有序列化属性的指令的排序规则有例外情况。这些例外情况在英特尔和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
的序列化属性。更改由两个提交组成1和2。定义了以下宏:
+#define MSR_F10H_DECFG 0xc0011029
+#define MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT 1
init_amd
中(一些注释是我的):/* 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);
}
}
msr_set_bit(MSR_F10H_DECFG,
MSR_F10H_DECFG_LFENCE_SERIALIZE_BIT);
set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
但似乎尚未更新任何AMD手册以提到对C001_1029[1]的支持。所有AMD 10h/12h/14h/15h/16h/17h处理器都支持此MSR。 CPUID函数1 EDX位26(SSE2)表示LFENCE支持。 AMD 0Fh/11h系列处理器始终支持LFENCE作为序列化,但不支持此MSR。
这意味着在未来的AMD处理器上(截至2018年1月),C001_1029[1]应被视为架构性的。AMD计划支持这个MSR并为所有未来的处理器提供这一位的访问权限。
有一个MSR来配置这种行为:
描述:在处理器中设置一个MSR,使LFENCE成为一个调度序列化指令,然后在代码流中使用LFENCE来序列化调度(LFENCE比也适用于调度序列化的RDTSCP更快)。通过设置MSR C001_1029 [1] = 1可以启用LFENCE的这种模式。
效果:当MSR位被设置时遇到LFENCE时,调度将停止,直到LFENCE指令成为机器上最老的指令。
适用性:所有AMD家族10h / 12h / 14h / 15h / 16h / 17h处理器都支持此MSR。 CPUID函数1 EDX位26(SSE2)表示支持LFENCE。 AMD家族0Fh / 11h处理器始终支持LFENCE作为序列化,但不支持此MSR。 AMD计划支持此MSR并为所有未来处理器提供对此位的访问。
(source)
lfence; rdtsc
现在基本上是安全的。 - Peter Cordesrdtscp
停止后续指令的执行,它只承诺在所有早期指令完成之前不会对时间进行采样。 因此,在定时间隔的开始处使用它是没有用的。 另请参考这种情况,在计时间隔底部使用 lfence;rdtsc;lfence
能够获得更一致的结果:clflush to invalidate cache line via C function - Peter Cordesrdtscp
是否真的像英特尔的论文规范中那样弱。它可能基本上会解码为uops,就像lfence;rdtsc
加上设置ECX一样。我似乎记得有人在评论中提到过,他们从未见过后续指令能够提前执行的情况。 - Peter Cordes
lfence
在英特尔上不是“串行化”的。该术语具有技术含义,包括完全刷新存储缓冲区。例如,cpuid
和iret
是串行化的。lfence
仅串行化指令流/乱序核心,而不是整个管道,包括存储缓冲区。我通常说它是“部分串行化”或类似的东西。 - Peter Cordescpuid
之类的事情,但他们还将_串行化_单独用于其他事物,包括不是_串行化指令_的事物。在我引用的那句话之前,lfence部分的句子使用“串行化操作”一词来引用lfence
。 - BeeOnRopelfence
至少被呈现为内存屏障,并且确实是一种内存屏障,而这种 OoO 阻塞副作用实际上是其原始主要功能的实现设计的结果。如果你对lfence
作为屏障感兴趣,那么你很可能关心性能,并且也许关心这种 OoO 阻塞行为。相反地,你提到lfence
的 OoO 行为几乎每次在上下文中出现该指令时都会发生。 - BeeOnRopelfence
可能会或可能不会序列化,这取决于 MSR 中设置的值。 - BeeOnRope