[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclass
From: |
Igor Mammedov |
Subject: |
[Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses |
Date: |
Tue, 5 Feb 2013 17:39:22 +0100 |
From: Andreas Färber <address@hidden>
Move x86_def_t definition to header and embed into X86CPUClass.
Register types per built-in model definition.
Move version initialization from x86_cpudef_setup() to class_init.
Inline cpu_x86_register() into the X86CPU initfn.
Since instance_init cannot reports errors, drop error handling.
Replace cpu_x86_find_by_name() with x86_cpu_class_by_name().
Move handling of KVM host vendor override from cpu_x86_find_by_name()
to the kvm_arch_init() and class_init(). Use TYPE_X86_CPU class to
communicate kvm specific defaults to other sub-classes.
Register host-{i386,x86_64}-cpu type from KVM code to avoid #ifdefs
and only when KVM is enabled to avoid hacks in CPU code.
Make kvm_cpu_fill_host() into a host specific class_init and inline
cpu_x86_fill_model_id().
Let kvm_check_features_against_host() obtain host-{i386,86_64}-cpu for
comparison.
Signed-off-by: Andreas Färber <address@hidden>
Signed-off-by: Igor Mammedov <address@hidden>
---
v4:
* set error if cpu model is not found and goto out;
* copy vendor override from 'host' CPU class in sub-class'es
class_init() if 'host' CPU class is available.
* register type TYPE_HOST_X86_CPU in kvm_arch_init(), this type
should be available only in KVM mode and we haven't printed it in
-cpu ? output so far, so we can continue doing so. It's not
really confusing to show 'host' cpu (even if we do it) when KVM
is not enabled.
* remove special case for 'host' CPU check in x86_cpu_class_by_name(),
due to 'host' CPU will not find anything if not in KVM mode or
return 'host' CPU class in KVM mode, i.e. treat it as regular CPUs.
---
target-i386/cpu-qom.h | 24 ++++
target-i386/cpu.c | 331 ++++++++++++++++++-------------------------------
target-i386/cpu.h | 5 +-
target-i386/kvm.c | 72 +++++++++++
4 files changed, 217 insertions(+), 215 deletions(-)
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index 48e6b54..80bf72d 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -30,6 +30,27 @@
#define TYPE_X86_CPU "i386-cpu"
#endif
+#define TYPE_HOST_X86_CPU "host-" TYPE_X86_CPU
+
+typedef struct x86_def_t {
+ const char *name;
+ uint32_t level;
+ /* vendor is zero-terminated, 12 character ASCII string */
+ char vendor[CPUID_VENDOR_SZ + 1];
+ int family;
+ int model;
+ int stepping;
+ uint32_t features, ext_features, ext2_features, ext3_features;
+ uint32_t kvm_features, svm_features;
+ uint32_t xlevel;
+ char model_id[48];
+ /* 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 X86_CPU_CLASS(klass) \
OBJECT_CLASS_CHECK(X86CPUClass, (klass), TYPE_X86_CPU)
#define X86_CPU(obj) \
@@ -41,6 +62,7 @@
* X86CPUClass:
* @parent_realize: The parent class' realize handler.
* @parent_reset: The parent class' reset handler.
+ * @info: Model-specific data.
*
* An x86 CPU model or family.
*/
@@ -51,6 +73,8 @@ typedef struct X86CPUClass {
DeviceRealize parent_realize;
void (*parent_reset)(CPUState *cpu);
+
+ x86_def_t info;
} X86CPUClass;
/**
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 1aee097..62fdc84 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -47,8 +47,8 @@
#include "hw/apic_internal.h"
#endif
-static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
- uint32_t vendor2, uint32_t vendor3)
+void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
+ uint32_t vendor2, uint32_t vendor3)
{
int i;
for (i = 0; i < 4; i++) {
@@ -346,25 +346,6 @@ static void add_flagname_to_bitmaps(const char *flagname,
}
}
-typedef struct x86_def_t {
- const char *name;
- uint32_t level;
- /* vendor is zero-terminated, 12 character ASCII string */
- char vendor[CPUID_VENDOR_SZ + 1];
- int family;
- int model;
- int stepping;
- uint32_t features, ext_features, ext2_features, ext3_features;
- uint32_t kvm_features, svm_features;
- uint32_t xlevel;
- char model_id[48];
- /* 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)
#define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \
CPUID_MSR | CPUID_MCE | CPUID_CX8 | CPUID_MMX | CPUID_APIC)
@@ -868,86 +849,6 @@ static x86_def_t builtin_x86_defs[] = {
},
};
-#ifdef CONFIG_KVM
-static int cpu_x86_fill_model_id(char *str)
-{
- uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
- int i;
-
- for (i = 0; i < 3; i++) {
- host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
- memcpy(str + i * 16 + 0, &eax, 4);
- memcpy(str + i * 16 + 4, &ebx, 4);
- memcpy(str + i * 16 + 8, &ecx, 4);
- memcpy(str + i * 16 + 12, &edx, 4);
- }
- return 0;
-}
-#endif
-
-/* Fill a x86_def_t struct with information about the host CPU, and
- * the CPU features supported by the host hardware + host kernel
- *
- * This function may be called only if KVM is enabled.
- */
-static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
-{
-#ifdef CONFIG_KVM
- KVMState *s = kvm_state;
- uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
-
- assert(kvm_enabled());
-
- x86_cpu_def->name = "host";
- host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
-
- host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
- x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
- x86_cpu_def->stepping = eax & 0x0F;
-
- x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
- x86_cpu_def->features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_EDX);
- x86_cpu_def->ext_features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_ECX);
-
- if (x86_cpu_def->level >= 7) {
- x86_cpu_def->cpuid_7_0_ebx_features =
- kvm_arch_get_supported_cpuid(s, 0x7, 0, R_EBX);
- } else {
- x86_cpu_def->cpuid_7_0_ebx_features = 0;
- }
-
- x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0,
R_EAX);
- x86_cpu_def->ext2_features =
- kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
- x86_cpu_def->ext3_features =
- kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
-
- cpu_x86_fill_model_id(x86_cpu_def->model_id);
-
- /* Call Centaur's CPUID instruction. */
- if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) {
- host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
- eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
- if (eax >= 0xC0000001) {
- /* Support VIA max extended level */
- x86_cpu_def->xlevel2 = eax;
- host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
- x86_cpu_def->ext4_features =
- kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
- }
- }
-
- /* 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 */
-}
-
static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask)
{
int i;
@@ -975,31 +876,31 @@ static int unavailable_host_feature(FeatureWordInfo *f,
uint32_t mask)
static int kvm_check_features_against_host(X86CPU *cpu)
{
CPUX86State *env = &cpu->env;
- x86_def_t host_def;
+ ObjectClass *host_oc = object_class_by_name(TYPE_HOST_X86_CPU);
+ X86CPUClass *host_xcc = X86_CPU_CLASS(host_oc);
uint32_t mask;
int rv, i;
struct model_features_t ft[] = {
- {&env->cpuid_features, &host_def.features,
+ {&env->cpuid_features, &host_xcc->info.features,
FEAT_1_EDX },
- {&env->cpuid_ext_features, &host_def.ext_features,
+ {&env->cpuid_ext_features, &host_xcc->info.ext_features,
FEAT_1_ECX },
- {&env->cpuid_ext2_features, &host_def.ext2_features,
+ {&env->cpuid_ext2_features, &host_xcc->info.ext2_features,
FEAT_8000_0001_EDX },
- {&env->cpuid_ext3_features, &host_def.ext3_features,
+ {&env->cpuid_ext3_features, &host_xcc->info.ext3_features,
FEAT_8000_0001_ECX },
- {&env->cpuid_ext4_features, &host_def.ext4_features,
+ {&env->cpuid_ext4_features, &host_xcc->info.ext4_features,
FEAT_C000_0001_EDX },
- {&env->cpuid_7_0_ebx_features, &host_def.cpuid_7_0_ebx_features,
+ {&env->cpuid_7_0_ebx_features, &host_xcc->info.cpuid_7_0_ebx_features,
FEAT_7_0_EBX },
- {&env->cpuid_svm_features, &host_def.svm_features,
+ {&env->cpuid_svm_features, &host_xcc->info.svm_features,
FEAT_SVM },
- {&env->cpuid_kvm_features, &host_def.kvm_features,
+ {&env->cpuid_kvm_features, &host_xcc->info.kvm_features,
FEAT_KVM },
};
assert(kvm_enabled());
- kvm_cpu_fill_host(&host_def);
for (rv = 0, i = 0; i < ARRAY_SIZE(ft); ++i) {
FeatureWord w = ft[i].feat_word;
FeatureWordInfo *wi = &feature_word_info[w];
@@ -1261,40 +1162,30 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor
*v, void *opaque,
cpu->env.tsc_khz = value / 1000;
}
-static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
+static ObjectClass *x86_cpu_class_by_name(const char *name)
{
- x86_def_t *def;
- int i;
+ ObjectClass *oc;
+ char *typename;
if (name == NULL) {
- return -1;
- }
- if (kvm_enabled() && strcmp(name, "host") == 0) {
- kvm_cpu_fill_host(x86_cpu_def);
- return 0;
+ return NULL;
}
- for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
- def = &builtin_x86_defs[i];
- if (strcmp(name, def->name) == 0) {
- memcpy(x86_cpu_def, def, sizeof(*def));
- /* sysenter isn't supported in compatibility mode on AMD,
- * syscall isn't supported in compatibility mode on Intel.
- * Normally we advertise the actual CPU vendor, but you can
- * override this using the 'vendor' property if you want to use
- * KVM's sysenter/syscall emulation in compatibility mode and
- * when doing cross vendor migration
- */
- if (kvm_enabled()) {
- uint32_t ebx = 0, ecx = 0, edx = 0;
- host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
- x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
- }
- return 0;
+ if (strcmp(name, "host") == 0) {
+ if (kvm_enabled()) {
+ return object_class_by_name(TYPE_HOST_X86_CPU);
}
+ return NULL;
}
- return -1;
+ typename = g_strdup_printf("%s-" TYPE_X86_CPU, name);
+ oc = object_class_by_name(typename);
+ g_free(typename);
+ if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_X86_CPU) ||
+ object_class_is_abstract(oc))) {
+ oc = NULL;
+ }
+ return oc;
}
/* Parse "+feature,-feature,feature=foo" CPU feature string
@@ -1516,57 +1407,13 @@ static void filter_features_for_kvm(X86CPU *cpu)
}
#endif
-static int cpu_x86_register(X86CPU *cpu, const char *name)
-{
- CPUX86State *env = &cpu->env;
- x86_def_t def1, *def = &def1;
- Error *error = NULL;
-
- memset(def, 0, sizeof(*def));
-
- if (cpu_x86_find_by_name(def, name) < 0) {
- error_setg(&error, "Unable to find CPU definition: %s", name);
- goto out;
- }
-
- if (kvm_enabled()) {
- def->kvm_features |= kvm_default_features;
- }
- def->ext_features |= CPUID_EXT_HYPERVISOR;
-
- object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error);
- 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), def->model, "model", &error);
- object_property_set_int(OBJECT(cpu), def->stepping, "stepping", &error);
- env->cpuid_features = def->features;
- env->cpuid_ext_features = def->ext_features;
- env->cpuid_ext2_features = def->ext2_features;
- env->cpuid_ext3_features = def->ext3_features;
- object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", &error);
- 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_features = def->cpuid_7_0_ebx_features;
- env->cpuid_xlevel2 = def->xlevel2;
-
- object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error);
-
-out:
- if (error) {
- fprintf(stderr, "%s\n", error_get_pretty(error));
- error_free(error);
- return -1;
- }
- return 0;
-}
-
X86CPU *cpu_x86_init(const char *cpu_model)
{
X86CPU *cpu = NULL;
CPUX86State *env;
gchar **model_pieces;
char *name, *features;
+ ObjectClass *oc;
Error *error = NULL;
model_pieces = g_strsplit(cpu_model, ",", 2);
@@ -1577,14 +1424,14 @@ X86CPU *cpu_x86_init(const char *cpu_model)
name = model_pieces[0];
features = model_pieces[1];
- cpu = X86_CPU(object_new(TYPE_X86_CPU));
- env = &cpu->env;
- env->cpu_model_str = cpu_model;
-
- if (cpu_x86_register(cpu, name) < 0) {
- error_setg(&error, "Unable to register CPU: %s", name);
+ oc = x86_cpu_class_by_name(name);
+ if (oc == NULL) {
+ error_setg(&error, "Unable to find CPU model: %s", name);
goto out;
}
+ cpu = X86_CPU(object_new(object_class_get_name(oc)));
+ env = &cpu->env;
+ env->cpu_model_str = cpu_model;
cpu_x86_parse_featurestr(cpu, features, &error);
if (error) {
@@ -1618,30 +1465,6 @@ void cpu_clear_apic_feature(CPUX86State *env)
#endif /* !CONFIG_USER_ONLY */
-/* Initialize list of CPU models, filling some non-static fields if necessary
- */
-void x86_cpudef_setup(void)
-{
- int i, j;
- static const char *model_with_versions[] = { "qemu32", "qemu64", "athlon"
};
-
- for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
- x86_def_t *def = &builtin_x86_defs[i];
-
- /* 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], def->name) == 0) {
- pstrcpy(def->model_id, sizeof(def->model_id),
- "QEMU Virtual CPU version ");
- pstrcat(def->model_id, sizeof(def->model_id),
- qemu_get_version());
- break;
- }
- }
- }
-}
-
static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
{
@@ -2195,6 +2018,8 @@ static void x86_cpu_initfn(Object *obj)
CPUState *cs = CPU(obj);
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
+ X86CPUClass *xcc = X86_CPU_GET_CLASS(obj);
+ const x86_def_t *def = &xcc->info;
static int inited;
cpu_exec_init(env);
@@ -2224,6 +2049,28 @@ static void x86_cpu_initfn(Object *obj)
x86_cpuid_get_tsc_freq,
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
+ object_property_set_str(OBJECT(cpu), def->vendor, "vendor", NULL);
+ object_property_set_int(OBJECT(cpu), def->level, "level", NULL);
+ object_property_set_int(OBJECT(cpu), def->family, "family", NULL);
+ object_property_set_int(OBJECT(cpu), def->model, "model", NULL);
+ object_property_set_int(OBJECT(cpu), def->stepping, "stepping", NULL);
+ env->cpuid_features = def->features;
+ env->cpuid_ext_features = def->ext_features;
+ env->cpuid_ext_features |= CPUID_EXT_HYPERVISOR;
+ env->cpuid_ext2_features = def->ext2_features;
+ env->cpuid_ext3_features = def->ext3_features;
+ object_property_set_int(OBJECT(cpu), def->xlevel, "xlevel", NULL);
+ env->cpuid_kvm_features = def->kvm_features;
+ if (kvm_enabled()) {
+ env->cpuid_kvm_features |= kvm_default_features;
+ }
+ env->cpuid_svm_features = def->svm_features;
+ env->cpuid_ext4_features = def->ext4_features;
+ env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features;
+ env->cpuid_xlevel2 = def->xlevel2;
+
+ object_property_set_str(OBJECT(cpu), def->model_id, "model-id", NULL);
+
env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
/* init various static tables used in TCG mode */
@@ -2236,6 +2083,44 @@ static void x86_cpu_initfn(Object *obj)
}
}
+static void x86_cpu_def_class_init(ObjectClass *oc, void *data)
+{
+ X86CPUClass *xcc = X86_CPU_CLASS(oc);
+ ObjectClass *hoc = object_class_by_name(TYPE_HOST_X86_CPU);
+ X86CPUClass *hostcc;
+ x86_def_t *def = data;
+ int i;
+ static const char *versioned_models[] = { "qemu32", "qemu64", "athlon" };
+
+ memcpy(&xcc->info, def, sizeof(x86_def_t));
+
+ /* host cpu class is available if KVM is enabled,
+ * get kvm overrides from it */
+ if (hoc) {
+ hostcc = X86_CPU_CLASS(hoc);
+ /* sysenter isn't supported in compatibility mode on AMD,
+ * syscall isn't supported in compatibility mode on Intel.
+ * Normally we advertise the actual CPU vendor, but you can
+ * override this using the 'vendor' property if you want to use
+ * KVM's sysenter/syscall emulation in compatibility mode and
+ * when doing cross vendor migration
+ */
+ memcpy(xcc->info.vendor, hostcc->info.vendor,
+ sizeof(xcc->info.vendor));
+ }
+
+ /* Look for specific models that have the QEMU version in .model_id */
+ for (i = 0; i < ARRAY_SIZE(versioned_models); i++) {
+ if (strcmp(versioned_models[i], def->name) == 0) {
+ pstrcpy(xcc->info.model_id, sizeof(xcc->info.model_id),
+ "QEMU Virtual CPU version ");
+ pstrcat(xcc->info.model_id, sizeof(xcc->info.model_id),
+ qemu_get_version());
+ break;
+ }
+ }
+}
+
static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
{
X86CPUClass *xcc = X86_CPU_CLASS(oc);
@@ -2247,6 +2132,21 @@ static void x86_cpu_common_class_init(ObjectClass *oc,
void *data)
xcc->parent_reset = cc->reset;
cc->reset = x86_cpu_reset;
+
+ cc->class_by_name = x86_cpu_class_by_name;
+}
+
+static void x86_register_cpu_type(const x86_def_t *def)
+{
+ TypeInfo type_info = {
+ .parent = TYPE_X86_CPU,
+ .class_init = x86_cpu_def_class_init,
+ .class_data = (void *)def,
+ };
+
+ type_info.name = g_strdup_printf("%s-" TYPE_X86_CPU, def->name);
+ type_register(&type_info);
+ g_free((void *)type_info.name);
}
static const TypeInfo x86_cpu_type_info = {
@@ -2254,14 +2154,19 @@ static const TypeInfo x86_cpu_type_info = {
.parent = TYPE_CPU,
.instance_size = sizeof(X86CPU),
.instance_init = x86_cpu_initfn,
- .abstract = false,
+ .abstract = true,
.class_size = sizeof(X86CPUClass),
.class_init = x86_cpu_common_class_init,
};
static void x86_cpu_register_types(void)
{
+ int i;
+
type_register_static(&x86_cpu_type_info);
+ for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
+ x86_register_cpu_type(&builtin_x86_defs[i]);
+ }
}
type_init(x86_cpu_register_types)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 7577e4f..11ef942 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -887,7 +887,6 @@ typedef struct CPUX86State {
X86CPU *cpu_x86_init(const char *cpu_model);
int cpu_x86_exec(CPUX86State *s);
void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf);
-void x86_cpudef_setup(void);
int cpu_x86_support_mca_broadcast(CPUX86State *env);
int cpu_get_pic_interrupt(CPUX86State *s);
@@ -1079,7 +1078,6 @@ static inline CPUX86State *cpu_init(const char *cpu_model)
#define cpu_gen_code cpu_x86_gen_code
#define cpu_signal_handler cpu_x86_signal_handler
#define cpu_list x86_cpu_list
-#define cpudef_setup x86_cpudef_setup
#define CPU_SAVE_VERSION 12
@@ -1256,4 +1254,7 @@ const char *get_register_name_32(unsigned int reg);
uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index);
void enable_compat_apic_id_mode(void);
+void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
+ uint32_t vendor2, uint32_t vendor3);
+
#endif /* CPU_I386_H */
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 9ebf181..dcaae76 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -735,6 +735,69 @@ static int kvm_get_supported_msrs(KVMState *s)
return ret;
}
+
+static void kvm_host_cpu_class_init(ObjectClass *oc, void *data)
+{
+ X86CPUClass *xcc = X86_CPU_CLASS(oc);
+ x86_def_t *x86_cpu_def = &xcc->info;
+ KVMState *s = kvm_state;
+ uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+ int i;
+
+ xcc->info.name = "host";
+ host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
+
+ host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
+ x86_cpu_def->model = ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12);
+ x86_cpu_def->stepping = eax & 0x0F;
+
+ x86_cpu_def->level = kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX);
+ x86_cpu_def->features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_EDX);
+ x86_cpu_def->ext_features = kvm_arch_get_supported_cpuid(s, 0x1, 0, R_ECX);
+
+ if (x86_cpu_def->level >= 7) {
+ x86_cpu_def->cpuid_7_0_ebx_features =
+ kvm_arch_get_supported_cpuid(s, 0x7, 0, R_EBX);
+ } else {
+ x86_cpu_def->cpuid_7_0_ebx_features = 0;
+ }
+
+ x86_cpu_def->xlevel = kvm_arch_get_supported_cpuid(s, 0x80000000, 0,
R_EAX);
+ x86_cpu_def->ext2_features =
+ kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX);
+ x86_cpu_def->ext3_features =
+ kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
+
+ for (i = 0; i < 3; i++) {
+ host_cpuid(0x80000002 + i, 0, &eax, &ebx, &ecx, &edx);
+ memcpy(xcc->info.model_id + i * 16 + 0, &eax, 4);
+ memcpy(xcc->info.model_id + i * 16 + 4, &ebx, 4);
+ memcpy(xcc->info.model_id + i * 16 + 8, &ecx, 4);
+ memcpy(xcc->info.model_id + i * 16 + 12, &edx, 4);
+ }
+
+ /* Call Centaur's CPUID instruction. */
+ if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) {
+ host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
+ eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
+ if (eax >= 0xC0000001) {
+ /* Support VIA max extended level */
+ x86_cpu_def->xlevel2 = eax;
+ host_cpuid(0xC0000001, 0, &eax, &ebx, &ecx, &edx);
+ x86_cpu_def->ext4_features =
+ kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX);
+ }
+ }
+
+ /* 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);
+}
+
int kvm_arch_init(KVMState *s)
{
QemuOptsList *list = qemu_find_opts("machine");
@@ -743,6 +806,12 @@ int kvm_arch_init(KVMState *s)
int ret;
struct utsname utsname;
+ static const TypeInfo host_x86_cpu_type_info = {
+ .name = TYPE_HOST_X86_CPU,
+ .parent = TYPE_X86_CPU,
+ .class_init = kvm_host_cpu_class_init,
+ };
+
ret = kvm_get_supported_msrs(s);
if (ret < 0) {
return ret;
@@ -797,6 +866,9 @@ int kvm_arch_init(KVMState *s)
}
}
}
+
+ type_register(&host_x86_cpu_type_info);
+
return 0;
}
--
1.7.1
- [Qemu-devel] [PATCH 2/5] target-i386: Split command line parsing out of cpu_x86_register(), (continued)
- [Qemu-devel] [PATCH 2/5] target-i386: Split command line parsing out of cpu_x86_register(), Igor Mammedov, 2013/02/05
- [Qemu-devel] [PATCH 5/5] target-i386: fix kvm_default_features overwriting kvm_arch_get_supported_cpuid(), Igor Mammedov, 2013/02/05
- Re: [Qemu-devel] [PATCH 5/5] target-i386: fix kvm_default_features overwriting kvm_arch_get_supported_cpuid(), Eduardo Habkost, 2013/02/05
- Re: [Qemu-devel] [PATCH 5/5] target-i386: fix kvm_default_features overwriting kvm_arch_get_supported_cpuid(), Igor Mammedov, 2013/02/05
- Re: [Qemu-devel] [PATCH 5/5] target-i386: fix kvm_default_features overwriting kvm_arch_get_supported_cpuid(), Eduardo Habkost, 2013/02/05
- Re: [Qemu-devel] [PATCH 5/5] target-i386: fix kvm_default_features overwriting kvm_arch_get_supported_cpuid(), Igor Mammedov, 2013/02/05
- Re: [Qemu-devel] [PATCH 5/5] target-i386: fix kvm_default_features overwriting kvm_arch_get_supported_cpuid(), Eduardo Habkost, 2013/02/05
- Re: [Qemu-devel] [PATCH 5/5] target-i386: fix kvm_default_features overwriting kvm_arch_get_supported_cpuid(), Igor Mammedov, 2013/02/06
- [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses,
Igor Mammedov <=
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Eduardo Habkost, 2013/02/07
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Igor Mammedov, 2013/02/08
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Andreas Färber, 2013/02/08
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Igor Mammedov, 2013/02/08
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Eduardo Habkost, 2013/02/08
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Eduardo Habkost, 2013/02/08
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Andreas Färber, 2013/02/08
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Eduardo Habkost, 2013/02/08
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Igor Mammedov, 2013/02/10
- Re: [Qemu-devel] [PATCH 3/5] target-i386: Slim conversion to X86CPU subclasses, Eduardo Habkost, 2013/02/12