29 |
29 |
#include "kvm.h"
|
30 |
30 |
|
31 |
31 |
//#define DEBUG_MMU
|
|
32 |
#include "qemu-option.h"
|
|
33 |
#include "qemu-config.h"
|
32 |
34 |
|
33 |
35 |
/* feature flags taken from "Intel Processor Identification and the CPUID
|
34 |
|
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
|
35 |
|
* about feature names, the Linux name is used. */
|
|
36 |
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
|
|
37 |
* between feature naming conventions, aliases may be added.
|
|
38 |
*/
|
36 |
39 |
static const char *feature_name[] = {
|
37 |
|
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
38 |
|
"cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
|
39 |
|
"pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */, NULL, "ds" /* Intel dts */, "acpi", "mmx",
|
40 |
|
"fxsr", "sse", "sse2", "ss", "ht" /* Intel htt */, "tm", "ia64", "pbe",
|
|
40 |
"fpu", "vme", "de", "pse",
|
|
41 |
"tsc", "msr", "pae", "mce",
|
|
42 |
"cx8", "apic", NULL, "sep",
|
|
43 |
"mtrr", "pge", "mca", "cmov",
|
|
44 |
"pat", "pse36", "pn" /* Intel psn */, "clflush" /* Intel clfsh */,
|
|
45 |
NULL, "ds" /* Intel dts */, "acpi", "mmx",
|
|
46 |
"fxsr", "sse", "sse2", "ss",
|
|
47 |
"ht" /* Intel htt */, "tm", "ia64", "pbe",
|
41 |
48 |
};
|
42 |
49 |
static const char *ext_feature_name[] = {
|
43 |
|
"pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est",
|
44 |
|
"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
|
45 |
|
NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
|
46 |
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, "hypervisor",
|
|
50 |
"pni|sse3" /* Intel,AMD sse3 */, NULL, NULL, "monitor",
|
|
51 |
"ds_cpl", "vmx", NULL /* Linux smx */, "est",
|
|
52 |
"tm2", "ssse3", "cid", NULL,
|
|
53 |
NULL, "cx16", "xtpr", NULL,
|
|
54 |
NULL, NULL, "dca", "sse4.1|sse4_1",
|
|
55 |
"sse4.2|sse4_2", "x2apic", NULL, "popcnt",
|
|
56 |
NULL, NULL, NULL, NULL,
|
|
57 |
NULL, NULL, NULL, "hypervisor",
|
47 |
58 |
};
|
48 |
59 |
static const char *ext2_feature_name[] = {
|
49 |
|
"fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
|
50 |
|
"cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall", "mtrr", "pge", "mca", "cmov",
|
51 |
|
"pat", "pse36", NULL, NULL /* Linux mp */, "nx" /* Intel xd */, NULL, "mmxext", "mmx",
|
52 |
|
"fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp", NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
|
|
60 |
"fpu", "vme", "de", "pse",
|
|
61 |
"tsc", "msr", "pae", "mce",
|
|
62 |
"cx8" /* AMD CMPXCHG8B */, "apic", NULL, "syscall",
|
|
63 |
"mtrr", "pge", "mca", "cmov",
|
|
64 |
"pat", "pse36", NULL, NULL /* Linux mp */,
|
|
65 |
"nx" /* Intel xd */, NULL, "mmxext", "mmx",
|
|
66 |
"fxsr", "fxsr_opt" /* AMD ffxsr */, "pdpe1gb" /* AMD Page1GB */, "rdtscp",
|
|
67 |
NULL, "lm" /* Intel 64 */, "3dnowext", "3dnow",
|
53 |
68 |
};
|
54 |
69 |
static const char *ext3_feature_name[] = {
|
55 |
|
"lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */, "cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
|
56 |
|
"3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL, "skinit", "wdt", NULL, NULL,
|
57 |
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
58 |
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
|
70 |
"lahf_lm" /* AMD LahfSahf */, "cmp_legacy", "svm", "extapic" /* AMD ExtApicSpace */,
|
|
71 |
"cr8legacy" /* AMD AltMovCr8 */, "abm", "sse4a", "misalignsse",
|
|
72 |
"3dnowprefetch", "osvw", NULL /* Linux ibs */, NULL,
|
|
73 |
"skinit", "wdt", NULL, NULL,
|
|
74 |
NULL, NULL, NULL, NULL,
|
|
75 |
NULL, NULL, NULL, NULL,
|
|
76 |
NULL, NULL, NULL, NULL,
|
|
77 |
NULL, NULL, NULL, NULL,
|
59 |
78 |
};
|
60 |
79 |
|
61 |
80 |
static const char *kvm_feature_name[] = {
|
... | ... | |
65 |
84 |
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
66 |
85 |
};
|
67 |
86 |
|
|
87 |
/* collects per-function cpuid data
|
|
88 |
*/
|
|
89 |
typedef struct model_features_t {
|
|
90 |
uint32_t *guest_feat;
|
|
91 |
uint32_t *host_feat;
|
|
92 |
uint32_t check_feat;
|
|
93 |
const char **flag_names;
|
|
94 |
uint32_t cpuid;
|
|
95 |
} model_features_t;
|
|
96 |
|
|
97 |
int check_cpuid = 0;
|
|
98 |
int enforce_cpuid = 0;
|
|
99 |
|
|
100 |
static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
|
|
101 |
uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
|
|
102 |
|
|
103 |
#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c)))
|
|
104 |
|
|
105 |
/* general substring compare of *[s1..e1) and *[s2..e2). sx is start of
|
|
106 |
* a substring. ex if !NULL points to the first char after a substring,
|
|
107 |
* otherwise the string is assumed to sized by a terminating nul.
|
|
108 |
* Return lexical ordering of *s1:*s2.
|
|
109 |
*/
|
|
110 |
static int sstrcmp(const char *s1, const char *e1, const char *s2,
|
|
111 |
const char *e2)
|
|
112 |
{
|
|
113 |
for (;;) {
|
|
114 |
if (!*s1 || !*s2 || *s1 != *s2)
|
|
115 |
return (*s1 - *s2);
|
|
116 |
++s1, ++s2;
|
|
117 |
if (s1 == e1 && s2 == e2)
|
|
118 |
return (0);
|
|
119 |
else if (s1 == e1)
|
|
120 |
return (*s2);
|
|
121 |
else if (s2 == e2)
|
|
122 |
return (*s1);
|
|
123 |
}
|
|
124 |
}
|
|
125 |
|
|
126 |
/* compare *[s..e) to *altstr. *altstr may be a simple string or multiple
|
|
127 |
* '|' delimited (possibly empty) strings in which case search for a match
|
|
128 |
* within the alternatives proceeds left to right. Return 0 for success,
|
|
129 |
* non-zero otherwise.
|
|
130 |
*/
|
|
131 |
static int altcmp(const char *s, const char *e, const char *altstr)
|
|
132 |
{
|
|
133 |
const char *p, *q;
|
|
134 |
|
|
135 |
for (q = p = altstr; ; ) {
|
|
136 |
while (*p && *p != '|')
|
|
137 |
++p;
|
|
138 |
if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p)))
|
|
139 |
return (0);
|
|
140 |
if (!*p)
|
|
141 |
return (1);
|
|
142 |
else
|
|
143 |
q = ++p;
|
|
144 |
}
|
|
145 |
}
|
|
146 |
|
|
147 |
/* search featureset for flag *[s..e), if found set corresponding bit in
|
|
148 |
* *pval and return success, otherwise return zero
|
|
149 |
*/
|
|
150 |
static int lookup_feature(uint32_t *pval, const char *s, const char *e,
|
|
151 |
const char **featureset)
|
|
152 |
{
|
|
153 |
uint32_t mask;
|
|
154 |
const char **ppc;
|
|
155 |
|
|
156 |
for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc)
|
|
157 |
if (*ppc && !altcmp(s, e, *ppc)) {
|
|
158 |
*pval |= mask;
|
|
159 |
break;
|
|
160 |
}
|
|
161 |
return (mask ? 1 : 0);
|
|
162 |
}
|
|
163 |
|
68 |
164 |
static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
|
69 |
165 |
uint32_t *ext_features,
|
70 |
166 |
uint32_t *ext2_features,
|
71 |
167 |
uint32_t *ext3_features,
|
72 |
168 |
uint32_t *kvm_features)
|
73 |
169 |
{
|
74 |
|
int i;
|
75 |
|
int found = 0;
|
76 |
|
|
77 |
|
for ( i = 0 ; i < 32 ; i++ )
|
78 |
|
if (feature_name[i] && !strcmp (flagname, feature_name[i])) {
|
79 |
|
*features |= 1 << i;
|
80 |
|
found = 1;
|
81 |
|
}
|
82 |
|
for ( i = 0 ; i < 32 ; i++ )
|
83 |
|
if (ext_feature_name[i] && !strcmp (flagname, ext_feature_name[i])) {
|
84 |
|
*ext_features |= 1 << i;
|
85 |
|
found = 1;
|
86 |
|
}
|
87 |
|
for ( i = 0 ; i < 32 ; i++ )
|
88 |
|
if (ext2_feature_name[i] && !strcmp (flagname, ext2_feature_name[i])) {
|
89 |
|
*ext2_features |= 1 << i;
|
90 |
|
found = 1;
|
91 |
|
}
|
92 |
|
for ( i = 0 ; i < 32 ; i++ )
|
93 |
|
if (ext3_feature_name[i] && !strcmp (flagname, ext3_feature_name[i])) {
|
94 |
|
*ext3_features |= 1 << i;
|
95 |
|
found = 1;
|
96 |
|
}
|
97 |
|
for ( i = 0 ; i < 32 ; i++ )
|
98 |
|
if (kvm_feature_name[i] && !strcmp (flagname, kvm_feature_name[i])) {
|
99 |
|
*kvm_features |= 1 << i;
|
100 |
|
found = 1;
|
101 |
|
}
|
102 |
|
|
103 |
|
if (!found) {
|
104 |
|
fprintf(stderr, "CPU feature %s not found\n", flagname);
|
105 |
|
}
|
|
170 |
if (!lookup_feature(features, flagname, NULL, feature_name) &&
|
|
171 |
!lookup_feature(ext_features, flagname, NULL, ext_feature_name) &&
|
|
172 |
!lookup_feature(ext2_features, flagname, NULL, ext2_feature_name) &&
|
|
173 |
!lookup_feature(ext3_features, flagname, NULL, ext3_feature_name) &&
|
|
174 |
!lookup_feature(kvm_features, flagname, NULL, kvm_feature_name))
|
|
175 |
fprintf(stderr, "CPU feature %s not found\n", flagname);
|
106 |
176 |
}
|
107 |
177 |
|
108 |
178 |
typedef struct x86_def_t {
|
|
179 |
struct x86_def_t *next;
|
109 |
180 |
const char *name;
|
110 |
181 |
uint32_t level;
|
111 |
182 |
uint32_t vendor1, vendor2, vendor3;
|
... | ... | |
116 |
187 |
uint32_t xlevel;
|
117 |
188 |
char model_id[48];
|
118 |
189 |
int vendor_override;
|
|
190 |
uint32_t flags;
|
119 |
191 |
} x86_def_t;
|
120 |
192 |
|
121 |
193 |
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
|
... | ... | |
129 |
201 |
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
|
130 |
202 |
CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
|
131 |
203 |
CPUID_PAE | CPUID_SEP | CPUID_APIC)
|
132 |
|
static x86_def_t x86_defs[] = {
|
|
204 |
|
|
205 |
/* maintains list of cpu model definitions
|
|
206 |
*/
|
|
207 |
static x86_def_t *x86_defs = {NULL};
|
|
208 |
|
|
209 |
/* built-in cpu model definitions (deprecated)
|
|
210 |
*/
|
|
211 |
static x86_def_t builtin_x86_defs[] = {
|
133 |
212 |
#ifdef TARGET_X86_64
|
134 |
213 |
{
|
135 |
214 |
.name = "qemu64",
|
... | ... | |
334 |
413 |
},
|
335 |
414 |
};
|
336 |
415 |
|
337 |
|
static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
|
338 |
|
uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
|
339 |
|
|
340 |
416 |
static int cpu_x86_fill_model_id(char *str)
|
341 |
417 |
{
|
342 |
418 |
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
... | ... | |
382 |
458 |
return 0;
|
383 |
459 |
}
|
384 |
460 |
|
|
461 |
static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
|
|
462 |
{
|
|
463 |
int i;
|
|
464 |
|
|
465 |
for (i = 0; i < 32; ++i)
|
|
466 |
if (1 << i & mask) {
|
|
467 |
fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
|
|
468 |
" flag '%s' [0x%08x]\n",
|
|
469 |
f->cpuid >> 16, f->cpuid & 0xffff,
|
|
470 |
f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
|
|
471 |
break;
|
|
472 |
}
|
|
473 |
return 0;
|
|
474 |
}
|
|
475 |
|
|
476 |
/* best effort attempt to inform user requested cpu flags aren't making
|
|
477 |
* their way to the guest. Note: ft[].check_feat ideally should be
|
|
478 |
* specified via a guest_def field to suppress report of extraneous flags.
|
|
479 |
*/
|
|
480 |
static int check_features_against_host(x86_def_t *guest_def)
|
|
481 |
{
|
|
482 |
x86_def_t host_def;
|
|
483 |
uint32_t mask;
|
|
484 |
int rv, i;
|
|
485 |
struct model_features_t ft[] = {
|
|
486 |
{&guest_def->features, &host_def.features,
|
|
487 |
~0, feature_name, 0x00000000},
|
|
488 |
{&guest_def->ext_features, &host_def.ext_features,
|
|
489 |
~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
|
|
490 |
{&guest_def->ext2_features, &host_def.ext2_features,
|
|
491 |
~PPRO_FEATURES, ext2_feature_name, 0x80000000},
|
|
492 |
{&guest_def->ext3_features, &host_def.ext3_features,
|
|
493 |
~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
|
|
494 |
|
|
495 |
cpu_x86_fill_host(&host_def);
|
|
496 |
for (rv = 0, i = 0; i < sizeof (ft) / sizeof (ft[0]); ++i)
|
|
497 |
for (mask = 1; mask; mask <<= 1)
|
|
498 |
if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
|
|
499 |
!(*ft[i].host_feat & mask)) {
|
|
500 |
unavailable_host_feature(&ft[i], mask);
|
|
501 |
rv = 1;
|
|
502 |
}
|
|
503 |
return rv;
|
|
504 |
}
|
|
505 |
|
385 |
506 |
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
|
386 |
507 |
{
|
387 |
508 |
unsigned int i;
|
... | ... | |
393 |
514 |
uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0, minus_kvm_features = 0;
|
394 |
515 |
uint32_t numvalue;
|
395 |
516 |
|
396 |
|
def = NULL;
|
397 |
|
for (i = 0; i < ARRAY_SIZE(x86_defs); i++) {
|
398 |
|
if (strcmp(name, x86_defs[i].name) == 0) {
|
399 |
|
def = &x86_defs[i];
|
|
517 |
for (def = x86_defs; def; def = def->next)
|
|
518 |
if (!strcmp(name, def->name))
|
400 |
519 |
break;
|
401 |
|
}
|
402 |
|
}
|
403 |
520 |
if (kvm_enabled() && strcmp(name, "host") == 0) {
|
404 |
521 |
cpu_x86_fill_host(x86_cpu_def);
|
405 |
522 |
} else if (!def) {
|
... | ... | |
488 |
605 |
fprintf(stderr, "unrecognized feature %s\n", featurestr);
|
489 |
606 |
goto error;
|
490 |
607 |
}
|
|
608 |
} else if (!strcmp(featurestr, "check")) {
|
|
609 |
check_cpuid = 1;
|
|
610 |
} else if (!strcmp(featurestr, "enforce")) {
|
|
611 |
check_cpuid = enforce_cpuid = 1;
|
491 |
612 |
} else {
|
492 |
613 |
fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
|
493 |
614 |
goto error;
|
... | ... | |
504 |
625 |
x86_cpu_def->ext2_features &= ~minus_ext2_features;
|
505 |
626 |
x86_cpu_def->ext3_features &= ~minus_ext3_features;
|
506 |
627 |
x86_cpu_def->kvm_features &= ~minus_kvm_features;
|
|
628 |
if (check_cpuid) {
|
|
629 |
if (check_features_against_host(x86_cpu_def) && enforce_cpuid)
|
|
630 |
goto error;
|
|
631 |
}
|
507 |
632 |
free(s);
|
508 |
633 |
return 0;
|
509 |
634 |
|
... | ... | |
512 |
637 |
return -1;
|
513 |
638 |
}
|
514 |
639 |
|
515 |
|
void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
|
|
640 |
/* generate a composite string into buf of all cpuid names in featureset
|
|
641 |
* selected by fbits. indicate truncation at bufsize in the event of overflow.
|
|
642 |
* if flags, suppress names undefined in featureset.
|
|
643 |
*/
|
|
644 |
static void listflags(char *buf, int bufsize, uint32_t fbits,
|
|
645 |
const char **featureset, uint32_t flags)
|
516 |
646 |
{
|
517 |
|
unsigned int i;
|
|
647 |
const char **p = &featureset[31];
|
|
648 |
char *q, *b, bit;
|
|
649 |
int nc;
|
|
650 |
|
|
651 |
b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
|
|
652 |
*buf = '\0';
|
|
653 |
for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
|
|
654 |
if (fbits & 1 << bit && (*p || !flags)) {
|
|
655 |
if (*p)
|
|
656 |
nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
|
|
657 |
else
|
|
658 |
nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
|
|
659 |
if (bufsize <= nc) {
|
|
660 |
if (b)
|
|
661 |
sprintf(b, "...");
|
|
662 |
return;
|
|
663 |
}
|
|
664 |
q += nc;
|
|
665 |
bufsize -= nc;
|
|
666 |
}
|
|
667 |
}
|
518 |
668 |
|
519 |
|
for (i = 0; i < ARRAY_SIZE(x86_defs); i++)
|
520 |
|
(*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
|
|
669 |
/* generate CPU information:
|
|
670 |
* -? list model names
|
|
671 |
* -?model list model names/IDs
|
|
672 |
* -?dump output all model (x86_def_t) data
|
|
673 |
* -?cpuid list all recognized cpuid flag names
|
|
674 |
*/
|
|
675 |
void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
|
|
676 |
const char *optarg)
|
|
677 |
{
|
|
678 |
unsigned char model = !strcmp("?model", optarg);
|
|
679 |
unsigned char dump = !strcmp("?dump", optarg);
|
|
680 |
unsigned char cpuid = !strcmp("?cpuid", optarg);
|
|
681 |
x86_def_t *def;
|
|
682 |
char buf[256];
|
|
683 |
|
|
684 |
if (cpuid) {
|
|
685 |
(*cpu_fprintf)(f, "Recognized CPUID flags:\n");
|
|
686 |
listflags(buf, sizeof (buf), (uint32_t)~0, feature_name, 1);
|
|
687 |
(*cpu_fprintf)(f, " f_edx: %s\n", buf);
|
|
688 |
listflags(buf, sizeof (buf), (uint32_t)~0, ext_feature_name, 1);
|
|
689 |
(*cpu_fprintf)(f, " f_ecx: %s\n", buf);
|
|
690 |
listflags(buf, sizeof (buf), (uint32_t)~0, ext2_feature_name, 1);
|
|
691 |
(*cpu_fprintf)(f, " extf_edx: %s\n", buf);
|
|
692 |
listflags(buf, sizeof (buf), (uint32_t)~0, ext3_feature_name, 1);
|
|
693 |
(*cpu_fprintf)(f, " extf_ecx: %s\n", buf);
|
|
694 |
return;
|
|
695 |
}
|
|
696 |
for (def = x86_defs; def; def = def->next) {
|
|
697 |
snprintf(buf, sizeof (buf), def->flags ? "[%s]": "%s", def->name);
|
|
698 |
if (model || dump) {
|
|
699 |
(*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
|
|
700 |
} else {
|
|
701 |
(*cpu_fprintf)(f, "x86 %16s\n", buf);
|
|
702 |
}
|
|
703 |
if (dump) {
|
|
704 |
memcpy(buf, &def->vendor1, sizeof (def->vendor1));
|
|
705 |
memcpy(buf + 4, &def->vendor2, sizeof (def->vendor2));
|
|
706 |
memcpy(buf + 8, &def->vendor3, sizeof (def->vendor3));
|
|
707 |
buf[12] = '\0';
|
|
708 |
(*cpu_fprintf)(f,
|
|
709 |
" family %d model %d stepping %d level %d xlevel 0x%x"
|
|
710 |
" vendor \"%s\"\n",
|
|
711 |
def->family, def->model, def->stepping, def->level,
|
|
712 |
def->xlevel, buf);
|
|
713 |
listflags(buf, sizeof (buf), def->features, feature_name, 0);
|
|
714 |
(*cpu_fprintf)(f, " feature_edx %08x (%s)\n", def->features,
|
|
715 |
buf);
|
|
716 |
listflags(buf, sizeof (buf), def->ext_features, ext_feature_name,
|
|
717 |
0);
|
|
718 |
(*cpu_fprintf)(f, " feature_ecx %08x (%s)\n", def->ext_features,
|
|
719 |
buf);
|
|
720 |
listflags(buf, sizeof (buf), def->ext2_features, ext2_feature_name,
|
|
721 |
0);
|
|
722 |
(*cpu_fprintf)(f, " extfeature_edx %08x (%s)\n",
|
|
723 |
def->ext2_features, buf);
|
|
724 |
listflags(buf, sizeof (buf), def->ext3_features, ext3_feature_name,
|
|
725 |
0);
|
|
726 |
(*cpu_fprintf)(f, " extfeature_ecx %08x (%s)\n",
|
|
727 |
def->ext3_features, buf);
|
|
728 |
(*cpu_fprintf)(f, "\n");
|
|
729 |
}
|
|
730 |
}
|
521 |
731 |
}
|
522 |
732 |
|
523 |
733 |
static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
|
... | ... | |
566 |
776 |
return 0;
|
567 |
777 |
}
|
568 |
778 |
|
|
779 |
#if !defined(CONFIG_LINUX_USER)
|
|
780 |
/* copy vendor id string to 32 bit register, nul pad as needed
|
|
781 |
*/
|
|
782 |
static void cpyid(const char *s, uint32_t *id)
|
|
783 |
{
|
|
784 |
char *d = (char *)id;
|
|
785 |
char i;
|
|
786 |
|
|
787 |
for (i = sizeof (*id); i--; )
|
|
788 |
*d++ = *s ? *s++ : '\0';
|
|
789 |
}
|
|
790 |
|
|
791 |
/* interpret radix and convert from string to arbitrary scalar,
|
|
792 |
* otherwise flag failure
|
|
793 |
*/
|
|
794 |
#define setscalar(pval, str, perr) \
|
|
795 |
{ \
|
|
796 |
char *pend; \
|
|
797 |
unsigned long ul; \
|
|
798 |
\
|
|
799 |
ul = strtoul(str, &pend, 0); \
|
|
800 |
*str && !*pend ? (*pval = ul) : (*perr = 1); \
|
|
801 |
}
|
|
802 |
|
|
803 |
/* map cpuid options to feature bits, otherwise return failure
|
|
804 |
* (option tags in *str are delimited by whitespace)
|
|
805 |
*/
|
|
806 |
static void setfeatures(uint32_t *pval, const char *str,
|
|
807 |
const char **featureset, int *perr)
|
|
808 |
{
|
|
809 |
const char *p, *q;
|
|
810 |
|
|
811 |
for (q = p = str; *p || *q; q = p) {
|
|
812 |
while (iswhite(*p))
|
|
813 |
q = ++p;
|
|
814 |
while (*p && !iswhite(*p))
|
|
815 |
++p;
|
|
816 |
if (!*q && !*p)
|
|
817 |
return;
|
|
818 |
if (!lookup_feature(pval, q, p, featureset)) {
|
|
819 |
fprintf(stderr, "error: feature \"%.*s\" not available in set\n",
|
|
820 |
(int)(p - q), q);
|
|
821 |
*perr = 1;
|
|
822 |
return;
|
|
823 |
}
|
|
824 |
}
|
|
825 |
}
|
|
826 |
|
|
827 |
/* map config file options to x86_def_t form
|
|
828 |
*/
|
|
829 |
static int cpudef_setfield(const char *name, const char *str, void *opaque)
|
|
830 |
{
|
|
831 |
x86_def_t *def = opaque;
|
|
832 |
int err = 0;
|
|
833 |
|
|
834 |
if (!strcmp(name, "name")) {
|
|
835 |
def->name = strdup(str);
|
|
836 |
} else if (!strcmp(name, "model_id")) {
|
|
837 |
strncpy(def->model_id, str, sizeof (def->model_id));
|
|
838 |
} else if (!strcmp(name, "level")) {
|
|
839 |
setscalar(&def->level, str, &err)
|
|
840 |
} else if (!strcmp(name, "vendor")) {
|
|
841 |
cpyid(&str[0], &def->vendor1);
|
|
842 |
cpyid(&str[4], &def->vendor2);
|
|
843 |
cpyid(&str[8], &def->vendor3);
|
|
844 |
} else if (!strcmp(name, "family")) {
|
|
845 |
setscalar(&def->family, str, &err)
|
|
846 |
} else if (!strcmp(name, "model")) {
|
|
847 |
setscalar(&def->model, str, &err)
|
|
848 |
} else if (!strcmp(name, "stepping")) {
|
|
849 |
setscalar(&def->stepping, str, &err)
|
|
850 |
} else if (!strcmp(name, "feature_edx")) {
|
|
851 |
setfeatures(&def->features, str, feature_name, &err);
|
|
852 |
} else if (!strcmp(name, "feature_ecx")) {
|
|
853 |
setfeatures(&def->ext_features, str, ext_feature_name, &err);
|
|
854 |
} else if (!strcmp(name, "extfeature_edx")) {
|
|
855 |
setfeatures(&def->ext2_features, str, ext2_feature_name, &err);
|
|
856 |
} else if (!strcmp(name, "extfeature_ecx")) {
|
|
857 |
setfeatures(&def->ext3_features, str, ext3_feature_name, &err);
|
|
858 |
} else if (!strcmp(name, "xlevel")) {
|
|
859 |
setscalar(&def->xlevel, str, &err)
|
|
860 |
} else {
|
|
861 |
fprintf(stderr, "error: unknown option [%s = %s]\n", name, str);
|
|
862 |
return (1);
|
|
863 |
}
|
|
864 |
if (err) {
|
|
865 |
fprintf(stderr, "error: bad option value [%s = %s]\n", name, str);
|
|
866 |
return (1);
|
|
867 |
}
|
|
868 |
return (0);
|
|
869 |
}
|
|
870 |
|
|
871 |
/* register config file entry as x86_def_t
|
|
872 |
*/
|
|
873 |
static int cpudef_register(QemuOpts *opts, void *opaque)
|
|
874 |
{
|
|
875 |
x86_def_t *def = qemu_mallocz(sizeof (x86_def_t));
|
|
876 |
|
|
877 |
qemu_opt_foreach(opts, cpudef_setfield, def, 1);
|
|
878 |
def->next = x86_defs;
|
|
879 |
x86_defs = def;
|
|
880 |
return (0);
|
|
881 |
}
|
|
882 |
#endif /* !CONFIG_LINUX_USER */
|
|
883 |
|
|
884 |
/* register "cpudef" models defined in configuration file. Here we first
|
|
885 |
* preload any built-in definitions
|
|
886 |
*/
|
|
887 |
void x86_cpudef_setup(void)
|
|
888 |
{
|
|
889 |
int i;
|
|
890 |
|
|
891 |
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
|
|
892 |
builtin_x86_defs[i].next = x86_defs;
|
|
893 |
builtin_x86_defs[i].flags = 1;
|
|
894 |
x86_defs = &builtin_x86_defs[i];
|
|
895 |
}
|
|
896 |
#if !defined(CONFIG_LINUX_USER)
|
|
897 |
qemu_opts_foreach(&qemu_cpudef_opts, cpudef_register, NULL, 0);
|
|
898 |
#endif
|
|
899 |
}
|
|
900 |
|
569 |
901 |
/* NOTE: must be called outside the CPU execute loop */
|
570 |
902 |
void cpu_reset(CPUX86State *env)
|
571 |
903 |
{
|