@@ -722,8 +722,8 @@ typedef struct CPUX86State {
CPUX86State *cpu_x86_init(const char *cpu_model);
int cpu_x86_exec(CPUX86State *s);
void cpu_x86_close(CPUX86State *s);
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt,
- ...));
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ const char *optarg);
int cpu_get_pic_interrupt(CPUX86State *s);
/* MSDOS compatibility mode FPU exception support */
void cpu_set_ferr(CPUX86State *s);
@@ -875,7 +875,7 @@ uint64_t cpu_get_tsc(CPUX86State *env);
#define cpu_exec cpu_x86_exec
#define cpu_gen_code cpu_x86_gen_code
#define cpu_signal_handler cpu_x86_signal_handler
-#define cpu_list x86_cpu_list
+#define cpu_list_id x86_cpu_list
#define CPU_SAVE_VERSION 11
@@ -42,7 +42,7 @@ static const char *feature_name[] = {
static const char *ext_feature_name[] = {
"pni" /* Intel,AMD sse3 */, NULL, NULL, "monitor", "ds_cpl", "vmx", NULL /* Linux smx */, "est",
"tm2", "ssse3", "cid", NULL, NULL, "cx16", "xtpr", NULL,
- NULL, NULL, "dca", NULL, NULL, NULL, NULL, "popcnt",
+ NULL, NULL, "dca", "sse4.1", "sse4.2", "x2apic", NULL, "popcnt",
NULL, NULL, NULL, NULL, NULL, NULL, NULL, "hypervisor",
};
static const char *ext2_feature_name[] = {
@@ -58,6 +58,18 @@ static const char *ext3_feature_name[] = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
+/* collects per-function cpuid data
+ */
+typedef struct model_features_t {
+ uint32_t *guest_feat;
+ uint32_t *host_feat;
+ uint32_t check_feat;
+ const char **flag_names;
+ uint32_t cpuid;
+ } model_features_t;
+
+int check_cpuid = 0;
+
static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features,
uint32_t *ext_features,
uint32_t *ext2_features,
@@ -111,10 +123,25 @@ typedef struct x86_def_t {
CPUID_MTRR | CPUID_PGE | CPUID_MCA | CPUID_CMOV | CPUID_PAT | \
CPUID_PSE36 | CPUID_FXSR)
#define PENTIUM3_FEATURES (PENTIUM2_FEATURES | CPUID_SSE)
-#define PPRO_FEATURES (CPUID_FP87 | CPUID_DE | CPUID_PSE | CPUID_TSC | \
- CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_PGE | CPUID_CMOV | \
- CPUID_PAT | CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | \
- CPUID_PAE | CPUID_SEP | CPUID_APIC)
+
+#define PPRO_FEATURES (\
+ 0|CPUID_SSE2|CPUID_SSE|CPUID_FXSR| /* 7 */ \
+ CPUID_MMX|0 << 22|0 << 21|0 << 20| /* 8 */ \
+ 0 << 19|0 << 18|0 << 17|CPUID_PAT| /* 1 */ \
+ CPUID_CMOV|0 << 14|CPUID_PGE|0 << 12| /* a */ \
+ CPUID_SEP|0 << 10|CPUID_APIC|CPUID_CX8| /* b */ \
+ CPUID_MCE|CPUID_PAE|CPUID_MSR|CPUID_TSC| /* f */ \
+ CPUID_PSE|CPUID_DE|0 << 1|CPUID_FP87) /* d */
+
+#define CPUID_EXT2_MASK (\
+ 0 << 27|0 << 26|0 << 25|CPUID_FXSR| /* 1 */ \
+ CPUID_MMX|0 << 22|0 << 21|0 << 20| /* 8 */ \
+ 0 << 19|0 << 18|CPUID_PSE36|CPUID_PAT| /* 3 */ \
+ CPUID_CMOV|CPUID_MCA|CPUID_PGE|CPUID_MTRR| /* f */ \
+ 0 << 11|0 << 10|CPUID_APIC|CPUID_CX8| /* 3 */ \
+ CPUID_MCE|CPUID_PAE|CPUID_MSR|CPUID_TSC| /* f */ \
+ CPUID_PSE|CPUID_DE|CPUID_VME|CPUID_FP87) /* f */
+
static x86_def_t x86_defs[] = {
#ifdef TARGET_X86_64
{
@@ -127,12 +154,10 @@ static x86_def_t x86_defs[] = {
.model = 2,
.stepping = 3,
.features = PPRO_FEATURES |
- /* these features are needed for Win64 and aren't fully implemented */
- CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
- /* this feature is needed for Solaris and isn't fully implemented */
- CPUID_PSE36,
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* note 1 */
+ CPUID_PSE36, /* note 2 */
.ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16 | CPUID_EXT_POPCNT,
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
.ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
@@ -155,7 +180,7 @@ static x86_def_t x86_defs[] = {
.ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_CX16 |
CPUID_EXT_POPCNT,
/* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_MMXEXT |
CPUID_EXT2_FFXSR,
@@ -169,6 +194,126 @@ static x86_def_t x86_defs[] = {
.model_id = "AMD Phenom(tm) 9550 Quad-Core Processor"
},
{
+ .name = "Conroe",
+ .level = 2,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
+ .family = 6, /* P6 */
+ .model = 2,
+ .stepping = 3,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* note 1 */
+ CPUID_PSE36, /* note 2 */
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_SSSE3,
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .ext3_features = CPUID_EXT3_LAHF_LM,
+ .xlevel = 0x8000000A,
+ .model_id = "Intel Celeron_4x0 (Conroe/Merom Class Core 2)",
+ },
+ {
+ .name = "Penryn",
+ .level = 2,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
+ .family = 6, /* P6 */
+ .model = 2,
+ .stepping = 3,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* note 1 */
+ CPUID_PSE36, /* note 2 */
+ .ext_features = CPUID_EXT_SSE3 |
+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE41,
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .ext3_features = CPUID_EXT3_LAHF_LM,
+ .xlevel = 0x8000000A,
+ .model_id = "Intel Core 2 Duo P9xxx (Penryn Class Core 2)",
+ },
+ {
+ .name = "Nehalem",
+ .level = 2,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
+ .family = 6, /* P6 */
+ .model = 2,
+ .stepping = 3,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* note 1 */
+ CPUID_PSE36, /* note 2 */
+ .ext_features = CPUID_EXT_SSE3 |
+ CPUID_EXT_CX16 | CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 |
+ CPUID_EXT_SSE42 | CPUID_EXT_POPCNT,
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .ext3_features = CPUID_EXT3_LAHF_LM,
+ .xlevel = 0x8000000A,
+ .model_id = "Intel Core i7 9xx (Nehalem Class Core i7)",
+ },
+ {
+ .name = "Opteron_G1",
+ .level = 5,
+ .vendor1 = CPUID_VENDOR_AMD_1,
+ .vendor2 = CPUID_VENDOR_AMD_2,
+ .vendor3 = CPUID_VENDOR_AMD_3,
+ .family = 15,
+ .model = 6,
+ .stepping = 1,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* note 1 */
+ CPUID_PSE36, /* note 2 */
+ .ext_features = CPUID_EXT_SSE3,
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ .xlevel = 0x80000008,
+ .model_id = "AMD Opteron 240 (Gen 1 Class Opteron)",
+ },
+ {
+ .name = "Opteron_G2",
+ .level = 5,
+ .vendor1 = CPUID_VENDOR_AMD_1,
+ .vendor2 = CPUID_VENDOR_AMD_2,
+ .vendor3 = CPUID_VENDOR_AMD_3,
+ .family = 15,
+ .model = 6,
+ .stepping = 1,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* note 1 */
+ CPUID_PSE36, /* note 2 */
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
+ CPUID_EXT2_RDTSCP,
+ .ext3_features = CPUID_EXT3_SVM | CPUID_EXT3_LAHF_LM,
+ .xlevel = 0x80000008,
+ .model_id = "AMD Opteron 22xx (Gen 2 Class Opteron)",
+ },
+ {
+ .name = "Opteron_G3",
+ .level = 5,
+ .vendor1 = CPUID_VENDOR_AMD_1,
+ .vendor2 = CPUID_VENDOR_AMD_2,
+ .vendor3 = CPUID_VENDOR_AMD_3,
+ .family = 15,
+ .model = 6,
+ .stepping = 1,
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA | /* note 1 */
+ CPUID_PSE36, /* note 2 */
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR |
+ CPUID_EXT_POPCNT | CPUID_EXT_CX16,
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX |
+ CPUID_EXT2_RDTSCP,
+ .ext3_features = CPUID_EXT3_SVM | CPUID_EXT3_SSE4A | CPUID_EXT3_ABM |
+ CPUID_EXT3_MISALIGNSSE | CPUID_EXT3_LAHF_LM,
+ .xlevel = 0x80000008,
+ .model_id = "AMD Opteron 23xx (Gen 3 Class Opteron)",
+ },
+ {
.name = "core2duo",
.level = 10,
.family = 6,
@@ -205,7 +350,7 @@ static x86_def_t x86_defs[] = {
/* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
.ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
/* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) |
CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
/* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
@@ -292,7 +437,7 @@ static x86_def_t x86_defs[] = {
.model = 2,
.stepping = 3,
.features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA,
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
.xlevel = 0x80000008,
/* XXX: put another string ? */
.model_id = "QEMU Virtual CPU version " QEMU_VERSION,
@@ -313,12 +458,16 @@ static x86_def_t x86_defs[] = {
CPUID_EXT_SSE3 /* PNI */ | CPUID_EXT_SSSE3,
/* Missing: CPUID_EXT_DSCPL | CPUID_EXT_EST |
* CPUID_EXT_TM2 | CPUID_EXT_XTPR */
- .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_NX,
+ .ext2_features = (PPRO_FEATURES & CPUID_EXT2_MASK) | CPUID_EXT2_NX,
/* Missing: .ext3_features = CPUID_EXT3_LAHF_LM */
.xlevel = 0x8000000A,
.model_id = "Intel(R) Atom(TM) CPU N270 @ 1.60GHz",
- },
+ }
};
+/* notes for preceeding cpu models:
+ * 1: these features are needed for Win64 and aren't fully implemented
+ * 2: this feature is needed for Solaris and isn't fully implemented
+ */
static void host_cpuid(uint32_t function, uint32_t count, uint32_t *eax,
uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
@@ -368,6 +517,51 @@ static int cpu_x86_fill_host(x86_def_t *x86_cpu_def)
return 0;
}
+static int unavailable_host_feature(struct model_features_t *f, uint32_t mask)
+{
+ int i;
+
+ for (i = 0; i < 32; ++i)
+ if (1 << i & mask) {
+ fprintf(stderr, "warning: host cpuid %04x_%04x lacks requested"
+ " flag '%s' [0x%08x]\n",
+ f->cpuid >> 16, f->cpuid & 0xffff,
+ f->flag_names[i] ? f->flag_names[i] : "[reserved]", mask);
+ break;
+ }
+ return 0;
+}
+
+/* best effort attempt to inform user requested cpu flags aren't making
+ * their way to the guest. Note: ft[].check_feat ideally should be
+ * specified via a guest_def field to suppress report of extraneous flags.
+ */
+static int check_features_against_host(x86_def_t *guest_def)
+{
+ x86_def_t host_def;
+ uint32_t mask;
+ int rv, i;
+ struct model_features_t ft[] = {
+ {&guest_def->features, &host_def.features,
+ ~0, feature_name, 0x00000000},
+ {&guest_def->ext_features, &host_def.ext_features,
+ ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
+ {&guest_def->ext2_features, &host_def.ext2_features,
+ ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
+ {&guest_def->ext3_features, &host_def.ext3_features,
+ ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
+
+ cpu_x86_fill_host(&host_def);
+ for (rv = 0, i = 0; i < sizeof (ft) / sizeof (ft[0]); ++i)
+ for (mask = 1; mask; mask <<= 1)
+ if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
+ !(*ft[i].host_feat & mask)) {
+ unavailable_host_feature(&ft[i], mask);
+ rv = 1;
+ }
+ return rv;
+}
+
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
{
unsigned int i;
@@ -471,6 +665,8 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
fprintf(stderr, "unrecognized feature %s\n", featurestr);
goto error;
}
+ } else if (!strcmp(featurestr, "check")) {
+ check_cpuid = 1;
} else {
fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
goto error;
@@ -485,6 +681,9 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
x86_cpu_def->ext_features &= ~minus_ext_features;
x86_cpu_def->ext2_features &= ~minus_ext2_features;
x86_cpu_def->ext3_features &= ~minus_ext3_features;
+ if (check_cpuid) {
+ check_features_against_host(x86_cpu_def);
+ }
free(s);
return 0;
@@ -493,12 +692,19 @@ error:
return -1;
}
-void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+void x86_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ const char *optarg)
{
unsigned int i;
+ unsigned char id = !strcmp("??", optarg);
for (i = 0; i < ARRAY_SIZE(x86_defs); i++)
- (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
+ if (id) {
+ (*cpu_fprintf)(f, "x86 %16s %-48s\n", x86_defs[i].name,
+ x86_defs[i].model_id);
+ } else {
+ (*cpu_fprintf)(f, "x86 %16s\n", x86_defs[i].name);
+ }
}
static int cpu_x86_register (CPUX86State *env, const char *cpu_model)
@@ -4982,8 +4982,12 @@ int main(int argc, char **argv, char **envp)
/* hw initialization will check this */
if (*optarg == '?') {
/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list)
+#if defined(cpu_list_id)
+ cpu_list_id(stdout, &fprintf, optarg);
+#elif defined(cpu_list) /* revert to previous func definition */
cpu_list(stdout, &fprintf);
+#else
+#error cpu_list_id() is undefined for this architecture.
#endif
exit(0);
} else {