From 235a6f06eb5571db600a743cda7c73fd4f74127f Mon Sep 17 00:00:00 2001 From: Karol Swietlicki Date: Mon, 4 Feb 2008 22:30:38 -0800 Subject: uml: improve detection of host cmov 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 Signed-off-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/include/common-offsets.h | 1 + arch/um/sys-i386/bugs.c | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index 0edab695ed4..b54bd35585c 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h @@ -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); diff --git a/arch/um/sys-i386/bugs.c b/arch/um/sys-i386/bugs.c index 5ee4c366074..797945cd3df 100644 --- a/arch/um/sys-i386/bugs.c +++ b/arch/um/sys-i386/bugs.c @@ -10,11 +10,41 @@ #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) -- cgit v1.2.3