15c48b108SAl Viro /* 25c48b108SAl Viro * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 35c48b108SAl Viro * Licensed under the GPL 45c48b108SAl Viro */ 55c48b108SAl Viro 65c48b108SAl Viro #include <signal.h> 7*37185b33SAl Viro #include <kern_util.h> 8*37185b33SAl Viro #include <longjmp.h> 9*37185b33SAl Viro #include <sysdep/ptrace.h> 105ade8878SAl Viro #include <generated/asm-offsets.h> 115c48b108SAl Viro 125c48b108SAl Viro /* Set during early boot */ 135c48b108SAl Viro static int host_has_cmov = 1; 145c48b108SAl Viro static jmp_buf cmov_test_return; 155c48b108SAl Viro 165c48b108SAl Viro static void cmov_sigill_test_handler(int sig) 175c48b108SAl Viro { 185c48b108SAl Viro host_has_cmov = 0; 195c48b108SAl Viro longjmp(cmov_test_return, 1); 205c48b108SAl Viro } 215c48b108SAl Viro 225c48b108SAl Viro void arch_check_bugs(void) 235c48b108SAl Viro { 245c48b108SAl Viro struct sigaction old, new; 255c48b108SAl Viro 265c48b108SAl Viro printk(UM_KERN_INFO "Checking for host processor cmov support..."); 275c48b108SAl Viro new.sa_handler = cmov_sigill_test_handler; 285c48b108SAl Viro 295c48b108SAl Viro /* Make sure that SIGILL is enabled after the handler longjmps back */ 305c48b108SAl Viro new.sa_flags = SA_NODEFER; 315c48b108SAl Viro sigemptyset(&new.sa_mask); 325c48b108SAl Viro sigaction(SIGILL, &new, &old); 335c48b108SAl Viro 345c48b108SAl Viro if (setjmp(cmov_test_return) == 0) { 355c48b108SAl Viro unsigned long foo = 0; 365c48b108SAl Viro __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo)); 375c48b108SAl Viro printk(UM_KERN_CONT "Yes\n"); 385c48b108SAl Viro } else 395c48b108SAl Viro printk(UM_KERN_CONT "No\n"); 405c48b108SAl Viro 415c48b108SAl Viro sigaction(SIGILL, &old, &new); 425c48b108SAl Viro } 435c48b108SAl Viro 445c48b108SAl Viro void arch_examine_signal(int sig, struct uml_pt_regs *regs) 455c48b108SAl Viro { 465c48b108SAl Viro unsigned char tmp[2]; 475c48b108SAl Viro 485c48b108SAl Viro /* 495c48b108SAl Viro * This is testing for a cmov (0x0f 0x4x) instruction causing a 505c48b108SAl Viro * SIGILL in init. 515c48b108SAl Viro */ 52c2220b2aSAl Viro if ((sig != SIGILL) || (get_current_pid() != 1)) 535c48b108SAl Viro return; 545c48b108SAl Viro 555c48b108SAl Viro if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) { 565c48b108SAl Viro printk(UM_KERN_ERR "SIGILL in init, could not read " 575c48b108SAl Viro "instructions!\n"); 585c48b108SAl Viro return; 595c48b108SAl Viro } 605c48b108SAl Viro 615c48b108SAl Viro if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) 625c48b108SAl Viro return; 635c48b108SAl Viro 645c48b108SAl Viro if (host_has_cmov == 0) 655c48b108SAl Viro printk(UM_KERN_ERR "SIGILL caused by cmov, which this " 665c48b108SAl Viro "processor doesn't implement. Boot a filesystem " 675c48b108SAl Viro "compiled for older processors"); 685c48b108SAl Viro else if (host_has_cmov == 1) 695c48b108SAl Viro printk(UM_KERN_ERR "SIGILL caused by cmov, which this " 705c48b108SAl Viro "processor claims to implement"); 715c48b108SAl Viro else 725c48b108SAl Viro printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)", 735c48b108SAl Viro host_has_cmov); 745c48b108SAl Viro } 75