[PATCH] switch ubd
[safe/jmp/linux-2.6] / arch / um / sys-i386 / bugs.c
index cae0af1..2c6d0d7 100644 (file)
 /*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
  * Licensed under the GPL
  */
 
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/signal.h>
-#include <asm/ldt.h>
+#include <signal.h>
+#include "kern_constants.h"
 #include "kern_util.h"
+#include "longjmp.h"
+#include "task.h"
 #include "user.h"
 #include "sysdep/ptrace.h"
-#include "task.h"
-#include "os.h"
-#include "user_util.h"
-
-#define MAXTOKEN 64
 
 /* Set during early boot */
-int host_has_cmov = 1;
-int host_has_xmm = 0;
+static int host_has_cmov = 1;
+static jmp_buf cmov_test_return;
 
-static char token(int fd, char *buf, int len, char stop)
+static void cmov_sigill_test_handler(int sig)
 {
-       int n;
-       char *ptr, *end, c;
-
-       ptr = buf;
-       end = &buf[len];
-       do {
-               n = os_read_file(fd, ptr, sizeof(*ptr));
-               c = *ptr++;
-               if(n != sizeof(*ptr)){
-                       if(n == 0)
-                               return 0;
-                       printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
-                       if(n < 0)
-                               return n;
-                       else return -EIO;
-               }
-       } while((c != '\n') && (c != stop) && (ptr < end));
-
-       if(ptr == end){
-               printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
-               return -1;
-       }
-       *(ptr - 1) = '\0';
-       return c;
+       host_has_cmov = 0;
+       longjmp(cmov_test_return, 1);
 }
 
-static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
-{
-       int n;
-       char c;
-
-       scratch[len - 1] = '\0';
-       while(1){
-               c = token(fd, scratch, len - 1, ':');
-               if(c <= 0)
-                       return 0;
-               else if(c != ':'){
-                       printk("Failed to find ':' in /proc/cpuinfo\n");
-                       return 0;
-               }
-
-               if(!strncmp(scratch, key, strlen(key)))
-                       return 1;
-
-               do {
-                       n = os_read_file(fd, &c, sizeof(c));
-                       if(n != sizeof(c)){
-                               printk("Failed to find newline in "
-                                      "/proc/cpuinfo, err = %d\n", -n);
-                               return 0;
-                       }
-               } while(c != '\n');
-       }
-       return 0;
-}
-
-static int check_cpu_flag(char *feature, int *have_it)
-{
-       char buf[MAXTOKEN], c;
-       int fd, len = ARRAY_SIZE(buf);
-
-       printk("Checking for host processor %s support...", feature);
-       fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
-       if(fd < 0){
-               printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
-               return 0;
-       }
-
-       *have_it = 0;
-       if(!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf)))
-               goto out;
-
-       c = token(fd, buf, len - 1, ' ');
-       if(c < 0)
-               goto out;
-       else if(c != ' '){
-               printk("Failed to find ' ' in /proc/cpuinfo\n");
-               goto out;
-       }
-
-       while(1){
-               c = token(fd, buf, len - 1, ' ');
-               if(c < 0)
-                       goto out;
-               else if(c == '\n') break;
-
-               if(!strcmp(buf, feature)){
-                       *have_it = 1;
-                       goto out;
-               }
-       }
- out:
-       if(*have_it == 0)
-               printk("No\n");
-       else if(*have_it == 1)
-               printk("Yes\n");
-       os_close_file(fd);
-       return 1;
-}
-
-#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
-       * for some people.
-       */
-static void disable_lcall(void)
+void arch_check_bugs(void)
 {
-       struct modify_ldt_ldt_s ldt;
-       int err;
+       struct sigaction old, new;
 
-       bzero(&ldt, sizeof(ldt));
-       ldt.entry_number = 7;
-       ldt.base_addr = 0;
-       ldt.limit = 0;
-       err = modify_ldt(1, &ldt, sizeof(ldt));
-       if(err)
-               printk("Failed to disable lcall7 - errno = %d\n", errno);
-}
-#endif
+       printk(UM_KERN_INFO "Checking for host processor cmov support...");
+       new.sa_handler = cmov_sigill_test_handler;
 
-void arch_init_thread(void)
-{
-#if 0
-       disable_lcall();
-#endif
-}
+       /* Make sure that SIGILL is enabled after the handler longjmps back */
+       new.sa_flags = SA_NODEFER;
+       sigemptyset(&new.sa_mask);
+       sigaction(SIGILL, &new, &old);
 
-void arch_check_bugs(void)
-{
-       int have_it;
+       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");
 
-       if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
-               printk("/proc/cpuinfo not available - skipping CPU capability "
-                      "checks\n");
-               return;
-       }
-       if(check_cpu_flag("cmov", &have_it))
-               host_has_cmov = have_it;
-       if(check_cpu_flag("xmm", &have_it))
-               host_has_xmm = have_it;
+       sigaction(SIGILL, &old, &new);
 }
 
-int arch_handle_signal(int sig, union uml_pt_regs *regs)
+void arch_examine_signal(int sig, struct uml_pt_regs *regs)
 {
        unsigned char tmp[2];
 
-       /* This is testing for a cmov (0x0f 0x4x) instruction causing a
+       /*
+        * This is testing for a cmov (0x0f 0x4x) instruction causing a
         * SIGILL in init.
         */
-       if((sig != SIGILL) || (TASK_PID(get_current()) != 1))
-               return 0;
+       if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
+               return;
 
-       if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
-               panic("SIGILL in init, could not read instructions!\n");
-       if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
-               return 0;
+       if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) {
+               printk(UM_KERN_ERR "SIGILL in init, could not read "
+                      "instructions!\n");
+               return;
+       }
+
+       if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
+               return;
 
-       if(host_has_cmov == 0)
-               panic("SIGILL caused by cmov, which this processor doesn't "
-                     "implement, boot a filesystem compiled for older "
-                     "processors");
-       else if(host_has_cmov == 1)
-               panic("SIGILL caused by cmov, which this processor claims to "
-                     "implement");
-       else if(host_has_cmov == -1)
-               panic("SIGILL caused by cmov, couldn't tell if this processor "
-                     "implements it, boot a filesystem compiled for older "
-                     "processors");
-       else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
-       return 0;
+       if (host_has_cmov == 0)
+               printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
+                      "processor doesn't implement.  Boot a filesystem "
+                      "compiled for older processors");
+       else if (host_has_cmov == 1)
+               printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
+                      "processor claims to implement");
+       else
+               printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)",
+                       host_has_cmov);
 }