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

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Linux Kernel Mailing List
Date: Monday, October 13, 2008 - 11:09 am

Gitweb:     http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=94f6ba...
Commit:     94f6bac1058fd59a8bd472d18c4b77f220d930b0
Parent:     e2ce07c8042975e52df4cec1f41faf15b83f2e42
Author:     Krzysztof Helt <krzysztof.h1@wp.pl>
AuthorDate: Tue Sep 30 23:17:51 2008 +0200
Committer:  Ingo Molnar <mingo@elte.hu>
CommitDate: Mon Oct 13 10:33:13 2008 +0200

    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>
---
 arch/x86/kernel/cpu/common.c |   31 +++++++++++++++++++------------
 1 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index f1af718..25581dc 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -124,18 +124,25 @@ static inline int flag_is_changeable_p(u32 flag)
 {
 	u32 f1, f2;
 
-	asm("pushfl\n\t"
-	    "pushfl\n\t"
-	    "popl %0\n\t"
-	    "movl %0,%1\n\t"
-	    "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));
+	/*
+	 * Cyrix and IDT cpus allow disabling of CPUID
+	 * so the code below may return different results
+	 * when it is executed before and after enabling
+	 * the CPUID. Add "volatile" to not allow gcc to
+	 * optimize the subsequent calls to this function.
+	 */
+	asm volatile ("pushfl\n\t"
+		      "pushfl\n\t"
+		      "popl %0\n\t"
+		      "movl %0,%1\n\t"
+		      "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;
 }
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
x86: do not allow to optimize flag_is_changeable_p() (rev. 2), Linux Kernel Mailing ..., (Mon Oct 13, 11:09 am)