47 |
47 |
#endif
|
48 |
48 |
#endif /* USE_CODE_COPY */
|
49 |
49 |
|
|
50 |
static struct x86_def_t *x86_cpu_def;
|
|
51 |
typedef struct x86_def_t x86_def_t;
|
|
52 |
static int cpu_x86_register (CPUX86State *env, const x86_def_t *def);
|
|
53 |
|
|
54 |
static void add_flagname_to_bitmaps(char *flagname, uint32_t *features,
|
|
55 |
uint32_t *ext_features,
|
|
56 |
uint32_t *ext2_features,
|
|
57 |
uint32_t *ext3_features)
|
|
58 |
{
|
|
59 |
int i;
|
|
60 |
/* feature flags taken from "Intel Processor Identification and the CPUID
|
|
61 |
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
|
|
62 |
* about feature names, the Linux name is used. */
|
|
63 |
const char *feature_name[] = {
|
|
64 |
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
|
65 |
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
|
|
66 |
"pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx",
|
|
67 |
"fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe",
|
|
68 |
};
|
|
69 |
const char *ext_feature_name[] = {
|
|
70 |
"pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est",
|
|
71 |
"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
|
|
72 |
NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
|
|
73 |
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
74 |
};
|
|
75 |
const char *ext2_feature_name[] = {
|
|
76 |
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
|
77 |
"cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mttr", "pge", "mca", "cmov",
|
|
78 |
"pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx",
|
|
79 |
"fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
|
|
80 |
};
|
|
81 |
const char *ext3_feature_name[] = {
|
|
82 |
"lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
|
|
83 |
"3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL,
|
|
84 |
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
85 |
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
86 |
};
|
|
87 |
|
|
88 |
for ( i = 0 ; i < 32 ; i++ )
|
|
89 |
if (feature_name[i] && !strcmp (flagname, feature_name[i])) {
|
|
90 |
*features |= 1 << i;
|
|
91 |
return;
|
|
92 |
}
|
|
93 |
for ( i = 0 ; i < 32 ; i++ )
|
|
94 |
if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) {
|
|
95 |
*ext_features |= 1 << i;
|
|
96 |
return;
|
|
97 |
}
|
|
98 |
for ( i = 0 ; i < 32 ; i++ )
|
|
99 |
if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) {
|
|
100 |
*ext2_features |= 1 << i;
|
|
101 |
return;
|
|
102 |
}
|
|
103 |
for ( i = 0 ; i < 32 ; i++ )
|
|
104 |
if (ext3_features[i] && !strcmp (flagname, ext3_feature_name[i])) {
|
|
105 |
*ext3_features |= 1 << i;
|
|
106 |
return;
|
|
107 |
}
|
|
108 |
fprintf(stderr, "CPU feature %s not found\n", flagname);
|
|
109 |
}
|
|
110 |
|
50 |
111 |
CPUX86State *cpu_x86_init(void)
|
51 |
112 |
{
|
52 |
113 |
CPUX86State *env;
|
... | ... | |
81 |
142 |
asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
|
82 |
143 |
}
|
83 |
144 |
#endif
|
84 |
|
{
|
85 |
|
int family, model, stepping;
|
86 |
|
#ifdef TARGET_X86_64
|
87 |
|
env->cpuid_vendor1 = 0x68747541; /* "Auth" */
|
88 |
|
env->cpuid_vendor2 = 0x69746e65; /* "enti" */
|
89 |
|
env->cpuid_vendor3 = 0x444d4163; /* "cAMD" */
|
90 |
|
family = 6;
|
91 |
|
model = 2;
|
92 |
|
stepping = 3;
|
93 |
|
#else
|
94 |
|
env->cpuid_vendor1 = 0x756e6547; /* "Genu" */
|
95 |
|
env->cpuid_vendor2 = 0x49656e69; /* "ineI" */
|
96 |
|
env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */
|
97 |
|
#if 0
|
98 |
|
/* pentium 75-200 */
|
99 |
|
family = 5;
|
100 |
|
model = 2;
|
101 |
|
stepping = 11;
|
102 |
|
#else
|
103 |
|
/* pentium pro */
|
104 |
|
family = 6;
|
105 |
|
model = 3;
|
106 |
|
stepping = 3;
|
107 |
|
#endif
|
|
145 |
cpu_x86_register(env, x86_cpu_def);
|
|
146 |
cpu_reset(env);
|
|
147 |
#ifdef USE_KQEMU
|
|
148 |
kqemu_init(env);
|
108 |
149 |
#endif
|
109 |
|
env->cpuid_level = 2;
|
110 |
|
env->cpuid_version = (family << 8) | (model << 4) | stepping;
|
111 |
|
env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
|
112 |
|
CPUID_TSC | CPUID_MSR | CPUID_MCE |
|
113 |
|
CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
|
114 |
|
CPUID_PAT);
|
115 |
|
env->pat = 0x0007040600070406ULL;
|
116 |
|
env->cpuid_ext3_features = CPUID_EXT3_SVM;
|
117 |
|
env->cpuid_ext_features = CPUID_EXT_SSE3;
|
118 |
|
env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
|
119 |
|
env->cpuid_features |= CPUID_APIC;
|
120 |
|
env->cpuid_xlevel = 0x8000000e;
|
121 |
|
{
|
122 |
|
const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION;
|
123 |
|
int c, len, i;
|
124 |
|
len = strlen(model_id);
|
125 |
|
for(i = 0; i < 48; i++) {
|
126 |
|
if (i >= len)
|
127 |
|
c = '\0';
|
128 |
|
else
|
129 |
|
c = model_id[i];
|
130 |
|
env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
|
131 |
|
}
|
132 |
|
}
|
133 |
|
#ifdef TARGET_X86_64
|
134 |
|
/* currently not enabled for std i386 because not fully tested */
|
135 |
|
env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
|
136 |
|
env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
|
|
150 |
return env;
|
|
151 |
}
|
|
152 |
|
|
153 |
struct x86_def_t {
|
|
154 |
const char *name;
|
|
155 |
uint32_t vendor1, vendor2, vendor3;
|
|
156 |
int family;
|
|
157 |
int model;
|
|
158 |
int stepping;
|
|
159 |
uint32_t features, ext_features, ext2_features, ext3_features;
|
|
160 |
uint32_t xlevel;
|
|
161 |
};
|
137 |
162 |
|
|
163 |
#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
|
|
164 |
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
|
|
165 |
CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
|
|
166 |
CPUID_PAE | CPUID_SEP | CPUID_APIC)
|
|
167 |
static x86_def_t x86_defs[] = {
|
|
168 |
#ifdef TARGET_X86_64
|
|
169 |
{
|
|
170 |
.name = "qemu64",
|
|
171 |
.vendor1 = 0x68747541, /* "Auth" */
|
|
172 |
.vendor2 = 0x69746e65, /* "enti" */
|
|
173 |
.vendor3 = 0x444d4163, /* "cAMD" */
|
|
174 |
.family = 6,
|
|
175 |
.model = 2,
|
|
176 |
.stepping = 3,
|
|
177 |
.features = PPRO_FEATURES |
|
138 |
178 |
/* these features are needed for Win64 and aren't fully implemented */
|
139 |
|
env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
|
|
179 |
CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
|
140 |
180 |
/* this feature is needed for Solaris and isn't fully implemented */
|
141 |
|
env->cpuid_features |= CPUID_PSE36;
|
|
181 |
CPUID_PSE36,
|
|
182 |
.ext_features = CPUID_EXT_SSE3,
|
|
183 |
.ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
|
|
184 |
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
|
|
185 |
.ext3_features = CPUID_EXT3_SVM,
|
|
186 |
.xlevel = 0x80000008,
|
|
187 |
},
|
142 |
188 |
#endif
|
|
189 |
{
|
|
190 |
.name = "qemu32",
|
|
191 |
.family = 6,
|
|
192 |
.model = 3,
|
|
193 |
.stepping = 3,
|
|
194 |
.features = PPRO_FEATURES,
|
|
195 |
.ext_features = CPUID_EXT_SSE3,
|
|
196 |
.xlevel = 0,
|
|
197 |
},
|
|
198 |
{
|
|
199 |
.name = "486",
|
|
200 |
.family = 4,
|
|
201 |
.model = 0,
|
|
202 |
.stepping = 0,
|
|
203 |
.features = 0x0000000B,
|
|
204 |
.xlevel = 0,
|
|
205 |
},
|
|
206 |
{
|
|
207 |
.name = "pentium",
|
|
208 |
.family = 5,
|
|
209 |
.model = 4,
|
|
210 |
.stepping = 3,
|
|
211 |
.features = 0x008001BF,
|
|
212 |
.xlevel = 0,
|
|
213 |
},
|
|
214 |
{
|
|
215 |
.name = "pentium2",
|
|
216 |
.family = 6,
|
|
217 |
.model = 5,
|
|
218 |
.stepping = 2,
|
|
219 |
.features = 0x0183F9FF,
|
|
220 |
.xlevel = 0,
|
|
221 |
},
|
|
222 |
{
|
|
223 |
.name = "pentium3",
|
|
224 |
.family = 6,
|
|
225 |
.model = 7,
|
|
226 |
.stepping = 3,
|
|
227 |
.features = 0x0383F9FF,
|
|
228 |
.xlevel = 0,
|
|
229 |
},
|
|
230 |
};
|
|
231 |
|
|
232 |
int x86_find_cpu_by_name(const unsigned char *cpu_model)
|
|
233 |
{
|
|
234 |
int ret;
|
|
235 |
unsigned int i;
|
|
236 |
|
|
237 |
char *s = strdup(cpu_model);
|
|
238 |
char *featurestr, *name = strtok(s, ",");
|
|
239 |
uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0;
|
|
240 |
uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0;
|
|
241 |
int family = -1, model = -1, stepping = -1;
|
|
242 |
|
|
243 |
ret = -1;
|
|
244 |
x86_cpu_def = NULL;
|
|
245 |
for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++) {
|
|
246 |
if (strcmp(name, x86_defs[i].name) == 0) {
|
|
247 |
x86_cpu_def = &x86_defs[i];
|
|
248 |
ret = 0;
|
|
249 |
break;
|
|
250 |
}
|
143 |
251 |
}
|
144 |
|
cpu_reset(env);
|
145 |
|
#ifdef USE_KQEMU
|
146 |
|
kqemu_init(env);
|
147 |
|
#endif
|
148 |
|
return env;
|
|
252 |
if (!x86_cpu_def)
|
|
253 |
goto error;
|
|
254 |
|
|
255 |
featurestr = strtok(NULL, ",");
|
|
256 |
|
|
257 |
while (featurestr) {
|
|
258 |
char *val;
|
|
259 |
if (featurestr[0] == '+') {
|
|
260 |
add_flagname_to_bitmaps(featurestr + 1, &plus_features, &plus_ext_features, &plus_ext2_features, &plus_ext3_features);
|
|
261 |
} else if (featurestr[0] == '-') {
|
|
262 |
add_flagname_to_bitmaps(featurestr + 1, &minus_features, &minus_ext_features, &minus_ext2_features, &minus_ext3_features);
|
|
263 |
} else if ((val = strchr(featurestr, '='))) {
|
|
264 |
*val = 0; val++;
|
|
265 |
if (!strcmp(featurestr, "family")) {
|
|
266 |
char *err;
|
|
267 |
family = strtol(val, &err, 10);
|
|
268 |
if (!*val || *err || family < 0) {
|
|
269 |
fprintf(stderr, "bad numerical value %s\n", val);
|
|
270 |
x86_cpu_def = 0;
|
|
271 |
goto error;
|
|
272 |
}
|
|
273 |
x86_cpu_def->family = family;
|
|
274 |
} else if (!strcmp(featurestr, "model")) {
|
|
275 |
char *err;
|
|
276 |
model = strtol(val, &err, 10);
|
|
277 |
if (!*val || *err || model < 0 || model > 0xf) {
|
|
278 |
fprintf(stderr, "bad numerical value %s\n", val);
|
|
279 |
x86_cpu_def = 0;
|
|
280 |
goto error;
|
|
281 |
}
|
|
282 |
x86_cpu_def->model = model;
|
|
283 |
} else if (!strcmp(featurestr, "stepping")) {
|
|
284 |
char *err;
|
|
285 |
stepping = strtol(val, &err, 10);
|
|
286 |
if (!*val || *err || stepping < 0 || stepping > 0xf) {
|
|
287 |
fprintf(stderr, "bad numerical value %s\n", val);
|
|
288 |
x86_cpu_def = 0;
|
|
289 |
goto error;
|
|
290 |
}
|
|
291 |
x86_cpu_def->stepping = stepping;
|
|
292 |
} else {
|
|
293 |
fprintf(stderr, "unregnized feature %s\n", featurestr);
|
|
294 |
x86_cpu_def = 0;
|
|
295 |
goto error;
|
|
296 |
}
|
|
297 |
} else {
|
|
298 |
fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
|
|
299 |
x86_cpu_def = 0;
|
|
300 |
goto error;
|
|
301 |
}
|
|
302 |
featurestr = strtok(NULL, ",");
|
|
303 |
}
|
|
304 |
x86_cpu_def->features |= plus_features;
|
|
305 |
x86_cpu_def->ext_features |= plus_ext_features;
|
|
306 |
x86_cpu_def->ext2_features |= plus_ext2_features;
|
|
307 |
x86_cpu_def->ext3_features |= plus_ext3_features;
|
|
308 |
x86_cpu_def->features &= ~minus_features;
|
|
309 |
x86_cpu_def->ext_features &= ~minus_ext_features;
|
|
310 |
x86_cpu_def->ext2_features &= ~minus_ext2_features;
|
|
311 |
x86_cpu_def->ext3_features &= ~minus_ext3_features;
|
|
312 |
|
|
313 |
error:
|
|
314 |
free(s);
|
|
315 |
return ret;
|
|
316 |
}
|
|
317 |
|
|
318 |
void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
|
|
319 |
{
|
|
320 |
unsigned int i;
|
|
321 |
|
|
322 |
for (i = 0; i < sizeof(x86_defs) / sizeof(x86_def_t); i++)
|
|
323 |
(*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
|
|
324 |
}
|
|
325 |
|
|
326 |
int cpu_x86_register (CPUX86State *env, const x86_def_t *def)
|
|
327 |
{
|
|
328 |
if (def->vendor1) {
|
|
329 |
env->cpuid_vendor1 = def->vendor1;
|
|
330 |
env->cpuid_vendor2 = def->vendor2;
|
|
331 |
env->cpuid_vendor3 = def->vendor3;
|
|
332 |
} else {
|
|
333 |
env->cpuid_vendor1 = 0x756e6547; /* "Genu" */
|
|
334 |
env->cpuid_vendor2 = 0x49656e69; /* "ineI" */
|
|
335 |
env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */
|
|
336 |
}
|
|
337 |
env->cpuid_level = 2;
|
|
338 |
env->cpuid_version = (def->family << 8) | (def->model << 4) | def->stepping;
|
|
339 |
env->cpuid_features = def->features;
|
|
340 |
env->pat = 0x0007040600070406ULL;
|
|
341 |
env->cpuid_ext_features = def->ext_features;
|
|
342 |
env->cpuid_ext2_features = def->ext2_features;
|
|
343 |
env->cpuid_xlevel = def->xlevel;
|
|
344 |
env->cpuid_ext3_features = def->ext3_features;
|
|
345 |
{
|
|
346 |
const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION;
|
|
347 |
int c, len, i;
|
|
348 |
len = strlen(model_id);
|
|
349 |
for(i = 0; i < 48; i++) {
|
|
350 |
if (i >= len)
|
|
351 |
c = '\0';
|
|
352 |
else
|
|
353 |
c = model_id[i];
|
|
354 |
env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
|
|
355 |
}
|
|
356 |
}
|
|
357 |
return 0;
|
149 |
358 |
}
|
150 |
359 |
|
151 |
360 |
/* NOTE: must be called outside the CPU execute loop */
|
... | ... | |
185 |
394 |
cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0);
|
186 |
395 |
|
187 |
396 |
env->eip = 0xfff0;
|
188 |
|
env->regs[R_EDX] = 0x600; /* indicate P6 processor */
|
|
397 |
env->regs[R_EDX] = env->cpuid_version;
|
189 |
398 |
|
190 |
399 |
env->eflags = 0x2;
|
191 |
400 |
|