NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
};
+const char *get_register_name_32(unsigned int reg)
+{
+ static const char *reg_names[CPU_NB_REGS32] = {
+ [R_EAX] = "EAX",
+ [R_ECX] = "ECX",
+ [R_EDX] = "EDX",
+ [R_EBX] = "EBX",
+ [R_ESP] = "ESP",
+ [R_EBP] = "EBP",
+ [R_ESI] = "ESI",
+ [R_EDI] = "EDI",
+ };
+
+ if (reg > CPU_NB_REGS32) {
+ return NULL;
+ }
+ return reg_names[reg];
+}
+
/* 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 reg;
+} model_features_t;
int check_cpuid = 0;
int enforce_cpuid = 0;
{
.name = "core2duo",
.level = 10,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 6,
.model = 15,
.stepping = 11,
{
.name = "qemu32",
.level = 4,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 6,
.model = 3,
.stepping = 3,
{
.name = "kvm32",
.level = 5,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 15,
.model = 6,
.stepping = 1,
{
.name = "coreduo",
.level = 10,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 6,
.model = 14,
.stepping = 8,
{
.name = "486",
.level = 1,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 4,
.model = 0,
.stepping = 0,
{
.name = "pentium",
.level = 1,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 5,
.model = 4,
.stepping = 3,
{
.name = "pentium2",
.level = 2,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 6,
.model = 5,
.stepping = 2,
{
.name = "pentium3",
.level = 2,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 6,
.model = 7,
.stepping = 3,
.name = "n270",
/* original is on level 10 */
.level = 5,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
.family = 6,
.model = 28,
.stepping = 2,
}
}
- /*
- * Every SVM feature requires emulation support in KVM - so we can't just
- * read the host features here. KVM might even support SVM features not
- * available on the host hardware. Just set all bits and mask out the
- * unsupported ones later.
- */
- x86_cpu_def->svm_features = -1;
+ /* Other KVM-specific feature fields: */
+ x86_cpu_def->svm_features =
+ kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX);
+ x86_cpu_def->kvm_features =
+ kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
+
#endif /* CONFIG_KVM */
}
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);
+ const char *reg = get_register_name_32(f->reg);
+ assert(reg);
+ fprintf(stderr, "warning: host doesn't support requested feature: "
+ "CPUID.%02XH:%s%s%s [bit %d]\n",
+ f->cpuid, reg,
+ f->flag_names[i] ? "." : "",
+ f->flag_names[i] ? f->flag_names[i] : "", i);
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.
+ * their way to the guest.
*
* This function may be called only if KVM is enabled.
*/
int rv, i;
struct model_features_t ft[] = {
{&guest_def->features, &host_def.features,
- ~0, feature_name, 0x00000000},
+ feature_name, 0x00000001, R_EDX},
{&guest_def->ext_features, &host_def.ext_features,
- ~CPUID_EXT_HYPERVISOR, ext_feature_name, 0x00000001},
+ ext_feature_name, 0x00000001, R_ECX},
{&guest_def->ext2_features, &host_def.ext2_features,
- ~PPRO_FEATURES, ext2_feature_name, 0x80000000},
+ ext2_feature_name, 0x80000001, R_EDX},
{&guest_def->ext3_features, &host_def.ext3_features,
- ~CPUID_EXT3_SVM, ext3_feature_name, 0x80000001}};
+ ext3_feature_name, 0x80000001, R_ECX}
+ };
assert(kvm_enabled());
kvm_cpu_fill_host(&host_def);
for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i)
for (mask = 1; mask; mask <<= 1)
- if (ft[i].check_feat & mask && *ft[i].guest_feat & mask &&
+ if (*ft[i].guest_feat & mask &&
!(*ft[i].host_feat & mask)) {
unavailable_host_feature(&ft[i], mask);
rv = 1;
if (cpu_x86_parse_featurestr(def, features) < 0) {
goto error;
}
- if (def->vendor1) {
- env->cpuid_vendor1 = def->vendor1;
- env->cpuid_vendor2 = def->vendor2;
- env->cpuid_vendor3 = def->vendor3;
- } else {
- env->cpuid_vendor1 = CPUID_VENDOR_INTEL_1;
- env->cpuid_vendor2 = CPUID_VENDOR_INTEL_2;
- env->cpuid_vendor3 = CPUID_VENDOR_INTEL_3;
- }
+ assert(def->vendor1);
+ env->cpuid_vendor1 = def->vendor1;
+ env->cpuid_vendor2 = def->vendor2;
+ env->cpuid_vendor3 = def->vendor3;
env->cpuid_vendor_override = def->vendor_override;
object_property_set_int(OBJECT(cpu), def->level, "level", &error);
object_property_set_int(OBJECT(cpu), def->family, "family", &error);
object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
"tsc-frequency", &error);
- /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on
- * CPUID[1].EDX.
- */
- if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 &&
- env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 &&
- env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) {
- env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES;
- env->cpuid_ext2_features |= (def->features & CPUID_EXT2_AMD_ALIASES);
- }
-
- if (!kvm_enabled()) {
- env->cpuid_features &= TCG_FEATURES;
- env->cpuid_ext_features &= TCG_EXT_FEATURES;
- env->cpuid_ext2_features &= (TCG_EXT2_FEATURES
-#ifdef TARGET_X86_64
- | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM
-#endif
- );
- env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
- env->cpuid_svm_features &= TCG_SVM_FEATURES;
- } else {
-#ifdef CONFIG_KVM
- filter_features_for_kvm(cpu);
-#endif
- }
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error);
if (error) {
fprintf(stderr, "%s\n", error_get_pretty(error));
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
+ X86CPU *cpu = x86_env_get_cpu(env);
+ CPUState *cs = CPU(cpu);
+
/* test if maximum index reached */
if (index & 0x80000000) {
if (index > env->cpuid_xlevel) {
index = env->cpuid_xlevel;
}
} else {
- index = env->cpuid_xlevel;
+ /* Intel documentation states that invalid EAX input will
+ * return the same information as EAX=cpuid_level
+ * (Intel SDM Vol. 2A - Instruction Set Reference - CPUID)
+ */
+ index = env->cpuid_level;
}
}
} else {
*ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
*ecx = env->cpuid_ext_features;
*edx = env->cpuid_features;
- if (env->nr_cores * env->nr_threads > 1) {
- *ebx |= (env->nr_cores * env->nr_threads) << 16;
+ if (cs->nr_cores * cs->nr_threads > 1) {
+ *ebx |= (cs->nr_cores * cs->nr_threads) << 16;
*edx |= 1 << 28; /* HTT bit */
}
break;
break;
case 4:
/* cache info: needed for Core compatibility */
- if (env->nr_cores > 1) {
- *eax = (env->nr_cores - 1) << 26;
+ if (cs->nr_cores > 1) {
+ *eax = (cs->nr_cores - 1) << 26;
} else {
*eax = 0;
}
break;
case 2: /* L2 cache info */
*eax |= 0x0000143;
- if (env->nr_threads > 1) {
- *eax |= (env->nr_threads - 1) << 14;
+ if (cs->nr_threads > 1) {
+ *eax |= (cs->nr_threads - 1) << 14;
}
*ebx = 0x3c0003f;
*ecx = 0x0000fff;
case 0xA:
/* Architectural Performance Monitoring Leaf */
if (kvm_enabled()) {
- KVMState *s = env->kvm_state;
+ KVMState *s = cs->kvm_state;
*eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX);
*ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX);
break;
}
if (kvm_enabled()) {
- KVMState *s = env->kvm_state;
+ KVMState *s = cs->kvm_state;
*eax = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EAX);
*ebx = kvm_arch_get_supported_cpuid(s, 0xd, count, R_EBX);
* discards multiple thread information if it is set.
* So dont set it here for Intel to make Linux guests happy.
*/
- if (env->nr_cores * env->nr_threads > 1) {
+ if (cs->nr_cores * cs->nr_threads > 1) {
uint32_t tebx, tecx, tedx;
get_cpuid_vendor(env, &tebx, &tecx, &tedx);
if (tebx != CPUID_VENDOR_INTEL_1 ||
*ebx = 0;
*ecx = 0;
*edx = 0;
- if (env->nr_cores * env->nr_threads > 1) {
- *ecx |= (env->nr_cores * env->nr_threads) - 1;
+ if (cs->nr_cores * cs->nr_threads > 1) {
+ *ecx |= (cs->nr_cores * cs->nr_threads) - 1;
}
break;
case 0x8000000A:
int i;
if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ qemu_log("CPU Reset (CPU %d)\n", s->cpu_index);
log_cpu_state(env, CPU_DUMP_FPU | CPU_DUMP_CCOP);
}
#if !defined(CONFIG_USER_ONLY)
/* We hard-wire the BSP to the first CPU. */
- if (env->cpu_index == 0) {
+ if (s->cpu_index == 0) {
apic_designate_bsp(env->apic_state);
}
env->cpuid_level = 7;
}
+ /* On AMD CPUs, some CPUID[8000_0001].EDX bits must match the bits on
+ * CPUID[1].EDX.
+ */
+ if (env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 &&
+ env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 &&
+ env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) {
+ env->cpuid_ext2_features &= ~CPUID_EXT2_AMD_ALIASES;
+ env->cpuid_ext2_features |= (env->cpuid_features
+ & CPUID_EXT2_AMD_ALIASES);
+ }
+
+ if (!kvm_enabled()) {
+ env->cpuid_features &= TCG_FEATURES;
+ env->cpuid_ext_features &= TCG_EXT_FEATURES;
+ env->cpuid_ext2_features &= (TCG_EXT2_FEATURES
+#ifdef TARGET_X86_64
+ | CPUID_EXT2_SYSCALL | CPUID_EXT2_LM
+#endif
+ );
+ env->cpuid_ext3_features &= TCG_EXT3_FEATURES;
+ env->cpuid_svm_features &= TCG_SVM_FEATURES;
+ } else {
+#ifdef CONFIG_KVM
+ filter_features_for_kvm(cpu);
+#endif
+ }
+
#ifndef CONFIG_USER_ONLY
qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
static void x86_cpu_initfn(Object *obj)
{
+ CPUState *cs = CPU(obj);
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
static int inited;
x86_cpuid_get_tsc_freq,
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
- env->cpuid_apic_id = env->cpu_index;
+ env->cpuid_apic_id = cs->cpu_index;
/* init various static tables used in TCG mode */
if (tcg_enabled() && !inited) {