18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) 38c2ecf20Sopenharmony_ci * Licensed under the GPL 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <signal.h> 78c2ecf20Sopenharmony_ci#include <kern_util.h> 88c2ecf20Sopenharmony_ci#include <longjmp.h> 98c2ecf20Sopenharmony_ci#include <sysdep/ptrace.h> 108c2ecf20Sopenharmony_ci#include <generated/asm-offsets.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci/* Set during early boot */ 138c2ecf20Sopenharmony_cistatic int host_has_cmov = 1; 148c2ecf20Sopenharmony_cistatic jmp_buf cmov_test_return; 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic void cmov_sigill_test_handler(int sig) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci host_has_cmov = 0; 198c2ecf20Sopenharmony_ci longjmp(cmov_test_return, 1); 208c2ecf20Sopenharmony_ci} 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_civoid arch_check_bugs(void) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct sigaction old, new; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci printk(UM_KERN_INFO "Checking for host processor cmov support..."); 278c2ecf20Sopenharmony_ci new.sa_handler = cmov_sigill_test_handler; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci /* Make sure that SIGILL is enabled after the handler longjmps back */ 308c2ecf20Sopenharmony_ci new.sa_flags = SA_NODEFER; 318c2ecf20Sopenharmony_ci sigemptyset(&new.sa_mask); 328c2ecf20Sopenharmony_ci sigaction(SIGILL, &new, &old); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (setjmp(cmov_test_return) == 0) { 358c2ecf20Sopenharmony_ci unsigned long foo = 0; 368c2ecf20Sopenharmony_ci __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo)); 378c2ecf20Sopenharmony_ci printk(UM_KERN_CONT "Yes\n"); 388c2ecf20Sopenharmony_ci } else 398c2ecf20Sopenharmony_ci printk(UM_KERN_CONT "No\n"); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci sigaction(SIGILL, &old, &new); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_civoid arch_examine_signal(int sig, struct uml_pt_regs *regs) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci unsigned char tmp[2]; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * This is testing for a cmov (0x0f 0x4x) instruction causing a 508c2ecf20Sopenharmony_ci * SIGILL in init. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ci if ((sig != SIGILL) || (get_current_pid() != 1)) 538c2ecf20Sopenharmony_ci return; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) { 568c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "SIGILL in init, could not read " 578c2ecf20Sopenharmony_ci "instructions!\n"); 588c2ecf20Sopenharmony_ci return; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40)) 628c2ecf20Sopenharmony_ci return; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (host_has_cmov == 0) 658c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "SIGILL caused by cmov, which this " 668c2ecf20Sopenharmony_ci "processor doesn't implement. Boot a filesystem " 678c2ecf20Sopenharmony_ci "compiled for older processors"); 688c2ecf20Sopenharmony_ci else if (host_has_cmov == 1) 698c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "SIGILL caused by cmov, which this " 708c2ecf20Sopenharmony_ci "processor claims to implement"); 718c2ecf20Sopenharmony_ci else 728c2ecf20Sopenharmony_ci printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)", 738c2ecf20Sopenharmony_ci host_has_cmov); 748c2ecf20Sopenharmony_ci} 75