uml: improve detection of host cmov
authorKarol Swietlicki <magotari@gmail.com>
Tue, 5 Feb 2008 06:30:38 +0000 (22:30 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Tue, 5 Feb 2008 17:44:25 +0000 (09:44 -0800)
This patch introduces a new way of checking for the cmov instruction.  I use
signal handling instead of reading /proc/cpuinfo.

[ jdike - Fiddled the asm to make it obvious that it didn't mess with
any in-use registers and made test_for_host_cmov void ]

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: Karol Swietlicki <magotari@gmail.com>
Signed-off-by: Jeff Dike <jdike@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/um/include/common-offsets.h
arch/um/sys-i386/bugs.c

index 0edab695ed4e3e665588435d6bb07074a1b692ad..b54bd35585c2d7c306dd6e6def01c2d958dc9d2b 100644 (file)
@@ -18,6 +18,7 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
 DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
 DEFINE_STR(UM_KERN_INFO, KERN_INFO);
 DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
+DEFINE_STR(UM_KERN_CONT, KERN_CONT);
 
 DEFINE(UM_ELF_CLASS, ELF_CLASS);
 DEFINE(UM_ELFCLASS32, ELFCLASS32);
index 5ee4c366074e66a82806271c48af2319f33d472b..797945cd3df2433f29643fbf95bcf7e0bdc29c55 100644 (file)
 #include "os.h"
 #include "task.h"
 #include "user.h"
+#include "sysdep/archsetjmp.h"
 
 #define MAXTOKEN 64
 
 /* Set during early boot */
 int host_has_cmov = 1;
+static jmp_buf cmov_test_return;
+
+static void cmov_sigill_test_handler(int sig)
+{
+       host_has_cmov = 0;
+       longjmp(cmov_test_return, 1);
+}
+
+static void test_for_host_cmov(void)
+{
+       struct sigaction old, new;
+
+       printk(UM_KERN_INFO "Checking for host processor cmov support...");
+       new.sa_handler = cmov_sigill_test_handler;
+
+       /* Make sure that SIGILL is enabled after the handler longjmps back */
+       new.sa_flags = SA_NODEFER;
+       sigemptyset(&new.sa_mask);
+       sigaction(SIGILL, &new, &old);
+
+       if (setjmp(cmov_test_return) == 0) {
+               unsigned long foo = 0;
+               __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo));
+               printk(UM_KERN_CONT "Yes\n");
+       } else
+               printk(UM_KERN_CONT "No\n");
+
+       sigaction(SIGILL, &old, &new);
+}
 
 static char token(int fd, char *buf, int len, char stop)
 {
@@ -153,15 +183,7 @@ void arch_init_thread(void)
 
 void arch_check_bugs(void)
 {
-       int have_it;
-
-       if (os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0) {
-               printk(UM_KERN_ERR "/proc/cpuinfo not available - skipping CPU "
-                      "capability checks\n");
-               return;
-       }
-       if (check_cpu_flag("cmov", &have_it))
-               host_has_cmov = have_it;
+       test_for_host_cmov();
 }
 
 int arch_handle_signal(int sig, struct uml_pt_regs *regs)