【问题标题】:AVX feature detection using SIGILL versus CPU probing使用 SIGILL 的 AVX 特征检测与 CPU 探测
【发布时间】:2017-10-23 23:51:39
【问题描述】:

我正在尝试确定一种有效的方法来检测英特尔和 AMD 处理器上的 AVX 和 AVX2 的可用性。在阅读英特尔软件开发人员手册第一卷(使用 XSAVE 功能集管理状态,第 310 页时,我有点惊讶地发现它更接近 SSE 和 XSAVE )。

英特尔在Is AVX enabled? 上发布了一些用于检测 AVX 可用性的代码。代码如下所示,它不会太痛苦。问题是,Visual Studio 是一个痛点,因为我们需要将代码从 C/C++ 文件移到 X64 的 ASM 文件中。

其他人似乎正在采用SIGILL 方法来检测 AVX 可用性。或者他们在不知不觉中使用了SIGILL 方法。例如,请参阅SIGILL on AVX instruction

我的问题是,使用 SIGILL 方法检测 AVX 可用性是否安全?此处,“安全” 表示当 CPU 和操作系统支持 AVX 时,AVX 指令将生成SIGILL;否则它将生成SIGILL


下面的代码是针对 32 位机器的,它来自英特尔博客 Is AVX enabled? 让我担心的是操纵控制寄存器。读取和写入某些 X86 和 ARM 控制寄存器有时需要超级用户/管理员权限。这是我更喜欢SIGILL 的原因(并避免使用控制寄存器)。

; int isAvxSupported();
isAvxSupported proc

  xor eax, eax
  cpuid
  cmp eax, 1           ; does CPUID support eax = 1?
  jb not_supported

  mov eax, 1
  cpuid
  and ecx, 018000000h  ; check 27 bit (OS uses XSAVE/XRSTOR)
  cmp ecx, 018000000h  ; and 28       (AVX supported by CPU)
  jne not_supported

  xor ecx, ecx         ; XFEATURE_ENABLED_MASK/XCR0 register number = 0
  xgetbv               ; XFEATURE_ENABLED_MASK register is in edx:eax
  and eax, 110b
  cmp eax, 110b        ; check the AVX registers restore at context switch
  jne not_supported

supported:
  mov eax, 1
  ret

not_supported:
  xor eax, eax
  ret

isAvxSupported endp

【问题讨论】:

标签: c assembly avx


【解决方案1】:

先说一点理论。

为了使用 AVX 指令集必须满足几个条件:

  1. CR4.OSXSAVE[bit 18] 必须为 1。
    此标志由操作系统设置以向处理器发出信号,表明它支持xsave 扩展。
    xsave 扩展是保存 AVX 状态的唯一方法(fxsave 不保存 ymm 寄存器),因此操作系统必须支持它们。

  2. XCR0.SSE[bit 1]XCR0.AVX[bit 2] 必须为 1。
    这些标志由操作系统设置,以通知处理器它支持保存和恢复 SSE 和 AVX 状态(通过xsave)。

  3. CPUID.1:ECX.AVX[bit 28] = 1
    当然,处理器首先必须支持 AVX 扩展。

所有这些寄存器都是用户模式可读的,但对于CR4
幸运的是,CR4.OSXSAVE 位反映在CPUID.1:ECX.OSXSAVE[bit 27] 中,因此所有信息都可以在用户模式下访问。 不涉及特权指令。

为了使用 AVX 扩展,必须同时支持硬件(CPUID.1:ECX.AVXCPUID.1:ECX.XSAVE)和操作系统(CPUID.1:ECX.OSXSAVEXCR0.SSEXCR0.AVX)。
由于操作系统仅在存在硬件支持的情况下才表示支持xsave,因此测试前者就足够了。
对于 AVX 扩展,仍然建议测试 CPUID.1:ECX.AVX,因为即使不支持 AVX,操作系统也可能设置 XCR0.AVX

这导致了英特尔官方强烈推荐的算法:

这与您发布的完全相同。


捕获异常以检测对 AVX 扩展的支持也可以保证您可以保证捕获的异常是 #UD
例如,通过执行 vzeroall,唯一可能的例外是 #UD#NM
第一个仅在以下情况下抛出:

如果 XCR0[2:1] ≠ ‘11b’。
如果 CR4.OSXSAVE[bit 18]=0.
如果 CPUID.01H.ECX.AVX[bit 28]=0.
如果 VEX.vvvv ≠ 1111B。

因此,除非您的汇编器/编译器损坏,否则它完全等同于开头所述的条件。

后者是作为保存 AVX 状态的优化而抛出的,因此它不会被操作系统暴露给用户模式程序。

因此在vzeroall 上捕获SIGILL 或类似的也可以。

【讨论】:

  • 当指令未生成#UD 且CR3.TS = 1 时,会引发#NM 异常。如果锁定前缀与VZEROALL 一起使用,则会生成#UD 异常。只有 ring 0 代码可以设置 CR3.TS,因此只会生成 #NM,以便操作系统可以懒惰地保存 FPU/SIMD 状态。
  • 谢谢玛格丽特。我还在消化答案。一个简单的问题......如果isAvxSupported 返回true,那么这是否意味着AVX2 也可用?还是我们需要额外的测试?天真地,似乎 AVX 和 AVX2 是不同的功能,AVX2 需要额外的测试。但是第 13 章,使用 XSAVE 功能集管理状态,只讨论了 AVX;它没有讨论 AVX2 或 AVX512。然而,第 13 章确实讨论了状态大小。这对于 {AVX|AVX2|AVX512} 和操作系统支持可能已经足够了。
  • @jww,抱歉回复晚了。在使用 AVX2 之前,应测试位 CPUID.7:EBX.AVX2[bit 5]。由于 AVX2 只是引入了新指令而没有新状态,这应该足够了(除了 AVX 测试)。
  • @MargaretBloom - 我还没有时间测试这个。这是一个 FOSS 项目,我现在正忙于其他工作。感谢您的回答,对于延迟的反馈,我们深表歉意。如果我在实施后有反馈,我会通知您。
  • @jww,没问题。慢慢来:)
猜你喜欢
  • 2010-11-20
  • 2016-06-21
  • 1970-01-01
  • 2013-05-13
  • 1970-01-01
  • 1970-01-01
  • 2012-12-16
相关资源
最近更新 更多