CPUID Patch for IDT Winchip

Uros Bizjak ubizjak@gmail.com
Mon May 20 15:51:00 GMT 2019


On Mon, May 20, 2019 at 4:24 PM tedheadster <tedheadster@gmail.com> wrote:
>
> Uros,
>
> On Mon, May 20, 2019 at 3:29 AM Uros Bizjak <ubizjak@gmail.com> wrote:
> > The CPUID documentation from Intel Architectures Developer's manual is
> > crystal clear on the implementation:
> >
> > --quote--
> > CPUID—CPU Identification
> >
> > Returns processor identification and feature
> > information to the EAX, EBX, ECX, and EDX
> > registers, as determined by input entered in
> > EAX (in some cases, ECX as well).
> > --quote--
>
> That is for the current versions of the documentation. Earlier versions are different (see below).
>
> > So, I dont see why we should implement the workaround for an
> > implementation bug in a widely used header for a relatively obscure
> > target. Please also note that there are other places in the compiler
> > that assume that the instruction returns values as specified above,
> > not to mention other applications that assumes the same.
> >
> > I think proposed target specific bugfix should be implemented
> > elsewhere, not in the cpuid.h header that assumes the specified
> > functionality.
>
> I did some research and found the Intel CPUID document that existed when the WinChip was manufactured (dated December 1996):
>
> http://bitsavers.trailing-edge.com/components/intel/appNotes/AP-485_Intel_Processor_Identification_and_the_CPUID_Instruction_Dec96.pdf
>
> It is ALSO silent about the contents of %ebx and %ecx after a cpuid() with %eax = 1. The Winchip met the Intel _published_ standard that existed at the time. Intel changed the standard a long time afterwards.

Hm, I see.

> This means that all the following processor manufacturers (and example cpus) of that era might demonstrate this behavior:
>
> AMD (Am486 DX2/DX4, Am5x86, K5)
> Centaur (WinChip C6, Winchip 2)
> NexGen (Nx586)
> Cyrix (Cx486DX2/DX4, 5x86, 6x86, 6x86MX)
>
> That is a lot of processors. Admittedly they are old, but they are still officially supported by GNU/Linux.
>
> Since the patch only introduces four (4) more opcodes, it is not computationally expensive. Here is the diff:
>
>   test   $0x200000,%eax
>   je     0xb7e214c0 <rdrand+128>
> - xor    %eax,%eax
> + xor    %edi,%edi
> + mov    %edi,%eax
>   cpuid
>   test   %eax,%eax
>   je     0xb7e214c0 <rdrand+128>
> + mov    %edi,%ebx
> + mov    %edi,%ecx
> + mov    %edi,%edx
>   mov    $0x1,%eax
>   cpuid

How about the attached patch that enables zeroing only for 32bit
processors, and only for cpuid leaf 1? Usually, __get_cpuid is used
with a constant leaf argument, so we benefit from constant propagation
into inline function. Also, according to the confusing documentation,
it looks to me that zeroing %ecx and %edx regs should be enough.

Uros.
-------------- next part --------------
Index: config/i386/cpuid.h
===================================================================
--- config/i386/cpuid.h	(revision 271384)
+++ config/i386/cpuid.h	(working copy)
@@ -187,6 +187,14 @@
 #define signature_VORTEX_ecx	0x436f5320
 #define signature_VORTEX_edx	0x36387865
 
+/* 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_compat(level, a, b, c, d)		\
+  __asm__ ("cpuid\n\t"					\
+	   : "=a" (a), "=b" (b), "=c" (c), "=d" (d)	\
+	   : "0" (level), "1" (0), "2" (0))
+
 #define __cpuid(level, a, b, c, d)			\
   __asm__ ("cpuid\n\t"					\
 	   : "=a" (a), "=b" (b), "=c" (c), "=d" (d)	\
@@ -271,7 +279,13 @@
   if (__maxlevel == 0 || __maxlevel < __leaf)
     return 0;
 
-  __cpuid (__leaf, *__eax, *__ebx, *__ecx, *__edx);
+#ifndef __x86_64__
+  if (__leaf == 1)
+    __cpuid_compat (__leaf, *__eax, *__ebx, *__ecx, *__edx);
+  else
+#endif
+    __cpuid (__leaf, *__eax, *__ebx, *__ecx, *__edx);
+
   return 1;
 }
 


More information about the Gcc-patches mailing list