diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2013-03-26 16:12:30 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2013-03-26 16:17:34 +0000 |
commit | 0b479504c82bd81c0b93de0e6529eae928eea3bf (patch) | |
tree | db4303c2a46871a9781d9759b4cd6cc24dc2d775 /src/sna/sna_cpu.c | |
parent | 9620f419076202ebc89b4c7f1c06374fb2554f28 (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.c | 17 |
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; } |