使用SIGILL与CPU探测进行AVXfunction检测
我正在尝试确定一种检测英特尔和AMD处理器上AVX和AVX2可用性的有效方法。 在阅读英特尔软件开发人员手册第一卷( 使用XSAVEfunction集管理状态 ,第310页)时,我更加惊讶地发现它更接近SSE和XSAVE。
英特尔发布了一些用于在启用Is AVX时检测AVX可用性的代码? 代码如下所示,并不太痛苦。 问题是,Visual Studio是一个痛点,因为我们需要将代码从C / C ++文件中移出到X64的ASM文件中。
其他人似乎采用SIGILL
方法来检测AVX可用性。 或者他们无意中使用了SIGILL
方法。 例如,请参阅AVX指令上的SIGILL 。
我的问题是,使用SIGILL
方法检测AVX可用性是否安全? 这里, “安全”表示当CPU和OS支持AVX时,AVX指令不会生成SIGILL
; 否则它会生成一个SIGILL
。
下面的代码适用于32位计算机,它来自英特尔博客是否已启用AVX? 令我担心的是操纵控制寄存器。 读取和写入某些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
首先是一点理论。
要使用AVX指令集,必须满足以下几个条件:
-
CR4.OSXSAVE[bit 18]
必须为1。
该标志由OS设置,以通知处理器它支持xsave
扩展。
xsave
扩展是保存AVX状态的唯一方法(fxsave
不保存ymm
寄存器),因此操作系统必须支持它们。 -
XCR0.SSE[bit 1]
和XCR0.AVX[bit 2]
必须为1。
这些标志由OS设置,以通知处理器它支持保存和恢复SSE和AVX状态(通过xsave
)。 -
CPUID.1:ECX.AVX[bit 28] = 1
当然,处理器必须首先支持AVX扩展。
所有这些寄存器都是用户模式可读的,但对于CR4
。
幸运的是, CR4.OSXSAVE
位反映在CPUID.1:ECX.OSXSAVE[bit 27]
,因此所有信息都是用户模式可访问的。 不涉及特权指示。
为了使用AVX扩展,必须同时存在硬件( CPUID.1:ECX.AVX
和CPUID.1:ECX.XSAVE
)和OS( CPUID.1:ECX.OSXSAVE
, XCR0.SSE
和XCR0.AVX
)支持。
由于操作系统仅在存在硬件支持的情况下发出支持xsave
信号,因此测试前者就足够了。
对于AVX扩展,仍建议测试CPUID.1:ECX.AVX
因为即使不支持AVX,操作系统也可能设置XCR0.AVX
。
这导致英特尔官方强烈推荐的算法:
这与您发布的完全相同。
捕获exception以检测对AVX扩展的支持也将被授予您可以保证捕获的exception是#UD 。
例如,通过执行vzeroall
,唯一可能的例外是#UD和#NM 。
第一个只在以下情况下抛出:
如果XCR0 [2:1]≠’11b’。
如果CR4.OSXSAVE [bit 18] = 0。
如果CPUID.01H.ECX.AVX [bit 28] = 0。
如果VEX.vvvv≠1111B。
因此,除非您的汇编程序/编译器损坏,否则它完全等同于开头所述的条件。
后者被抛出作为保存AVX状态的优化,因此,它不会被OS暴露给用户模式程序。
因此,在vzeroall
或类似的地方捕获SIGILL
也可以。