
One problem with the cpuid instruction is that it uses %ebx which, when code is compiled as PIC for i386, is used as the PIC base register. This patch tries to handle this case by replacing the second register (%1) constraint with "=r", i.e. any (other) register, and swapping %ebx and %1 around the cpuid instruction. This patch could use a test, preferably on real i686 hardware. At least it needs some review and perhaps inspection of the generated assembler output. The idea and reasoning was taken from this comment: http://gcc.gnu.org/ml/gcc-patches/2007-09/msg00324.html
34 lines
926 B
Diff
34 lines
926 B
Diff
--- utils/cpuid.h 2010-07-05 17:43:17.000000000 +0200
|
|
+++ utils/cpuid.h 2016-10-13 22:31:26.988374329 +0200
|
|
@@ -1,6 +1,21 @@
|
|
#ifndef _CPUFREQ_CPUID_H
|
|
#define _CPUFREQ_CPUID_H
|
|
|
|
+#if defined(__i386__) && defined(__PIC__)
|
|
+static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
|
|
+ unsigned int *ecx, unsigned int *edx)
|
|
+{
|
|
+ /* ecx is often an input as well as an output. */
|
|
+ asm volatile("xchgl\t%%ebx, %1\n\t" \
|
|
+ "cpuid\n\t" \
|
|
+ "xchgl\t%%ebx, %1"
|
|
+ : "=a" (*eax),
|
|
+ "=r" (*ebx),
|
|
+ "=c" (*ecx),
|
|
+ "=d" (*edx)
|
|
+ : "0" (*eax), "2" (*ecx));
|
|
+}
|
|
+#else
|
|
static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
|
|
unsigned int *ecx, unsigned int *edx)
|
|
{
|
|
@@ -12,6 +27,8 @@
|
|
"=d" (*edx)
|
|
: "0" (*eax), "2" (*ecx));
|
|
}
|
|
+#endif
|
|
+
|
|
static inline void cpuid(unsigned int op,
|
|
unsigned int *eax, unsigned int *ebx,
|
|
unsigned int *ecx, unsigned int *edx)
|