1*5c48b108SAl Viro /* 2*5c48b108SAl Viro * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 3*5c48b108SAl Viro * Licensed under the GPL 4*5c48b108SAl Viro */ 5*5c48b108SAl Viro 6*5c48b108SAl Viro #include <signal.h> 7*5c48b108SAl Viro #include "kern_util.h" 8*5c48b108SAl Viro #include "longjmp.h" 9*5c48b108SAl Viro #include "task.h" 10*5c48b108SAl Viro #include "sysdep/ptrace.h" 11*5c48b108SAl Viro 12*5c48b108SAl Viro /* Set during early boot */ 13*5c48b108SAl Viro static int host_has_cmov = 1; 14*5c48b108SAl Viro static jmp_buf cmov_test_return; 15*5c48b108SAl Viro 16*5c48b108SAl Viro static void cmov_sigill_test_handler(int sig) 17*5c48b108SAl Viro { 18*5c48b108SAl Viro host_has_cmov = 0; 19*5c48b108SAl Viro longjmp(cmov_test_return, 1); 20*5c48b108SAl Viro } 21*5c48b108SAl Viro 22*5c48b108SAl Viro void arch_check_bugs(void) 23*5c48b108SAl Viro { 24*5c48b108SAl Viro struct sigaction old, new; 25*5c48b108SAl Viro 26*5c48b108SAl Viro printk(UM_KERN_INFO "Checking for host processor cmov support..."); 27*5c48b108SAl Viro new.sa_handler = cmov_sigill_test_handler; 28*5c48b108SAl Viro 29*5c48b108SAl Viro /* Make sure that SIGILL is enabled after the handler longjmps back */ 30*5c48b108SAl Viro new.sa_flags = SA_NODEFER; 31*5c48b108SAl Viro sigemptyset(&new.sa_mask); 32*5c48b108SAl Viro sigaction(SIGILL, &new, &old); 33*5c48b108SAl Viro 34*5c48b108SAl Viro if (setjmp(cmov_test_return) == 0) { 35*5c48b108SAl Viro unsigned long foo = 0; 36*5c48b108SAl Viro __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo)); 37*5c48b108SAl Viro printk(UM_KERN_CONT "Yes\n"); 38*5c48b108SAl Viro } else 39*5c48b108SAl Viro printk(UM_KERN_CONT "No\n"); 40*5c48b108SAl Viro 41*5c48b108SAl Viro sigaction(SIGILL, &old, &new); 42*5c48b108SAl Viro } 43*5c48b108SAl Viro 44*5c48b108SAl Viro void arch_examine_signal(int sig, struct uml_pt_regs *regs) 45*5c48b108SAl Viro { 46*5c48b108SAl Viro unsigned char tmp[2]; 47*5c48b108SAl Viro 48*5c48b108SAl Viro /* 49*5c48b108SAl Viro * This is testing for a cmov (0x0f 0x4x) instruction causing a 50*5c48b108SAl Viro * SIGILL in init. 51*5c48b108SAl Viro */ 52*5c48b108SAl Viro if ((sig != SIGILL) || (TASK_PID(get_current()) != 1)) 53*5c48b108SAl Viro return; 54*5c48b108SAl Viro 55*5c48b108SAl Viro if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) { 56*5c48b108SAl Viro printk(UM_KERN_ERR "SIGILL in init, could not read " 57*5c48b108SAl Viro "instructions!\n"); 58*5c48b108SAl Viro return; 59*5c48b108SAl Viro } 60*5c48b108SAl Viro 61*5c48b108SAl Viro if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) 62*5c48b108SAl Viro return; 63*5c48b108SAl Viro 64*5c48b108SAl Viro if (host_has_cmov == 0) 65*5c48b108SAl Viro printk(UM_KERN_ERR "SIGILL caused by cmov, which this " 66*5c48b108SAl Viro "processor doesn't implement. Boot a filesystem " 67*5c48b108SAl Viro "compiled for older processors"); 68*5c48b108SAl Viro else if (host_has_cmov == 1) 69*5c48b108SAl Viro printk(UM_KERN_ERR "SIGILL caused by cmov, which this " 70*5c48b108SAl Viro "processor claims to implement"); 71*5c48b108SAl Viro else 72*5c48b108SAl Viro printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)", 73*5c48b108SAl Viro host_has_cmov); 74*5c48b108SAl Viro } 75