CPUID Patch for IDT Winchip

Uros Bizjak ubizjak@gmail.com
Tue May 21 07:46:00 GMT 2019


On Tue, May 21, 2019 at 12:20 AM tedheadster <tedheadster@gmail.com> wrote:
>
> On Mon, May 20, 2019 at 2:57 PM Uros Bizjak <ubizjak@gmail.com> wrote:
> >
> > On Mon, May 20, 2019 at 6:12 PM tedheadster <tedheadster@gmail.com> wrote:
> > > Did you instead mean "zeroing %EBX and %ECX regs should be enough"?
> >
> > Ah, yes. This is what I meant to say. The patch clears %ebx and %ecx.
> >
>
> Uros,
>   your patch worked on real 32-bit hardware. The assembly output is
> nearly identical to mine, with merely a re-ordering when setting the
> %eax, %ebx, and %ecx registers.

Attached patch fixes the core of the problem. We can change __cpuid
itself to use zeroing, unless we can prove that we use constant
argument, different than 1. __cpuid is mostly used with constant
argument, so constant propagation does its job. As an example:

--cut here--
#include "cpuid.h"

int main ()
{
  unsigned int eax, ebx, ecx, edx;

  if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
    __builtin_abort ();

  printf ("%#x, %#x, %#x, %#x\n", eax, ebx, ecx, edx);
  return 0;
}
--cut here--

results in:

  2f:   31 f6                   xor    %esi,%esi
  31:   89 f0                   mov    %esi,%eax
  33:   0f a2                   cpuid
  35:   85 c0                   test   %eax,%eax
  37:   0f 84 fc ff ff ff       je     39 <main+0x39>
  3d:   83 ec 0c                sub    $0xc,%esp
  40:   89 f3                   mov    %esi,%ebx
  42:   89 f1                   mov    %esi,%ecx
  44:   b8 01 00 00 00          mov    $0x1,%eax
  49:   0f a2                   cpuid

Uros.
-------------- next part --------------
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index 8ddd425c8b7e..1d6ef335e76d 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -187,10 +187,27 @@
 #define signature_VORTEX_ecx	0x436f5320
 #define signature_VORTEX_edx	0x36387865
 
+#ifndef __x86_64__
+/* At least one cpu (Winchip 2) does not set %ebx and %ecx
+   for cpuid leaf 1. Forcibly zero the two registers before
+   calling cpuid as a precaution.  */
+#define __cpuid(level, a, b, c, d)			\
+  do {							\
+    if (__builtin_constant_p (level) && (level) != 1)	\
+      __asm__ ("cpuid\n\t"				\
+	      : "=a" (a), "=b" (b), "=c" (c), "=d" (d)	\
+	      : "0" (level));				\
+    else						\
+      __asm__ ("cpuid\n\t"				\
+	      : "=a" (a), "=b" (b), "=c" (c), "=d" (d)	\
+	      : "0" (level), "1" (0), "2" (0));		\
+  } while (0)
+#else
 #define __cpuid(level, a, b, c, d)			\
   __asm__ ("cpuid\n\t"					\
 	   : "=a" (a), "=b" (b), "=c" (c), "=d" (d)	\
 	   : "0" (level))
+#endif
 
 #define __cpuid_count(level, count, a, b, c, d)		\
   __asm__ ("cpuid\n\t"					\


More information about the Gcc-patches mailing list