blob: fc991184850c0a8f6680d122bc4668afd4076ac8 [file] [log] [blame]
Jeff Dikea5ed1ff2007-05-06 14:50:58 -07001/*
Jeff Dikeba180fd2007-10-16 01:27:00 -07002 * Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * Licensed under the GPL
4 */
5
Linus Torvalds1da177e2005-04-16 15:20:36 -07006#include <errno.h>
Jeff Dikeba180fd2007-10-16 01:27:00 -07007#include <signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <string.h>
Jeff Dikeba180fd2007-10-16 01:27:00 -07009#include "kern_constants.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include "os.h"
Jeff Dikeba180fd2007-10-16 01:27:00 -070011#include "task.h"
12#include "user.h"
Karol Swietlicki235a6f02008-02-04 22:30:38 -080013#include "sysdep/archsetjmp.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
Linus Torvalds1da177e2005-04-16 15:20:36 -070015/* Set during early boot */
16int host_has_cmov = 1;
Karol Swietlicki235a6f02008-02-04 22:30:38 -080017static jmp_buf cmov_test_return;
18
19static void cmov_sigill_test_handler(int sig)
20{
21 host_has_cmov = 0;
22 longjmp(cmov_test_return, 1);
23}
24
25static void test_for_host_cmov(void)
26{
27 struct sigaction old, new;
28
29 printk(UM_KERN_INFO "Checking for host processor cmov support...");
30 new.sa_handler = cmov_sigill_test_handler;
31
32 /* Make sure that SIGILL is enabled after the handler longjmps back */
33 new.sa_flags = SA_NODEFER;
34 sigemptyset(&new.sa_mask);
35 sigaction(SIGILL, &new, &old);
36
37 if (setjmp(cmov_test_return) == 0) {
38 unsigned long foo = 0;
39 __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo));
40 printk(UM_KERN_CONT "Yes\n");
41 } else
42 printk(UM_KERN_CONT "No\n");
43
44 sigaction(SIGILL, &old, &new);
45}
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Linus Torvalds1da177e2005-04-16 15:20:36 -070047void arch_init_thread(void)
48{
Linus Torvalds1da177e2005-04-16 15:20:36 -070049}
50
51void arch_check_bugs(void)
52{
Karol Swietlicki235a6f02008-02-04 22:30:38 -080053 test_for_host_cmov();
Linus Torvalds1da177e2005-04-16 15:20:36 -070054}
55
Jeff Dike77bf4402007-10-16 01:26:58 -070056int arch_handle_signal(int sig, struct uml_pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -070057{
58 unsigned char tmp[2];
59
Jeff Dikeba180fd2007-10-16 01:27:00 -070060 /*
61 * This is testing for a cmov (0x0f 0x4x) instruction causing a
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 * SIGILL in init.
63 */
Jeff Dikeba180fd2007-10-16 01:27:00 -070064 if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070065 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67 if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
68 panic("SIGILL in init, could not read instructions!\n");
Jeff Dikeba180fd2007-10-16 01:27:00 -070069 if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070070 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Jeff Dikeba180fd2007-10-16 01:27:00 -070072 if (host_has_cmov == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 panic("SIGILL caused by cmov, which this processor doesn't "
74 "implement, boot a filesystem compiled for older "
75 "processors");
Jeff Dikeba180fd2007-10-16 01:27:00 -070076 else if (host_has_cmov == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 panic("SIGILL caused by cmov, which this processor claims to "
78 "implement");
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070080 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081}