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