Revision a049de61 target-i386/helper2.c
b/target-i386/helper2.c | ||
---|---|---|
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 |
|
Also available in: Unified diff