Merge branch '2.5.x'
[catacomb] / base / dispatch.c
index 131e3fd..db9c319 100644 (file)
@@ -43,7 +43,6 @@
 
 #if CPUFAM_X86 || CPUFAM_AMD64
 
-#  define EFLAGS_ID (1u << 21)
 #  define CPUID1D_SSE2 (1u << 26)
 #  define CPUID1D_FXSR (1u << 24)
 #  define CPUID1C_PCLMUL (1u << 1)
 #  define CPUID1C_RDRAND (1u << 30)
 
 struct cpuid { unsigned a, b, c, d; };
-
-/* --- @cpuid@ --- *
- *
- * Arguments:  @struct cpuid *cc@ = where to write the result
- *             @unsigned a, c@ = EAX and ECX registers to set
- *
- * Returns:    ---
- *
- * Use:                Minimal C wrapper around the x86 `CPUID' instruction.  Checks
- *             that the instruction is actually available before invoking
- *             it; fills the output structure with zero if it's not going to
- *             work.
- */
-
-#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)
-{
-  unsigned ff;
-  __asm__ ("pushf; pushl %1; popf; pushf; popl %0; popf"
-          : "=r" (ff)
-          : "r" (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"
-          : "=r" (ff)
-          : "r" (f));
-  return (ff);
-}
-#  endif
-#endif
+extern int dispatch_x86ish_cpuid(struct cpuid *, unsigned a, unsigned c);
+extern int dispatch_x86ish_xmmregisters_p(void);
+extern int dispatch_x86ish_rdrand(unsigned *);
 
 static void cpuid(struct cpuid *cc, unsigned a, unsigned c)
 {
-#ifdef __GNUC__
-  unsigned f;
-#endif
-
-  cc->a = cc->b = cc->c = cc->d = 0;
-
-#ifdef __GNUC__
-  /* Stupid dance to detect whether the CPUID instruction is available. */
-  f = getflags();
-  if (!(setflags(f |  EFLAGS_ID) & EFLAGS_ID) ||
-       setflags(f & ~EFLAGS_ID) & EFLAGS_ID) {
+  int rc = dispatch_x86ish_cpuid(cc, a, c);
+  if (rc)
     dispatch_debug("CPUID instruction not available");
-    return;
-  }
-  setflags(f);
-
-  /* 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
+  else
+    dispatch_debug("CPUID(%08x, %08x) -> %08x, %08x, %08x, %08x",
+                  a, c, cc->a, cc->b, cc->c, cc->d);
 }
 
 static unsigned cpuid_maxleaf(void)
@@ -162,43 +96,10 @@ static int cpuid_features_p(unsigned dbits, unsigned cbits)
 
 static int xmm_registers_available_p(void)
 {
-#ifdef __GNUC__
-  unsigned f;
-  /* This hack is by Agner Fog.  Use FXSAVE/FXRSTOR to figure out whether the
-   * 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"
-          "fxrstor (%%esp); fxsave (%%esp)\n"
-          "movl 160(%%esp), %%ecx; movl %%eax, 160(%%esp)\n"
-          "fxrstor (%%esp); movl %%edx, %%esp\n"
-          "xorl %%ecx, %%eax"
-          : "=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
+  int f = dispatch_x86ish_xmmregisters_p();
+
   dispatch_debug("XMM registers %savailable", f ? "" : "not ");
   return (f);
-#else
-  dispatch_debug("GNU inline assembler not available; can't check for XMM");
-  return (0);
-#endif
 }
 
 /* --- @rdrand_works_p@ --- *
@@ -210,25 +111,6 @@ static int xmm_registers_available_p(void)
  *             that it's already been verified to be safe to issue.
  */
 
-#ifdef __GNUC__
-static int rdrand(unsigned *x)
-{
-  int i, rc;
-  unsigned _t;
-
-  i = 16;
-  __asm__ ("" : "=g" (_t));
-  __asm__ ("0: rdrand %2; jc 1f; decl %1; jnz 0b\n"
-          "mov $-1, %0; jmp 9f\n"
-          "1: movl %2, (%3); xorl %0, %0\n"
-          "9:"
-          : "=r" (rc), "+r" (i), "+r" (_t)
-          : "r" (x)
-          : "cc");
-  return (rc);
-}
-#endif
-
 static int rdrand_works_p(void)
 {
   unsigned ref, x, i;
@@ -237,9 +119,9 @@ static int rdrand_works_p(void)
    * will fail with probability %$2^{-128}$% with a truly random generator,
    * which seems fair enough.
    */
-  if (rdrand(&ref)) goto fail;
+  if (dispatch_x86ish_rdrand(&ref)) goto fail;
   for (i = 0; i < 4; i++) {
-    if (rdrand(&x)) goto fail;
+    if (dispatch_x86ish_rdrand(&x)) goto fail;
     if (x != ref) goto not_stuck;
   }
   dispatch_debug("RDRAND always returns 0x%08x!", ref);