blob: b0cb05228a97edfcdd202b23b9fd6452f40d5966 [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
Jeff Dikeba180fd2007-10-16 01:27:00 -07006#include <signal.h>
Jeff Dikeba180fd2007-10-16 01:27:00 -07007#include "kern_constants.h"
Jeff Dike9226b832008-02-04 22:30:40 -08008#include "longjmp.h"
Jeff Dikeba180fd2007-10-16 01:27:00 -07009#include "task.h"
10#include "user.h"
Jeff Dike9226b832008-02-04 22:30:40 -080011#include "sysdep/ptrace.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
Linus Torvalds1da177e2005-04-16 15:20:36 -070013/* Set during early boot */
14int host_has_cmov = 1;
Karol Swietlicki235a6f02008-02-04 22:30:38 -080015static jmp_buf cmov_test_return;
16
17static void cmov_sigill_test_handler(int sig)
18{
19 host_has_cmov = 0;
20 longjmp(cmov_test_return, 1);
21}
22
Jeff Dike9226b832008-02-04 22:30:40 -080023void arch_check_bugs(void)
Karol Swietlicki235a6f02008-02-04 22:30:38 -080024{
25 struct sigaction old, new;
26
27 printk(UM_KERN_INFO "Checking for host processor cmov support...");
28 new.sa_handler = cmov_sigill_test_handler;
29
30 /* Make sure that SIGILL is enabled after the handler longjmps back */
31 new.sa_flags = SA_NODEFER;
32 sigemptyset(&new.sa_mask);
33 sigaction(SIGILL, &new, &old);
34
35 if (setjmp(cmov_test_return) == 0) {
36 unsigned long foo = 0;
37 __asm__ __volatile__("cmovz %0, %1" : "=r" (foo) : "0" (foo));
38 printk(UM_KERN_CONT "Yes\n");
39 } else
40 printk(UM_KERN_CONT "No\n");
41
42 sigaction(SIGILL, &old, &new);
43}
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
Jeff Dike9226b832008-02-04 22:30:40 -080045void arch_examine_signal(int sig, struct uml_pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046{
47 unsigned char tmp[2];
48
Jeff Dikeba180fd2007-10-16 01:27:00 -070049 /*
50 * This is testing for a cmov (0x0f 0x4x) instruction causing a
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 * SIGILL in init.
52 */
Jeff Dikeba180fd2007-10-16 01:27:00 -070053 if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
Jeff Dike9226b832008-02-04 22:30:40 -080054 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070055
Jeff Dike9226b832008-02-04 22:30:40 -080056 if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2)) {
57 printk(UM_KERN_ERR "SIGILL in init, could not read "
58 "instructions!\n");
59 return;
60 }
61
Jeff Dikeba180fd2007-10-16 01:27:00 -070062 if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
Jeff Dike9226b832008-02-04 22:30:40 -080063 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Jeff Dikeba180fd2007-10-16 01:27:00 -070065 if (host_has_cmov == 0)
Jeff Dike9226b832008-02-04 22:30:40 -080066 printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
67 "processor doesn't implement. Boot a filesystem "
68 "compiled for older processors");
Jeff Dikeba180fd2007-10-16 01:27:00 -070069 else if (host_has_cmov == 1)
Jeff Dike9226b832008-02-04 22:30:40 -080070 printk(UM_KERN_ERR "SIGILL caused by cmov, which this "
71 "processor claims to implement");
72 else
73 printk(UM_KERN_ERR "Bad value for host_has_cmov (%d)",
74 host_has_cmov);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075}