From mboxrd@z Thu Jan 1 00:00:00 1970 From: Eduardo Habkost Subject: [qom-cpu PATCH 7/7 v9] target-i386: CPU model subclasses Date: Mon, 10 Feb 2014 08:21:30 -0200 Message-ID: <20140210102130.GP24353@otherpad.lan.raisama.net> References: <1391111339-6958-1-git-send-email-ehabkost@redhat.com> <1391111339-6958-8-git-send-email-ehabkost@redhat.com> <20140131181338.GB28427@otherpad.lan.raisama.net> <52F81C09.6070504@suse.de> <20140210081958.GN24353@otherpad.lan.raisama.net> <20140210082617.GO24353@otherpad.lan.raisama.net> Mime-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: QUOTED-PRINTABLE Cc: kvm@vger.kernel.org, libvir-list@redhat.com, qemu-devel@nongnu.org, Paolo Bonzini , Igor Mammedov , Jiri Denemark To: Andreas =?iso-8859-1?Q?F=E4rber?= Return-path: Received: from mx1.redhat.com ([209.132.183.28]:16298 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751725AbaBJKVg (ORCPT ); Mon, 10 Feb 2014 05:21:36 -0500 Content-Disposition: inline In-Reply-To: <20140210082617.GO24353@otherpad.lan.raisama.net> Sender: kvm-owner@vger.kernel.org List-ID: Register separate QOM classes for each x86 CPU model. This will allow management code to more easily probe what each CPU mode= l provides, by simply creating objects using the appropriate class name, without having to restart QEMU. This also allows us to eliminate the qdev_prop_set_globals_for_type() hack to set CPU-model-specific global properties. Instead of creating separate class_init functions for each class, I jus= t used class_data to store a pointer to the X86CPUDefinition struct for each CPU model. This should make the patch shorter and easier to review= =2E Later we can gradually convert each X86CPUDefinition field to lists of per-class property defaults. Written based on the ideas from the patch "[RFC v5] target-i386: Slim conversion to X86CPU subclasses + KVM subclasses" written by Andreas =46=E4rber , Igor Mammedov . The "host" CPU model is special, as the feature flags depend on KVM being initialized. So it has its own class_init and instance_init function, and feature flags are set on instance_init instead of class_init. Signed-off-by: Andreas F=E4rber Signed-off-by: Igor Mammedov Signed-off-by: Eduardo Habkost --- This patch is similar to the one sent by Andrea and then later resubmitted by Igor as "[RFC v5] target-i386: Slim conversion to X86CPU subclasses + KVM subclasses", as it doesn't create one new class_init function for each subclass. Main differences v5 -> v6 are: * Code was written from scratch (instead of using the previous patches as base) * I didn't mean to rewrite it entirely, but when doing additional simplification of the CPU init logic on other patches, I ended up rewriting it. * I chose to keep the Signed-off-by lines because I built upon Andreas's and Igor's ideas. Is that OK? * No KVM-specific subclasses, to keep things simpler. * No embedding of X86CPUDefinition (x86_def_t) inside the class struct= , instead keeping a pointer to the existing X86CPUDefinition struct. * The "host" class is registered on cpu.c, but the CPUID data is filled on instance_init instead of class_init (because KVM has to be initialized already). * kvm_required field introduced to make sure the "host" class can't be used without KVM. Changes v6 -> v7: * Rebase Changes v7 -> v8: * Removed CPU listing code (will be sent as a separate patch) * Kept x86_cpudef_setup() (will be addressed in a separate patch) Changes v8 -> v9: * Remove model_desc field from X86CPUClass (it is not necessary yet) --- target-i386/cpu-qom.h | 10 +++ target-i386/cpu.c | 193 +++++++++++++++++++++++++++++++-----------= -------- 2 files changed, 131 insertions(+), 72 deletions(-) diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index 722f11a..00ad5a4 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -37,6 +37,9 @@ #define X86_CPU_GET_CLASS(obj) \ OBJECT_GET_CLASS(X86CPUClass, (obj), TYPE_X86_CPU) =20 + +typedef struct X86CPUDefinition X86CPUDefinition; + /** * X86CPUClass: * @parent_realize: The parent class' realize handler. @@ -49,6 +52,13 @@ typedef struct X86CPUClass { CPUClass parent_class; /*< public >*/ =20 + /* CPU model definition + * Should be eventually replaced by subclass-specific property def= aults + */ + X86CPUDefinition *cpu_def; + /* CPU model requires KVM to be enabled */ + bool kvm_required; + DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); } X86CPUClass; diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 5a530b5..0b6be20 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -484,7 +484,10 @@ static void add_flagname_to_bitmaps(const char *fl= agname, } } =20 -typedef struct X86CPUDefinition { +/* CPU model definition data that was not converted to QOM per-subclas= s + * property defaults yet. + */ +struct X86CPUDefinition { const char *name; uint32_t level; uint32_t xlevel; @@ -497,7 +500,7 @@ typedef struct X86CPUDefinition { FeatureWordArray features; char model_id[48]; bool cache_info_passthrough; -} X86CPUDefinition; +}; =20 #define I486_FEATURES (CPUID_FP87 | CPUID_VME | CPUID_PSE) #define PENTIUM_FEATURES (I486_FEATURES | CPUID_DE | CPUID_TSC | \ @@ -547,8 +550,29 @@ typedef struct X86CPUDefinition { CPUID_7_0_EBX_ERMS, CPUID_7_0_EBX_INVPCID, CPUID_7_0_EBX_RTM= , CPUID_7_0_EBX_RDSEED */ =20 -/* built-in CPU model definitions +/* CPU class name definitions: */ + +#define X86_CPU_CLASS_SUFFIX "-" TYPE_X86_CPU +#define CPU_CLASS_NAME(name) (name X86_CPU_CLASS_SUFFIX) + +/* Return class name for a given CPU model name + * Caller is responsible for freeing the returned string. */ +static char *x86_cpu_class_name(const char *model_name) +{ + return g_strdup_printf(CPU_CLASS_NAME("%s"), model_name); +} + +/* Return X86CPUClass for a CPU model name */ +static X86CPUClass *x86_cpu_class_by_name(const char *name) +{ + X86CPUClass *cc; + char *class_name =3D x86_cpu_class_name(name); + cc =3D X86_CPU_CLASS(object_class_by_name(class_name)); + g_free(class_name); + return cc; +} + static X86CPUDefinition builtin_x86_defs[] =3D { { .name =3D "qemu64", @@ -1093,6 +1117,33 @@ static X86CPUDefinition builtin_x86_defs[] =3D { }, }; =20 +static void x86_cpu_class_init_cpudef(ObjectClass *oc, void *data) +{ + X86CPUDefinition *cpudef =3D data; + X86CPUClass *xcc =3D X86_CPU_CLASS(oc); + xcc->cpu_def =3D cpudef; +} + +static void x86_register_cpudef_classes(void) +{ + int i; + for (i =3D 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { + X86CPUDefinition *def =3D &builtin_x86_defs[i]; + char *class_name =3D x86_cpu_class_name(def->name); + TypeInfo ti =3D { + .name =3D class_name, + .parent =3D TYPE_X86_CPU, + .instance_size =3D sizeof(X86CPU), + .abstract =3D false, + .class_size =3D sizeof(X86CPUClass), + .class_init =3D x86_cpu_class_init_cpudef, + .class_data =3D def, + }; + type_register(&ti); + g_free(class_name); + } +} + /** * x86_cpu_compat_set_features: * @cpu_model: CPU model name to be changed. If NULL, all CPU models a= re changed @@ -1134,44 +1185,70 @@ static int cpu_x86_fill_model_id(char *str) return 0; } =20 -/* Fill a X86CPUDefinition struct with information about the host CPU,= and - * the CPU features supported by the host hardware + host kernel +static X86CPUDefinition host_cpudef; + +/* class_init for the "host" CPU model * - * This function may be called only if KVM is enabled. + * This function may be called before KVM is initialized. */ -static void kvm_cpu_fill_host(X86CPUDefinition *x86_cpu_def) +static void x86_cpu_class_init_host(ObjectClass *oc, void *data) { - KVMState *s =3D kvm_state; + X86CPUClass *xcc =3D X86_CPU_CLASS(oc); uint32_t eax =3D 0, ebx =3D 0, ecx =3D 0, edx =3D 0; =20 - assert(kvm_enabled()); + xcc->kvm_required =3D true; =20 - x86_cpu_def->name =3D "host"; - x86_cpu_def->cache_info_passthrough =3D true; host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx); - x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx); + x86_cpu_vendor_words2str(host_cpudef.vendor, ebx, edx, ecx); =20 host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx); - x86_cpu_def->family =3D ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF)= ; - x86_cpu_def->model =3D ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 1= 2); - x86_cpu_def->stepping =3D eax & 0x0F; + host_cpudef.family =3D ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF); + host_cpudef.model =3D ((eax >> 4) & 0x0F) | ((eax & 0xF0000) >> 12= ); + host_cpudef.stepping =3D eax & 0x0F; + + cpu_x86_fill_model_id(host_cpudef.model_id); =20 - x86_cpu_def->level =3D kvm_arch_get_supported_cpuid(s, 0x0, 0, R_E= AX); - x86_cpu_def->xlevel =3D kvm_arch_get_supported_cpuid(s, 0x80000000= , 0, R_EAX); - x86_cpu_def->xlevel2 =3D - kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX); + xcc->cpu_def =3D &host_cpudef; + host_cpudef.cache_info_passthrough =3D true; =20 - cpu_x86_fill_model_id(x86_cpu_def->model_id); + /* level, xlevel, xlevel2, and the feature words are initialized o= n + * instance_init, because they require KVM to be initialized. + */ +} + +static void x86_cpu_instance_init_host(Object *obj) +{ + X86CPU *cpu =3D X86_CPU(obj); + CPUX86State *env =3D &cpu->env; + KVMState *s =3D kvm_state; + + assert(kvm_enabled()); + + env->cpuid_level =3D kvm_arch_get_supported_cpuid(s, 0x0, 0, R_EAX= ); + env->cpuid_xlevel =3D kvm_arch_get_supported_cpuid(s, 0x80000000, = 0, R_EAX); + env->cpuid_xlevel2 =3D kvm_arch_get_supported_cpuid(s, 0xC0000000,= 0, R_EAX); =20 FeatureWord w; for (w =3D 0; w < FEATURE_WORDS; w++) { FeatureWordInfo *wi =3D &feature_word_info[w]; - x86_cpu_def->features[w] =3D + env->features[w] =3D kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, wi->cpuid_e= cx, wi->cpuid_reg); } + object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abort); } =20 + +static const TypeInfo x86_cpu_host_type_info =3D { + .name =3D CPU_CLASS_NAME("host"), + .parent =3D TYPE_X86_CPU, + .instance_size =3D sizeof(X86CPU), + .instance_init =3D x86_cpu_instance_init_host, + .abstract =3D false, + .class_size =3D sizeof(X86CPUClass), + .class_init =3D x86_cpu_class_init_host, +}; + static int unavailable_host_feature(FeatureWordInfo *f, uint32_t mask) { int i; @@ -1582,32 +1659,6 @@ static PropertyInfo qdev_prop_spinlocks =3D { .set =3D x86_set_hv_spinlocks, }; =20 -static int cpu_x86_find_by_name(X86CPU *cpu, X86CPUDefinition *x86_cpu= _def, - const char *name) -{ - X86CPUDefinition *def; - int i; - - if (name =3D=3D NULL) { - return -1; - } - if (kvm_enabled() && strcmp(name, "host") =3D=3D 0) { - kvm_cpu_fill_host(x86_cpu_def); - object_property_set_bool(OBJECT(cpu), true, "pmu", &error_abor= t); - return 0; - } - - for (i =3D 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { - def =3D &builtin_x86_defs[i]; - if (strcmp(name, def->name) =3D=3D 0) { - memcpy(x86_cpu_def, def, sizeof(*def)); - return 0; - } - } - - return -1; -} - /* Convert all '_' in a feature string option name to '-', to make fea= ture * name conform to QOM property naming rule, which uses '-' instead of= '_'. */ @@ -1817,19 +1868,11 @@ static void filter_features_for_kvm(X86CPU *cpu= ) } } =20 -/* Load CPU definition for a given CPU model name +/* Load data from X86CPUDefinition */ -static void x86_cpu_load_def(X86CPU *cpu, const char *name, Error **er= rp) +static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error= **errp) { CPUX86State *env =3D &cpu->env; - X86CPUDefinition def1, *def =3D &def1; - - memset(def, 0, sizeof(*def)); - - if (cpu_x86_find_by_name(cpu, def, name) < 0) { - error_setg(errp, "Unable to find CPU definition: %s", name); - return; - } =20 object_property_set_int(OBJECT(cpu), def->level, "level", errp); object_property_set_int(OBJECT(cpu), def->family, "family", errp); @@ -1881,7 +1924,6 @@ X86CPU *cpu_x86_create(const char *cpu_model, Dev= iceState *icc_bridge, X86CPU *cpu =3D NULL; gchar **model_pieces; char *name, *features; - char *typename; Error *error =3D NULL; =20 model_pieces =3D g_strsplit(cpu_model, ",", 2); @@ -1892,12 +1934,19 @@ X86CPU *cpu_x86_create(const char *cpu_model, D= eviceState *icc_bridge, name =3D model_pieces[0]; features =3D model_pieces[1]; =20 - cpu =3D X86_CPU(object_new(TYPE_X86_CPU)); - x86_cpu_load_def(cpu, name, &error); - if (error) { + X86CPUClass *cc =3D x86_cpu_class_by_name(name); + if (!cc) { + error_setg(&error, "Unable to find CPU definition: %s", name); + goto out; + } + + if (cc->kvm_required && !kvm_enabled()) { + error_setg(&error, "CPU model '%s' requires KVM", name); goto out; } =20 + cpu =3D X86_CPU(object_new(object_class_get_name(OBJECT_CLASS(cc))= )); + #ifndef CONFIG_USER_ONLY if (icc_bridge =3D=3D NULL) { error_setg(&error, "Invalid icc-bridge value"); @@ -1907,14 +1956,6 @@ X86CPU *cpu_x86_create(const char *cpu_model, De= viceState *icc_bridge, object_unref(OBJECT(cpu)); #endif =20 - /* Emulate per-model subclasses for global properties */ - typename =3D g_strdup_printf("%s-" TYPE_X86_CPU, name); - qdev_prop_set_globals_for_type(DEVICE(cpu), typename, &error); - g_free(typename); - if (error) { - goto out; - } - cpu_x86_parse_featurestr(cpu, features, &error); if (error) { goto out; @@ -1923,8 +1964,10 @@ X86CPU *cpu_x86_create(const char *cpu_model, De= viceState *icc_bridge, out: if (error !=3D NULL) { error_propagate(errp, error); - object_unref(OBJECT(cpu)); - cpu =3D NULL; + if (cpu) { + object_unref(OBJECT(cpu)); + cpu =3D NULL; + } } g_strfreev(model_pieces); return cpu; @@ -2615,6 +2658,7 @@ static void x86_cpu_initfn(Object *obj) { CPUState *cs =3D CPU(obj); X86CPU *cpu =3D X86_CPU(obj); + X86CPUClass *xcc =3D X86_CPU_GET_CLASS(cpu); CPUX86State *env =3D &cpu->env; static int inited; =20 @@ -2666,6 +2710,9 @@ static void x86_cpu_initfn(Object *obj) cpu_set_debug_excp_handler(breakpoint_handler); #endif } + + X86CPUDefinition *def =3D xcc->cpu_def; + x86_cpu_load_def(cpu, def, &error_abort); } =20 static int64_t x86_cpu_get_arch_id(CPUState *cs) @@ -2763,7 +2810,7 @@ static const TypeInfo x86_cpu_type_info =3D { .parent =3D TYPE_CPU, .instance_size =3D sizeof(X86CPU), .instance_init =3D x86_cpu_initfn, - .abstract =3D false, + .abstract =3D true, .class_size =3D sizeof(X86CPUClass), .class_init =3D x86_cpu_common_class_init, }; @@ -2771,6 +2818,8 @@ static const TypeInfo x86_cpu_type_info =3D { static void x86_cpu_register_types(void) { type_register_static(&x86_cpu_type_info); + x86_register_cpudef_classes(); + type_register_static(&x86_cpu_host_type_info); } =20 type_init(x86_cpu_register_types) --=20 1.8.5.3