bugs.c 4.0 KB
Newer Older
J
Jeff Dike 已提交
1
/*
L
Linus Torvalds 已提交
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
 * Licensed under the GPL
 */

#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/signal.h>
#include <asm/ldt.h>
#include "kern_util.h"
#include "user.h"
#include "sysdep/ptrace.h"
#include "task.h"
#include "os.h"

#define MAXTOKEN 64

/* Set during early boot */
int host_has_cmov = 1;
int host_has_xmm = 0;

static char token(int fd, char *buf, int len, char stop)
{
	int n;
	char *ptr, *end, c;

	ptr = buf;
	end = &buf[len];
	do {
31
		n = os_read_file_k(fd, ptr, sizeof(*ptr));
L
Linus Torvalds 已提交
32 33
		c = *ptr++;
		if(n != sizeof(*ptr)){
J
Jeff Dike 已提交
34 35
			if(n == 0)
				return 0;
L
Linus Torvalds 已提交
36 37
			printk("Reading /proc/cpuinfo failed, err = %d\n", -n);
			if(n < 0)
J
Jeff Dike 已提交
38 39
				return n;
			else return -EIO;
L
Linus Torvalds 已提交
40 41 42 43 44
		}
	} while((c != '\n') && (c != stop) && (ptr < end));

	if(ptr == end){
		printk("Failed to find '%c' in /proc/cpuinfo\n", stop);
J
Jeff Dike 已提交
45
		return -1;
L
Linus Torvalds 已提交
46 47
	}
	*(ptr - 1) = '\0';
J
Jeff Dike 已提交
48
	return c;
L
Linus Torvalds 已提交
49 50 51 52 53 54 55 56 57 58 59
}

static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
{
	int n;
	char c;

	scratch[len - 1] = '\0';
	while(1){
		c = token(fd, scratch, len - 1, ':');
		if(c <= 0)
J
Jeff Dike 已提交
60
			return 0;
L
Linus Torvalds 已提交
61 62
		else if(c != ':'){
			printk("Failed to find ':' in /proc/cpuinfo\n");
J
Jeff Dike 已提交
63
			return 0;
L
Linus Torvalds 已提交
64 65 66
		}

		if(!strncmp(scratch, key, strlen(key)))
J
Jeff Dike 已提交
67
			return 1;
L
Linus Torvalds 已提交
68 69

		do {
70
			n = os_read_file_k(fd, &c, sizeof(c));
L
Linus Torvalds 已提交
71 72 73
			if(n != sizeof(c)){
				printk("Failed to find newline in "
				       "/proc/cpuinfo, err = %d\n", -n);
J
Jeff Dike 已提交
74
				return 0;
L
Linus Torvalds 已提交
75 76 77
			}
		} while(c != '\n');
	}
J
Jeff Dike 已提交
78
	return 0;
L
Linus Torvalds 已提交
79 80 81 82 83
}

static int check_cpu_flag(char *feature, int *have_it)
{
	char buf[MAXTOKEN], c;
84
	int fd, len = ARRAY_SIZE(buf);
L
Linus Torvalds 已提交
85 86 87 88 89

	printk("Checking for host processor %s support...", feature);
	fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
	if(fd < 0){
		printk("Couldn't open /proc/cpuinfo, err = %d\n", -fd);
90
		return 0;
L
Linus Torvalds 已提交
91 92 93
	}

	*have_it = 0;
94
	if(!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf)))
L
Linus Torvalds 已提交
95 96 97
		goto out;

	c = token(fd, buf, len - 1, ' ');
J
Jeff Dike 已提交
98 99
	if(c < 0)
		goto out;
L
Linus Torvalds 已提交
100 101 102 103 104 105 106
	else if(c != ' '){
		printk("Failed to find ' ' in /proc/cpuinfo\n");
		goto out;
	}

	while(1){
		c = token(fd, buf, len - 1, ' ');
J
Jeff Dike 已提交
107 108
		if(c < 0)
			goto out;
L
Linus Torvalds 已提交
109 110 111 112 113 114 115 116
		else if(c == '\n') break;

		if(!strcmp(buf, feature)){
			*have_it = 1;
			goto out;
		}
	}
 out:
J
Jeff Dike 已提交
117 118 119 120
	if(*have_it == 0)
		printk("No\n");
	else if(*have_it == 1)
		printk("Yes\n");
L
Linus Torvalds 已提交
121
	os_close_file(fd);
122
	return 1;
L
Linus Torvalds 已提交
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
}

#if 0 /* This doesn't work in tt mode, plus it's causing compilation problems
       * for some people.
       */
static void disable_lcall(void)
{
	struct modify_ldt_ldt_s ldt;
	int err;

	bzero(&ldt, sizeof(ldt));
	ldt.entry_number = 7;
	ldt.base_addr = 0;
	ldt.limit = 0;
	err = modify_ldt(1, &ldt, sizeof(ldt));
	if(err)
		printk("Failed to disable lcall7 - errno = %d\n", errno);
}
#endif

void arch_init_thread(void)
{
#if 0
	disable_lcall();
#endif
}

void arch_check_bugs(void)
{
	int have_it;

	if(os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0){
		printk("/proc/cpuinfo not available - skipping CPU capability "
		       "checks\n");
		return;
	}
	if(check_cpu_flag("cmov", &have_it))
		host_has_cmov = have_it;
	if(check_cpu_flag("xmm", &have_it))
		host_has_xmm = have_it;
}

int arch_handle_signal(int sig, union uml_pt_regs *regs)
{
	unsigned char tmp[2];

	/* This is testing for a cmov (0x0f 0x4x) instruction causing a
	 * SIGILL in init.
	 */
J
Jeff Dike 已提交
172 173
	if((sig != SIGILL) || (TASK_PID(get_current()) != 1))
		return 0;
L
Linus Torvalds 已提交
174 175 176 177

	if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
		panic("SIGILL in init, could not read instructions!\n");
	if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
J
Jeff Dike 已提交
178
		return 0;
L
Linus Torvalds 已提交
179 180 181 182 183 184 185 186 187 188 189 190 191

	if(host_has_cmov == 0)
		panic("SIGILL caused by cmov, which this processor doesn't "
		      "implement, boot a filesystem compiled for older "
		      "processors");
	else if(host_has_cmov == 1)
		panic("SIGILL caused by cmov, which this processor claims to "
		      "implement");
	else if(host_has_cmov == -1)
		panic("SIGILL caused by cmov, couldn't tell if this processor "
		      "implements it, boot a filesystem compiled for older "
		      "processors");
	else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
J
Jeff Dike 已提交
192
	return 0;
L
Linus Torvalds 已提交
193
}