blob: 5ee4c366074e66a82806271c48af2319f33d472b [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"
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
14#define MAXTOKEN 64
15
16/* Set during early boot */
17int host_has_cmov = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
19static char token(int fd, char *buf, int len, char stop)
20{
21 int n;
22 char *ptr, *end, c;
23
24 ptr = buf;
25 end = &buf[len];
26 do {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -070027 n = os_read_file(fd, ptr, sizeof(*ptr));
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 c = *ptr++;
Jeff Dikeba180fd2007-10-16 01:27:00 -070029 if (n != sizeof(*ptr)) {
30 if (n == 0)
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070031 return 0;
Jeff Dikeba180fd2007-10-16 01:27:00 -070032 printk(UM_KERN_ERR "Reading /proc/cpuinfo failed, "
33 "err = %d\n", -n);
34 if (n < 0)
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070035 return n;
36 else return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 }
Jeff Dikeba180fd2007-10-16 01:27:00 -070038 } while ((c != '\n') && (c != stop) && (ptr < end));
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Jeff Dikeba180fd2007-10-16 01:27:00 -070040 if (ptr == end) {
41 printk(UM_KERN_ERR "Failed to find '%c' in /proc/cpuinfo\n",
42 stop);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070043 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 }
45 *(ptr - 1) = '\0';
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070046 return c;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047}
48
49static int find_cpuinfo_line(int fd, char *key, char *scratch, int len)
50{
51 int n;
52 char c;
53
54 scratch[len - 1] = '\0';
Jeff Dikeba180fd2007-10-16 01:27:00 -070055 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 c = token(fd, scratch, len - 1, ':');
Jeff Dikeba180fd2007-10-16 01:27:00 -070057 if (c <= 0)
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070058 return 0;
Jeff Dikeba180fd2007-10-16 01:27:00 -070059 else if (c != ':') {
60 printk(UM_KERN_ERR "Failed to find ':' in "
61 "/proc/cpuinfo\n");
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070062 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 }
64
Jeff Dikeba180fd2007-10-16 01:27:00 -070065 if (!strncmp(scratch, key, strlen(key)))
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070066 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68 do {
Jeff Dikea6ea4cc2007-05-06 14:51:43 -070069 n = os_read_file(fd, &c, sizeof(c));
Jeff Dikeba180fd2007-10-16 01:27:00 -070070 if (n != sizeof(c)) {
71 printk(UM_KERN_ERR "Failed to find newline in "
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 "/proc/cpuinfo, err = %d\n", -n);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070073 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 }
Jeff Dikeba180fd2007-10-16 01:27:00 -070075 } while (c != '\n');
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 }
Jeff Dikea5ed1ff2007-05-06 14:50:58 -070077 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078}
79
Linus Torvalds1da177e2005-04-16 15:20:36 -070080static int check_cpu_flag(char *feature, int *have_it)
81{
82 char buf[MAXTOKEN], c;
Jeff Dike91b165c2006-09-25 23:33:00 -070083 int fd, len = ARRAY_SIZE(buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Jeff Dikeba180fd2007-10-16 01:27:00 -070085 printk(UM_KERN_INFO "Checking for host processor %s support...",
86 feature);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 fd = os_open_file("/proc/cpuinfo", of_read(OPENFLAGS()), 0);
Jeff Dikeba180fd2007-10-16 01:27:00 -070088 if (fd < 0) {
89 printk(UM_KERN_ERR "Couldn't open /proc/cpuinfo, err = %d\n",
90 -fd);
Jeff Dike91b165c2006-09-25 23:33:00 -070091 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 }
93
94 *have_it = 0;
Jeff Dikeba180fd2007-10-16 01:27:00 -070095 if (!find_cpuinfo_line(fd, "flags", buf, ARRAY_SIZE(buf)))
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 goto out;
97
98 c = token(fd, buf, len - 1, ' ');
Jeff Dikeba180fd2007-10-16 01:27:00 -070099 if (c < 0)
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700100 goto out;
Jeff Dikeba180fd2007-10-16 01:27:00 -0700101 else if (c != ' ') {
102 printk(UM_KERN_ERR "Failed to find ' ' in /proc/cpuinfo\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 goto out;
104 }
105
Jeff Dikeba180fd2007-10-16 01:27:00 -0700106 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 c = token(fd, buf, len - 1, ' ');
Jeff Dikeba180fd2007-10-16 01:27:00 -0700108 if (c < 0)
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700109 goto out;
Jeff Dikeba180fd2007-10-16 01:27:00 -0700110 else if (c == '\n')
111 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
Jeff Dikeba180fd2007-10-16 01:27:00 -0700113 if (!strcmp(buf, feature)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 *have_it = 1;
115 goto out;
116 }
117 }
118 out:
Jeff Dikeba180fd2007-10-16 01:27:00 -0700119 if (*have_it == 0)
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700120 printk("No\n");
Jeff Dikeba180fd2007-10-16 01:27:00 -0700121 else if (*have_it == 1)
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700122 printk("Yes\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 os_close_file(fd);
Jeff Dike91b165c2006-09-25 23:33:00 -0700124 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
126
Jeff Dikeba180fd2007-10-16 01:27:00 -0700127#if 0 /*
128 * This doesn't work in tt mode, plus it's causing compilation problems
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 * for some people.
130 */
131static void disable_lcall(void)
132{
133 struct modify_ldt_ldt_s ldt;
134 int err;
135
136 bzero(&ldt, sizeof(ldt));
137 ldt.entry_number = 7;
138 ldt.base_addr = 0;
139 ldt.limit = 0;
140 err = modify_ldt(1, &ldt, sizeof(ldt));
Jeff Dikeba180fd2007-10-16 01:27:00 -0700141 if (err)
142 printk(UM_KERN_ERR "Failed to disable lcall7 - errno = %d\n",
143 errno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144}
145#endif
146
147void arch_init_thread(void)
148{
149#if 0
150 disable_lcall();
151#endif
152}
153
154void arch_check_bugs(void)
155{
156 int have_it;
157
Jeff Dikeba180fd2007-10-16 01:27:00 -0700158 if (os_access("/proc/cpuinfo", OS_ACC_R_OK) < 0) {
159 printk(UM_KERN_ERR "/proc/cpuinfo not available - skipping CPU "
160 "capability checks\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return;
162 }
Jeff Dikeba180fd2007-10-16 01:27:00 -0700163 if (check_cpu_flag("cmov", &have_it))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 host_has_cmov = have_it;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165}
166
Jeff Dike77bf4402007-10-16 01:26:58 -0700167int arch_handle_signal(int sig, struct uml_pt_regs *regs)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168{
169 unsigned char tmp[2];
170
Jeff Dikeba180fd2007-10-16 01:27:00 -0700171 /*
172 * This is testing for a cmov (0x0f 0x4x) instruction causing a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 * SIGILL in init.
174 */
Jeff Dikeba180fd2007-10-16 01:27:00 -0700175 if ((sig != SIGILL) || (TASK_PID(get_current()) != 1))
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700176 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177
178 if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
179 panic("SIGILL in init, could not read instructions!\n");
Jeff Dikeba180fd2007-10-16 01:27:00 -0700180 if ((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700181 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Jeff Dikeba180fd2007-10-16 01:27:00 -0700183 if (host_has_cmov == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 panic("SIGILL caused by cmov, which this processor doesn't "
185 "implement, boot a filesystem compiled for older "
186 "processors");
Jeff Dikeba180fd2007-10-16 01:27:00 -0700187 else if (host_has_cmov == 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 panic("SIGILL caused by cmov, which this processor claims to "
189 "implement");
Jeff Dikeba180fd2007-10-16 01:27:00 -0700190 else if (host_has_cmov == -1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 panic("SIGILL caused by cmov, couldn't tell if this processor "
192 "implements it, boot a filesystem compiled for older "
193 "processors");
194 else panic("Bad value for host_has_cmov (%d)", host_has_cmov);
Jeff Dikea5ed1ff2007-05-06 14:50:58 -0700195 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196}