#include "hyperv.h"
+#include "hw/hw.h"
+
/* feature flags taken from "Intel Processor Identification and the CPUID
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
* between feature naming conventions, aliases may be added.
"ds_cpl", "vmx", "smx", "est",
"tm2", "ssse3", "cid", NULL,
"fma", "cx16", "xtpr", "pdcm",
- NULL, NULL, "dca", "sse4.1|sse4_1",
+ NULL, "pcid", "dca", "sse4.1|sse4_1",
"sse4.2|sse4_2", "x2apic", "movbe", "popcnt",
"tsc-deadline", "aes", "xsave", "osxsave",
"avx", NULL, NULL, "hypervisor",
};
static const char *kvm_feature_name[] = {
- "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, NULL, NULL,
+ "kvmclock", "kvm_nopiodelay", "kvm_mmu", "kvmclock", "kvm_asyncpf", NULL, "kvm_pv_eoi", NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Store the results of Centaur's CPUID instructions */
uint32_t ext4_features;
uint32_t xlevel2;
+ /* The feature bits on CPUID[EAX=7,ECX=0].EBX */
+ uint32_t cpuid_7_0_ebx_features;
} x86_def_t;
#define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE)
.ext3_features = CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM |
CPUID_EXT3_ABM | CPUID_EXT3_SSE4A,
.xlevel = 0x8000000A,
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
},
{
.name = "phenom",
.features = PPRO_FEATURES,
.ext_features = CPUID_EXT_SSE3 | CPUID_EXT_POPCNT,
.xlevel = 0x80000004,
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
},
{
.name = "kvm32",
.features = PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA,
.ext2_features = (PPRO_FEATURES & EXT2_FEATURE_MASK) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT,
.xlevel = 0x80000008,
- /* XXX: put another string ? */
- .model_id = "QEMU Virtual CPU version " QEMU_VERSION,
},
{
.name = "n270",
x86_cpu_def->ext_features = ecx;
x86_cpu_def->features = edx;
+ if (kvm_enabled() && x86_cpu_def->level >= 7) {
+ x86_cpu_def->cpuid_7_0_ebx_features = kvm_arch_get_supported_cpuid(kvm_state, 0x7, 0, R_EBX);
+ } else {
+ x86_cpu_def->cpuid_7_0_ebx_features = 0;
+ }
+
host_cpuid(0x80000000, 0, &eax, &ebx, &ecx, &edx);
x86_cpu_def->xlevel = eax;
const char *name, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
- int64_t value;
- value = cpu->env.cpuid_level;
- /* TODO Use visit_type_uint32() once available */
- visit_type_int(v, &value, name, errp);
+ visit_type_uint32(v, &cpu->env.cpuid_level, name, errp);
}
static void x86_cpuid_set_level(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
- const int64_t min = 0;
- const int64_t max = UINT32_MAX;
- int64_t value;
- /* TODO Use visit_type_uint32() once available */
- visit_type_int(v, &value, name, errp);
- if (error_is_set(errp)) {
- return;
- }
- if (value < min || value > max) {
- error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
- name ? name : "null", value, min, max);
- return;
- }
-
- cpu->env.cpuid_level = value;
+ visit_type_uint32(v, &cpu->env.cpuid_level, name, errp);
}
static void x86_cpuid_get_xlevel(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
- int64_t value;
- value = cpu->env.cpuid_xlevel;
- /* TODO Use visit_type_uint32() once available */
- visit_type_int(v, &value, name, errp);
+ visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp);
}
static void x86_cpuid_set_xlevel(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
- const int64_t min = 0;
- const int64_t max = UINT32_MAX;
- int64_t value;
-
- /* TODO Use visit_type_uint32() once available */
- visit_type_int(v, &value, name, errp);
- if (error_is_set(errp)) {
- return;
- }
- if (value < min || value > max) {
- error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, "",
- name ? name : "null", value, min, max);
- return;
- }
- cpu->env.cpuid_xlevel = value;
+ visit_type_uint32(v, &cpu->env.cpuid_xlevel, name, errp);
}
static char *x86_cpuid_get_vendor(Object *obj, Error **errp)
env->cpuid_kvm_features = def->kvm_features;
env->cpuid_svm_features = def->svm_features;
env->cpuid_ext4_features = def->ext4_features;
+ env->cpuid_7_0_ebx = def->cpuid_7_0_ebx_features;
env->cpuid_xlevel2 = def->xlevel2;
object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
"tsc-frequency", &error);
*/
void x86_cpudef_setup(void)
{
- int i;
+ int i, j;
+ static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon" };
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
builtin_x86_defs[i].next = x86_defs;
builtin_x86_defs[i].flags = 1;
+
+ /* Look for specific "cpudef" models that */
+ /* have the QEMU version in .model_id */
+ for (j = 0; j < ARRAY_SIZE(model_with_versions); j++) {
+ if (strcmp(model_with_versions[j], builtin_x86_defs[i].name) == 0) {
+ pstrcpy(builtin_x86_defs[i].model_id, sizeof(builtin_x86_defs[i].model_id), "QEMU Virtual CPU version ");
+ pstrcat(builtin_x86_defs[i].model_id, sizeof(builtin_x86_defs[i].model_id), qemu_get_version());
+ break;
+ }
+ }
+
x86_defs = &builtin_x86_defs[i];
}
#if !defined(CONFIG_USER_ONLY)
*edx = 0;
break;
case 7:
- if (kvm_enabled()) {
- KVMState *s = env->kvm_state;
-
- *eax = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EAX);
- *ebx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EBX);
- *ecx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_ECX);
- *edx = kvm_arch_get_supported_cpuid(s, 0x7, count, R_EDX);
+ /* Structured Extended Feature Flags Enumeration Leaf */
+ if (count == 0) {
+ *eax = 0; /* Maximum ECX value for sub-leaves */
+ *ebx = env->cpuid_7_0_ebx; /* Feature flags */
+ *ecx = 0; /* Reserved */
+ *edx = 0; /* Reserved */
} else {
*eax = 0;
*ebx = 0;
env->dr[7] = DR7_FIXED_1;
cpu_breakpoint_remove_all(env, BP_CPU);
cpu_watchpoint_remove_all(env, BP_CPU);
+
+#if !defined(CONFIG_USER_ONLY)
+ /* We hard-wire the BSP to the first CPU. */
+ if (env->cpu_index == 0) {
+ apic_designate_bsp(env->apic_state);
+ }
+
+ env->halted = !cpu_is_bsp(cpu);
+#endif
+}
+
+#ifndef CONFIG_USER_ONLY
+bool cpu_is_bsp(X86CPU *cpu)
+{
+ return cpu_get_apic_base(cpu->env.apic_state) & MSR_IA32_APICBASE_BSP;
}
+/* TODO: remove me, when reset over QOM tree is implemented */
+static void x86_cpu_machine_reset_cb(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ cpu_reset(CPU(cpu));
+}
+#endif
+
static void mce_init(X86CPU *cpu)
{
CPUX86State *cenv = &cpu->env;
}
}
+void x86_cpu_realize(Object *obj, Error **errp)
+{
+ X86CPU *cpu = X86_CPU(obj);
+
+#ifndef CONFIG_USER_ONLY
+ qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
+#endif
+
+ mce_init(cpu);
+ qemu_init_vcpu(&cpu->env);
+ cpu_reset(CPU(cpu));
+}
+
static void x86_cpu_initfn(Object *obj)
{
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
+ static int inited;
cpu_exec_init(env);
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
env->cpuid_apic_id = env->cpu_index;
- mce_init(cpu);
+
+ /* init various static tables used in TCG mode */
+ if (tcg_enabled() && !inited) {
+ inited = 1;
+ optimize_flags_init();
+#ifndef CONFIG_USER_ONLY
+ cpu_set_debug_excp_handler(breakpoint_handler);
+#endif
+ }
}
static void x86_cpu_common_class_init(ObjectClass *oc, void *data)