summaryrefslogtreecommitdiff
path: root/fb/fbpict.c
diff options
context:
space:
mode:
authorAdam Jackson <ajax@nwnk.net>2005-11-30 02:36:25 +0000
committerAdam Jackson <ajax@nwnk.net>2005-11-30 02:36:25 +0000
commit4ec0b623b6ab5f8a1e5af2cc3d839251acf81ce2 (patch)
tree3c40d54e8a78208c60373c646cd87af1b20bd426 /fb/fbpict.c
parented826d563cba82c516fd41f6a29ee50aa1fe6c6a (diff)
Bug #5093: Fix fb for non-SSE machines. (Xavier Bachelot)
Diffstat (limited to 'fb/fbpict.c')
-rw-r--r--fb/fbpict.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/fb/fbpict.c b/fb/fbpict.c
index 0d336fd12..05e0ef03f 100644
--- a/fb/fbpict.c
+++ b/fb/fbpict.c
@@ -1336,3 +1336,121 @@ fbPictureInit (ScreenPtr pScreen, PictFormatPtr formats, int nformats)
return TRUE;
}
+
+#ifdef USE_MMX
+/* The CPU detection code needs to be in a file not compiled with
+ * "-mmmx -msse", as gcc would generate CMOV instructions otherwise
+ * that would lead to SIGILL instructions on old CPUs that don't have
+ * it.
+ */
+#if !defined(__amd64__) && !defined(__x86_64__)
+
+enum CPUFeatures {
+ NoFeatures = 0,
+ MMX = 0x1,
+ MMX_Extensions = 0x2,
+ SSE = 0x6,
+ SSE2 = 0x8,
+ CMOV = 0x10
+};
+
+static unsigned int detectCPUFeatures(void) {
+ unsigned int result;
+ char vendor[13];
+ vendor[0] = 0;
+ vendor[12] = 0;
+ /* see p. 118 of amd64 instruction set manual Vol3 */
+ /* We need to be careful about the handling of %ebx and
+ * %esp here. We can't declare either one as clobbered
+ * since they are special registers (%ebx is the "PIC
+ * register" holding an offset to global data, %esp the
+ * stack pointer), so we need to make sure they have their+ * original values when we access the output operands.
+ */
+ __asm__ ("pushf\n"
+ "pop %%eax\n"
+ "mov %%eax, %%ecx\n"
+ "xor $0x00200000, %%eax\n"
+ "push %%eax\n"
+ "popf\n"
+ "pushf\n"
+ "pop %%eax\n"
+ "mov $0x0, %%edx\n"
+ "xor %%ecx, %%eax\n"
+ "jz 1\n"
+
+ "mov $0x00000000, %%eax\n"
+ "push %%ebx\n"
+ "cpuid\n"
+ "mov %%ebx, %%eax\n"
+ "pop %%ebx\n"
+ "mov %%eax, %1\n"
+ "mov %%edx, %2\n"
+ "mov %%ecx, %3\n"
+ "mov $0x00000001, %%eax\n"
+ "push %%ebx\n"
+ "cpuid\n"
+ "pop %%ebx\n"
+ "1:\n"
+ "mov %%edx, %0\n"
+ : "=r" (result),
+ "=m" (vendor[0]),
+ "=m" (vendor[4]),
+ "=m" (vendor[8])
+ :
+ : "%eax", "%ecx", "%edx"
+ );
+
+ unsigned int features = 0;
+ if (result) {
+ /* result now contains the standard feature bits */
+ if (result & (1 << 15))
+ features |= CMOV;
+ if (result & (1 << 23))
+ features |= MMX;
+ if (result & (1 << 25))
+ features |= SSE;
+ if (result & (1 << 26))
+ features |= SSE2;
+ if ((result & MMX) && !(result & SSE) && (strcmp(vendor, "AuthenticAMD") == 0)) {
+ /* check for AMD MMX extensions */
+
+ unsigned int result;
+ __asm__("push %%ebx\n"
+ "mov $0x80000000, %%eax\n"
+ "cpuid\n"
+ "xor %%edx, %%edx\n"
+ "cmp $0x1, %%eax\n"
+ "jge 2\n"
+ "mov $0x80000001, %%eax\n"
+ "cpuid\n"
+ "2:\n"
+ "pop %%ebx\n"
+ "mov %%edx, %0\n"
+ : "=r" (result)
+ :
+ : "%eax", "%ecx", "%edx"
+ );
+ if (result & (1<<22))
+ features |= MMX_Extensions;
+ }
+ }
+ return features;
+}
+
+Bool
+fbHaveMMX (void)
+{
+ static Bool initialized = FALSE;
+ static Bool mmx_present;
+
+ if (!initialized)
+ {
+ unsigned int features = detectCPUFeatures();
+ mmx_present = (features & (MMX|MMX_Extensions)) == (MMX|MMX_Extensions);
+ initialized = TRUE;
+ }
+
+ return mmx_present;
+}
+#endif /* __amd64__ */
+#endif