Add support for AMD64 processors and Microsoft Windows.
[catacomb] / base / dispatch.c
index 61c45fa..8936ea4 100644 (file)
@@ -41,7 +41,7 @@
 
 /*----- Intel x86/AMD64 feature probing -----------------------------------*/
 
-#ifdef CPUFAM_X86
+#if CPUFAM_X86 || CPUFAM_AMD64
 
 #  define EFLAGS_ID (1u << 21)
 #  define CPUID1D_SSE2 (1u << 26)
@@ -64,6 +64,7 @@ struct cpuid { unsigned a, b, c, d; };
  */
 
 #ifdef __GNUC__
+#  if CPUFAM_X86
 static __inline__ unsigned getflags(void)
   { unsigned f; __asm__ ("pushf; popl %0" : "=g" (f)); return (f); }
 static __inline__ unsigned setflags(unsigned f)
@@ -74,6 +75,18 @@ static __inline__ unsigned setflags(unsigned f)
           : "g" (f));
   return (ff);
 }
+#  else
+static __inline__ unsigned long getflags(void)
+  { unsigned long f; __asm__ ("pushf; popq %0" : "=g" (f)); return (f); }
+static __inline__ unsigned long long setflags(unsigned long f)
+{
+  unsigned long ff;
+  __asm__ ("pushf; pushq %1; popf; pushf; popq %0; popf"
+          : "=g" (ff)
+          : "g" (f));
+  return (ff);
+}
+#  endif
 #endif
 
 static void cpuid(struct cpuid *cc, unsigned a, unsigned c)
@@ -97,9 +110,19 @@ static void cpuid(struct cpuid *cc, unsigned a, unsigned c)
   /* Alas, EBX is magical in PIC code, so abuse ESI instead.  This isn't
    * pretty, but it works.
    */
+#  if CPUFAM_X86
   __asm__ ("pushl %%ebx; cpuid; movl %%ebx, %%esi; popl %%ebx"
           : "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d)
           : "a" (a) , "c" (c));
+#  elif CPUFAM_AMD64
+  __asm__ ("pushq %%rbx; cpuid; movl %%ebx, %%esi; popq %%rbx"
+          : "=a" (cc->a), "=S" (cc->b), "=c" (cc->c), "=d" (cc->d)
+          : "a" (a) , "c" (c));
+#  else
+#    error "I'm confused."
+#  endif
+  dispatch_debug("CPUID(%08x, %08x) -> %08x, %08x, %08x, %08x",
+                a, c, cc->a, cc->b, cc->c, cc->d);
 #else
   dispatch_debug("GNU inline assembler not available; can't CPUID");
 #endif
@@ -141,6 +164,7 @@ static int xmm_registers_available_p(void)
    * XMM registers are actually alive.
    */
   if (!cpuid_features_p(CPUID1D_FXSR, 0)) return (0);
+#  if CPUFAM_X86
   __asm__ ("movl %%esp, %%edx; subl $512, %%esp; andl $~15, %%esp\n"
           "fxsave (%%esp)\n"
           "movl 160(%%esp), %%eax; xorl $0xaaaa5555, 160(%%esp)\n"
@@ -151,6 +175,21 @@ static int xmm_registers_available_p(void)
           : "=a" (f)
           : /* no inputs */
           : "%ecx", "%edx");
+#  elif CPUFAM_AMD64
+  __asm__ ("movq %%rsp, %%rdx; subq $512, %%rsp; andq $~15, %%rsp\n"
+          "fxsave (%%rsp)\n"
+          "movl 160(%%rsp), %%eax; xorl $0xaaaa5555, 160(%%rsp)\n"
+          "fxrstor (%%rsp); fxsave (%%rsp)\n"
+          "movl 160(%%rsp), %%ecx; movl %%eax, 160(%%rsp)\n"
+          "fxrstor (%%rsp); movq %%rdx, %%rsp\n"
+          "xorl %%ecx, %%eax"
+          : "=a" (f)
+          : /* no inputs */
+          : "%ecx", "%rdx");
+#  else
+#    error "I'm confused."
+#  endif
+  dispatch_debug("XMM registers %savailable", f ? "" : "not ");
   return (f);
 #else
   dispatch_debug("GNU inline assembler not available; can't check for XMM");
@@ -257,7 +296,7 @@ int cpu_feature_p(int feat)
     return (feat_debug(ftok, "runtime probe", cond));
 
   switch (feat) {
-#ifdef CPUFAM_X86
+#if CPUFAM_X86 || CPUFAM_AMD64
     CASE_CPUFEAT(X86_SSE2, "x86:sse2",
                 xmm_registers_available_p() &&
                 cpuid_features_p(CPUID1D_SSE2, 0));