summaryrefslogtreecommitdiff
path: root/src/sna/sna_cpu.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2013-03-26 16:12:30 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2013-03-26 16:17:34 +0000
commit0b479504c82bd81c0b93de0e6529eae928eea3bf (patch)
treedb4303c2a46871a9781d9759b4cd6cc24dc2d775 /src/sna/sna_cpu.c
parent9620f419076202ebc89b4c7f1c06374fb2554f28 (diff)
sna: Check for OS support of AVX/AVX2 before use
If the OS has not initialised support for the extended instructions, then their use may result in general protection faults. Based on code by Thiago Macieira. Reported-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src/sna/sna_cpu.c')
-rw-r--r--src/sna/sna_cpu.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/src/sna/sna_cpu.c b/src/sna/sna_cpu.c
index ab4942b6..ff83ba57 100644
--- a/src/sna/sna_cpu.c
+++ b/src/sna/sna_cpu.c
@@ -39,11 +39,17 @@
#define bit_AVX2 (1<<5)
#endif
+#define xgetbv(index,eax,edx) \
+ __asm__ ("xgetbv" : "=a"(eax), "=d"(edx) : "c" (index))
+
+#define has_YMM 0x1
+
unsigned sna_cpu_detect(void)
{
unsigned max = __get_cpuid_max(false, 0);
unsigned int eax, ebx, ecx, edx;
unsigned features = 0;
+ unsigned extra = 0;
if (max >= 1) {
__cpuid(1, eax, ebx, ecx, edx);
@@ -59,7 +65,14 @@ unsigned sna_cpu_detect(void)
if (ecx & bit_SSE4_2)
features |= SSE4_2;
- if (ecx & bit_AVX)
+ if (ecx & bit_OSXSAVE) {
+ unsigned int bv_eax, bv_ecx;
+ xgetbv(0, bv_eax, bv_ecx);
+ if ((bv_eax & 6) == 6)
+ extra |= has_YMM;
+ }
+
+ if (extra & has_YMM && ecx & bit_AVX)
features |= AVX;
if (edx & bit_MMX)
@@ -74,7 +87,7 @@ unsigned sna_cpu_detect(void)
if (max >= 7) {
__cpuid_count(7, 0, eax, ebx, ecx, edx);
- if (ebx & bit_AVX2)
+ if (extra & has_YMM && ebx & bit_AVX2)
features |= AVX2;
}