x86: do not allow to optimize flag_is_changeable_p() (rev. 2)

The flag_is_changeable_p() is used by
has_cpuid_p() which can return different results
in the code sequence below:

 if (!have_cpuid_p())
      identify_cpu_without_cpuid(c);

  /* cyrix could have cpuid enabled via c_identify()*/
  if (!have_cpuid_p())
      return;

Otherwise, the gcc 3.4.6 optimizes these two calls
into one which make the code not working correctly.

Cyrix cpus have the CPUID instruction enabled before
the second call to the have_cpuid_p() but
it is not detected due to the gcc optimization.
Thus the ARR registers (mtrr like) are not detected
on such a cpu.

Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
Krzysztof Helt 2008-09-30 23:17:51 +02:00 committed by Ingo Molnar
parent e2ce07c804
commit 94f6bac105
1 changed files with 19 additions and 12 deletions

View File

@ -124,18 +124,25 @@ static inline int flag_is_changeable_p(u32 flag)
{ {
u32 f1, f2; u32 f1, f2;
asm("pushfl\n\t" /*
"pushfl\n\t" * Cyrix and IDT cpus allow disabling of CPUID
"popl %0\n\t" * so the code below may return different results
"movl %0,%1\n\t" * when it is executed before and after enabling
"xorl %2,%0\n\t" * the CPUID. Add "volatile" to not allow gcc to
"pushl %0\n\t" * optimize the subsequent calls to this function.
"popfl\n\t" */
"pushfl\n\t" asm volatile ("pushfl\n\t"
"popl %0\n\t" "pushfl\n\t"
"popfl\n\t" "popl %0\n\t"
: "=&r" (f1), "=&r" (f2) "movl %0,%1\n\t"
: "ir" (flag)); "xorl %2,%0\n\t"
"pushl %0\n\t"
"popfl\n\t"
"pushfl\n\t"
"popl %0\n\t"
"popfl\n\t"
: "=&r" (f1), "=&r" (f2)
: "ir" (flag));
return ((f1^f2) & flag) != 0; return ((f1^f2) & flag) != 0;
} }