From 04d104b61198615c259d1851684b2713213dcf99 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 22 Apr 2013 16:00:16 -0300 Subject: [PATCH 01/11] target-i386: Add ECX information to FeatureWordInfo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FEAT_7_0_EBX uses ECX as input, so we have to take that into account when reporting feature word values. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 9f2adad805..0f924696f9 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -152,8 +152,10 @@ static const char *cpuid_7_0_ebx_feature_name[] = { typedef struct FeatureWordInfo { const char **feat_names; - uint32_t cpuid_eax; /* Input EAX for CPUID */ - int cpuid_reg; /* R_* register constant */ + uint32_t cpuid_eax; /* Input EAX for CPUID */ + bool cpuid_needs_ecx; /* CPUID instruction uses ECX as input */ + uint32_t cpuid_ecx; /* Input ECX value for CPUID */ + int cpuid_reg; /* output register (R_* constant) */ } FeatureWordInfo; static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { @@ -187,7 +189,9 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, [FEAT_7_0_EBX] = { .feat_names = cpuid_7_0_ebx_feature_name, - .cpuid_eax = 7, .cpuid_reg = R_EBX, + .cpuid_eax = 7, + .cpuid_needs_ecx = true, .cpuid_ecx = 0, + .cpuid_reg = R_EBX, }, }; From bd87d2a2c05569a28768648b069cbc24c40f4fb8 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 22 Apr 2013 16:00:18 -0300 Subject: [PATCH 02/11] target-i386: Use FeatureWord loop on filter_features_for_kvm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of open-coding the filtering code for each feature word, change the existing code to use the feature_word_info array, that has exactly the same CPUID eax/ecx/register values for each feature word. Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Andreas Färber --- target-i386/cpu.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 0f924696f9..a39b36422f 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1651,24 +1651,14 @@ static void filter_features_for_kvm(X86CPU *cpu) { CPUX86State *env = &cpu->env; KVMState *s = kvm_state; + FeatureWord w; - env->features[FEAT_1_EDX] &= - kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX); - env->features[FEAT_1_ECX] &= - kvm_arch_get_supported_cpuid(s, 1, 0, R_ECX); - env->features[FEAT_8000_0001_EDX] &= - kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_EDX); - env->features[FEAT_8000_0001_ECX] &= - kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX); - env->features[FEAT_SVM] &= - kvm_arch_get_supported_cpuid(s, 0x8000000A, 0, R_EDX); - env->features[FEAT_7_0_EBX] &= - kvm_arch_get_supported_cpuid(s, 7, 0, R_EBX); - env->features[FEAT_KVM] &= - kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX); - env->features[FEAT_C000_0001_EDX] &= - kvm_arch_get_supported_cpuid(s, 0xC0000001, 0, R_EDX); - + for (w = 0; w < FEATURE_WORDS; w++) { + FeatureWordInfo *wi = &feature_word_info[w]; + env->features[w] &= kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, + wi->cpuid_ecx, + wi->cpuid_reg); + } } #endif From 8e8aba5054c043027445c880fcb9dbc8f6a217f3 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 6 May 2013 13:20:07 -0300 Subject: [PATCH 03/11] target-i386: Add "feature-words" property to X86CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This property will be useful for libvirt, as libvirt already has logic based on low-level feature bits (not feature names), so it will be really easy to convert the current libvirt logic to something using the "feature-words" property. The property will have two main use cases: - Checking host capabilities, by checking the features of the "host" CPU model - Checking which features are enabled on each CPU model Example output: $ ./QMP/qmp --path=/tmp/m \ qom-get --path=/machine/icc-bridge/icc/child[0] \ --property=feature-words item[0].cpuid-register: EDX item[0].cpuid-input-eax: 2147483658 item[0].features: 0 item[1].cpuid-register: EAX item[1].cpuid-input-eax: 1073741825 item[1].features: 0 item[2].cpuid-register: EDX item[2].cpuid-input-eax: 3221225473 item[2].features: 0 item[3].cpuid-register: ECX item[3].cpuid-input-eax: 2147483649 item[3].features: 101 item[4].cpuid-register: EDX item[4].cpuid-input-eax: 2147483649 item[4].features: 563346425 item[5].cpuid-register: EBX item[5].cpuid-input-eax: 7 item[5].features: 0 item[5].cpuid-input-ecx: 0 item[6].cpuid-register: ECX item[6].cpuid-input-eax: 1 item[6].features: 2155880449 item[7].cpuid-register: EDX item[7].cpuid-input-eax: 1 item[7].features: 126614521 Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Andreas Färber --- Makefile.objs | 7 ++++- qapi-schema.json | 32 ++++++++++++++++++++++ target-i386/cpu.c | 70 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 96 insertions(+), 13 deletions(-) diff --git a/Makefile.objs b/Makefile.objs index fcb303a839..286ce069b2 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -79,10 +79,15 @@ common-obj-$(CONFIG_SMARTCARD_NSS) += $(libcacard-y) ###################################################################### # qapi -common-obj-y += qmp-marshal.o qapi-visit.o qapi-types.o +common-obj-y += qmp-marshal.o common-obj-y += qmp.o hmp.o endif +###################################################################### +# some qapi visitors are used by both system and user emulation: + +common-obj-y += qapi-visit.o qapi-types.o + ####################################################################### # Target-independent parts used in system and user emulation common-obj-y += qemu-log.o diff --git a/qapi-schema.json b/qapi-schema.json index 7797400666..199744a833 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3587,3 +3587,35 @@ ## {'command': 'query-command-line-options', 'data': { '*option': 'str' }, 'returns': ['CommandLineOptionInfo'] } + +## +# @X86CPURegister32 +# +# A X86 32-bit register +# +# Since: 1.5 +## +{ 'enum': 'X86CPURegister32', + 'data': [ 'EAX', 'EBX', 'ECX', 'EDX', 'ESP', 'EBP', 'ESI', 'EDI' ] } + +## +# @X86CPUFeatureWordInfo +# +# Information about a X86 CPU feature word +# +# @cpuid-input-eax: Input EAX value for CPUID instruction for that feature word +# +# @cpuid-input-ecx: #optional Input ECX value for CPUID instruction for that +# feature word +# +# @cpuid-register: Output register containing the feature bits +# +# @features: value of output register, containing the feature bits +# +# Since: 1.5 +## +{ 'type': 'X86CPUFeatureWordInfo', + 'data': { 'cpuid-input-eax': 'int', + '*cpuid-input-ecx': 'int', + 'cpuid-register': 'X86CPURegister32', + 'features': 'int' } } diff --git a/target-i386/cpu.c b/target-i386/cpu.c index a39b36422f..3857514bb2 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -30,6 +30,8 @@ #include "qemu/config-file.h" #include "qapi/qmp/qerror.h" +#include "qapi-types.h" +#include "qapi-visit.h" #include "qapi/visitor.h" #include "sysemu/arch_init.h" @@ -195,23 +197,34 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = { }, }; +typedef struct X86RegisterInfo32 { + /* Name of register */ + const char *name; + /* QAPI enum value register */ + X86CPURegister32 qapi_enum; +} X86RegisterInfo32; + +#define REGISTER(reg) \ + [R_##reg] = { .name = #reg, .qapi_enum = X86_C_P_U_REGISTER32_##reg } +X86RegisterInfo32 x86_reg_info_32[CPU_NB_REGS32] = { + REGISTER(EAX), + REGISTER(ECX), + REGISTER(EDX), + REGISTER(EBX), + REGISTER(ESP), + REGISTER(EBP), + REGISTER(ESI), + REGISTER(EDI), +}; +#undef REGISTER + + 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]; + return x86_reg_info_32[reg].name; } /* collects per-function cpuid data @@ -1405,6 +1418,36 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque, cpu->env.cpuid_apic_id = value; } +static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + X86CPU *cpu = X86_CPU(obj); + CPUX86State *env = &cpu->env; + FeatureWord w; + Error *err = NULL; + X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { }; + X86CPUFeatureWordInfoList list_entries[FEATURE_WORDS] = { }; + X86CPUFeatureWordInfoList *list = NULL; + + for (w = 0; w < FEATURE_WORDS; w++) { + FeatureWordInfo *wi = &feature_word_info[w]; + X86CPUFeatureWordInfo *qwi = &word_infos[w]; + qwi->cpuid_input_eax = wi->cpuid_eax; + qwi->has_cpuid_input_ecx = wi->cpuid_needs_ecx; + qwi->cpuid_input_ecx = wi->cpuid_ecx; + qwi->cpuid_register = x86_reg_info_32[wi->cpuid_reg].qapi_enum; + qwi->features = env->features[w]; + + /* List will be in reverse order, but order shouldn't matter */ + list_entries[w].next = list; + list_entries[w].value = &word_infos[w]; + list = &list_entries[w]; + } + + visit_type_X86CPUFeatureWordInfoList(v, &list, "feature-words", &err); + error_propagate(errp, err); +} + static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name) { x86_def_t *def; @@ -2396,6 +2439,9 @@ static void x86_cpu_initfn(Object *obj) object_property_add(obj, "apic-id", "int", x86_cpuid_get_apic_id, x86_cpuid_set_apic_id, NULL, NULL, NULL); + object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo", + x86_cpu_get_feature_words, + NULL, NULL, NULL, NULL); env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index); From 034acf4a581b03fc10cba772f731ae521e00fcd8 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 6 May 2013 13:20:08 -0300 Subject: [PATCH 04/11] target-i386: Introduce X86CPU::filtered_features field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This field will contain the feature bits that were filtered out because of missing host support. Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Andreas Färber --- target-i386/cpu-qom.h | 3 +++ target-i386/cpu.c | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h index f890f1c912..849cedf94c 100644 --- a/target-i386/cpu-qom.h +++ b/target-i386/cpu-qom.h @@ -65,6 +65,9 @@ typedef struct X86CPU { /*< public >*/ CPUX86State env; + + /* Features that were filtered out because of missing host capabilities */ + uint32_t filtered_features[FEATURE_WORDS]; } X86CPU; static inline X86CPU *x86_env_get_cpu(CPUX86State *env) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 3857514bb2..38793bc5c8 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1698,9 +1698,12 @@ static void filter_features_for_kvm(X86CPU *cpu) for (w = 0; w < FEATURE_WORDS; w++) { FeatureWordInfo *wi = &feature_word_info[w]; - env->features[w] &= kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, - wi->cpuid_ecx, - wi->cpuid_reg); + uint32_t host_feat = kvm_arch_get_supported_cpuid(s, wi->cpuid_eax, + wi->cpuid_ecx, + wi->cpuid_reg); + uint32_t requested_features = env->features[w]; + env->features[w] &= host_feat; + cpu->filtered_features[w] = requested_features & ~env->features[w]; } } #endif From 7e5292b553c9ec27e0816abdcb717f87aa6b6a8d Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Mon, 6 May 2013 13:20:09 -0300 Subject: [PATCH 05/11] target-i386: Add "filtered-features" property to X86CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This property will contain all the features that were removed from the CPU because they are not supported by the host. This way, libvirt or other management tools can emulate the check/enforce behavior by checking if filtered-properties is all zeroes, before starting the guest. Example output where some features were missing: $ qemu-system-x86_64 -enable-kvm -cpu Haswell,check -S \ -qmp unix:/tmp/m,server,nowait warning: host doesn't support requested feature: CPUID.01H:ECX.fma [bit 12] warning: host doesn't support requested feature: CPUID.01H:ECX.movbe [bit 22] warning: host doesn't support requested feature: CPUID.01H:ECX.tsc-deadline [bit 24] warning: host doesn't support requested feature: CPUID.01H:ECX.xsave [bit 26] warning: host doesn't support requested feature: CPUID.01H:ECX.avx [bit 28] warning: host doesn't support requested feature: CPUID.07H:EBX.fsgsbase [bit 0] warning: host doesn't support requested feature: CPUID.07H:EBX.bmi1 [bit 3] warning: host doesn't support requested feature: CPUID.07H:EBX.hle [bit 4] warning: host doesn't support requested feature: CPUID.07H:EBX.avx2 [bit 5] warning: host doesn't support requested feature: CPUID.07H:EBX.smep [bit 7] warning: host doesn't support requested feature: CPUID.07H:EBX.bmi2 [bit 8] warning: host doesn't support requested feature: CPUID.07H:EBX.erms [bit 9] warning: host doesn't support requested feature: CPUID.07H:EBX.invpcid [bit 10] warning: host doesn't support requested feature: CPUID.07H:EBX.rtm [bit 11] [...] $ ./QMP/qmp --path=/tmp/m \ qom-get --path=/machine/icc-bridge/icc/child[0] \ --property=filtered-features item[0].cpuid-register: EDX item[0].cpuid-input-eax: 2147483658 item[0].features: 0 item[1].cpuid-register: EAX item[1].cpuid-input-eax: 1073741825 item[1].features: 0 item[2].cpuid-register: EDX item[2].cpuid-input-eax: 3221225473 item[2].features: 0 item[3].cpuid-register: ECX item[3].cpuid-input-eax: 2147483649 item[3].features: 0 item[4].cpuid-register: EDX item[4].cpuid-input-eax: 2147483649 item[4].features: 0 item[5].cpuid-register: EBX item[5].cpuid-input-eax: 7 item[5].features: 4025 item[5].cpuid-input-ecx: 0 item[6].cpuid-register: ECX item[6].cpuid-input-eax: 1 item[6].features: 356519936 item[7].cpuid-register: EDX item[7].cpuid-input-eax: 1 item[7].features: 0 Example output when no feature is missing: $ qemu-system-x86_64 -enable-kvm -cpu Nehalem,enforce -S \ -qmp unix:/tmp/m,server,nowait [...] $ ./QMP/qmp --path=/tmp/m \ qom-get --path=/machine/icc-bridge/icc/child[0] \ --property=filtered-features item[0].cpuid-register: EDX item[0].cpuid-input-eax: 2147483658 item[0].features: 0 item[1].cpuid-register: EAX item[1].cpuid-input-eax: 1073741825 item[1].features: 0 item[2].cpuid-register: EDX item[2].cpuid-input-eax: 3221225473 item[2].features: 0 item[3].cpuid-register: ECX item[3].cpuid-input-eax: 2147483649 item[3].features: 0 item[4].cpuid-register: EDX item[4].cpuid-input-eax: 2147483649 item[4].features: 0 item[5].cpuid-register: EBX item[5].cpuid-input-eax: 7 item[5].features: 0 item[5].cpuid-input-ecx: 0 item[6].cpuid-register: ECX item[6].cpuid-input-eax: 1 item[6].features: 0 item[7].cpuid-register: EDX item[7].cpuid-input-eax: 1 item[7].features: 0 Signed-off-by: Eduardo Habkost Reviewed-by: Eric Blake Signed-off-by: Andreas Färber --- target-i386/cpu.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 38793bc5c8..eb1825b53d 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1418,11 +1418,11 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque, cpu->env.cpuid_apic_id = value; } +/* Generic getter for "feature-words" and "filtered-features" properties */ static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque, const char *name, Error **errp) { - X86CPU *cpu = X86_CPU(obj); - CPUX86State *env = &cpu->env; + uint32_t *array = (uint32_t *)opaque; FeatureWord w; Error *err = NULL; X86CPUFeatureWordInfo word_infos[FEATURE_WORDS] = { }; @@ -1436,7 +1436,7 @@ static void x86_cpu_get_feature_words(Object *obj, Visitor *v, void *opaque, qwi->has_cpuid_input_ecx = wi->cpuid_needs_ecx; qwi->cpuid_input_ecx = wi->cpuid_ecx; qwi->cpuid_register = x86_reg_info_32[wi->cpuid_reg].qapi_enum; - qwi->features = env->features[w]; + qwi->features = array[w]; /* List will be in reverse order, but order shouldn't matter */ list_entries[w].next = list; @@ -2444,7 +2444,10 @@ static void x86_cpu_initfn(Object *obj) x86_cpuid_set_apic_id, NULL, NULL, NULL); object_property_add(obj, "feature-words", "X86CPUFeatureWordInfo", x86_cpu_get_feature_words, - NULL, NULL, NULL, NULL); + NULL, NULL, (void *)env->features, NULL); + object_property_add(obj, "filtered-features", "X86CPUFeatureWordInfo", + x86_cpu_get_feature_words, + NULL, NULL, (void *)cpu->filtered_features, NULL); env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index); From b1fe9bcbceb6fb9d800f735da37aa79ac4552c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 1 May 2013 16:10:24 +0200 Subject: [PATCH 06/11] qdev: Let qdev_prop_parse() pass through Error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move error reporting to callers. Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/core/qdev-properties.c | 25 +++++++++++-------------- hw/core/qdev.c | 7 ++++++- include/hw/qdev-properties.h | 5 +++-- qdev-monitor.c | 6 +++++- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index ca1739ec84..716ba19a3c 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -986,25 +986,18 @@ void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, } } -int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) +void qdev_prop_parse(DeviceState *dev, const char *name, const char *value, + Error **errp) { char *legacy_name; - Error *err = NULL; legacy_name = g_strdup_printf("legacy-%s", name); if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { - object_property_parse(OBJECT(dev), value, legacy_name, &err); + object_property_parse(OBJECT(dev), value, legacy_name, errp); } else { - object_property_parse(OBJECT(dev), value, name, &err); + object_property_parse(OBJECT(dev), value, name, errp); } g_free(legacy_name); - - if (err) { - qerror_report_err(err); - error_free(err); - return -1; - } - return 0; } void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) @@ -1106,18 +1099,22 @@ void qdev_prop_register_global_list(GlobalProperty *props) } } -void qdev_prop_set_globals(DeviceState *dev) +void qdev_prop_set_globals(DeviceState *dev, Error **errp) { ObjectClass *class = object_get_class(OBJECT(dev)); do { GlobalProperty *prop; QTAILQ_FOREACH(prop, &global_props, next) { + Error *err = NULL; + if (strcmp(object_class_get_name(class), prop->driver) != 0) { continue; } - if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { - exit(1); + qdev_prop_parse(dev, prop->property, prop->value, &err); + if (err != NULL) { + error_propagate(errp, err); + return; } } class = object_class_get_parent(class); diff --git a/hw/core/qdev.c b/hw/core/qdev.c index 069ac9034c..6985ad870c 100644 --- a/hw/core/qdev.c +++ b/hw/core/qdev.c @@ -752,7 +752,12 @@ static void device_initfn(Object *obj) } class = object_class_get_parent(class); } while (class != object_class_by_name(TYPE_DEVICE)); - qdev_prop_set_globals(dev); + qdev_prop_set_globals(dev, &err); + if (err != NULL) { + qerror_report_err(err); + error_free(err); + exit(1); + } object_property_add_link(OBJECT(dev), "parent_bus", TYPE_BUS, (Object **)&dev->parent_bus, &err); diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 25dd1bb39a..38469d45a7 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -148,7 +148,8 @@ extern PropertyInfo qdev_prop_arraylen; /* Set properties between creation and init. */ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop); -int qdev_prop_parse(DeviceState *dev, const char *name, const char *value); +void qdev_prop_parse(DeviceState *dev, const char *name, const char *value, + Error **errp); void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value); void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value); void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value); @@ -167,7 +168,7 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); void qdev_prop_register_global(GlobalProperty *prop); void qdev_prop_register_global_list(GlobalProperty *props); -void qdev_prop_set_globals(DeviceState *dev); +void qdev_prop_set_globals(DeviceState *dev, Error **errp); void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, Property *prop, const char *value); diff --git a/qdev-monitor.c b/qdev-monitor.c index 2cb5600d63..e54dbc2c5d 100644 --- a/qdev-monitor.c +++ b/qdev-monitor.c @@ -105,13 +105,17 @@ static void qdev_print_devinfo(ObjectClass *klass, void *opaque) static int set_property(const char *name, const char *value, void *opaque) { DeviceState *dev = opaque; + Error *err = NULL; if (strcmp(name, "driver") == 0) return 0; if (strcmp(name, "bus") == 0) return 0; - if (qdev_prop_parse(dev, name, value) == -1) { + qdev_prop_parse(dev, name, value, &err); + if (err != NULL) { + qerror_report_err(err); + error_free(err); return -1; } return 0; From 868d378bb087c6003bfa0e431aec0e5871a90ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 1 May 2013 16:03:19 +0200 Subject: [PATCH 07/11] qdev: Introduce qdev_prop_set_globals_for_type() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse it in qdev_prop_set_globals(). Reviewed-by: Eduardo Habkost [AF: Renamed from qdev_prop_set_custom_globals()] Signed-off-by: Andreas Färber --- hw/core/qdev-properties.c | 36 +++++++++++++++++++++++++----------- include/hw/qdev-properties.h | 2 ++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index 716ba19a3c..3a324fb0c3 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -1099,23 +1099,37 @@ void qdev_prop_register_global_list(GlobalProperty *props) } } +void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, + Error **errp) +{ + GlobalProperty *prop; + + QTAILQ_FOREACH(prop, &global_props, next) { + Error *err = NULL; + + if (strcmp(typename, prop->driver) != 0) { + continue; + } + qdev_prop_parse(dev, prop->property, prop->value, &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + } +} + void qdev_prop_set_globals(DeviceState *dev, Error **errp) { ObjectClass *class = object_get_class(OBJECT(dev)); do { - GlobalProperty *prop; - QTAILQ_FOREACH(prop, &global_props, next) { - Error *err = NULL; + Error *err = NULL; - if (strcmp(object_class_get_name(class), prop->driver) != 0) { - continue; - } - qdev_prop_parse(dev, prop->property, prop->value, &err); - if (err != NULL) { - error_propagate(errp, err); - return; - } + qdev_prop_set_globals_for_type(dev, object_class_get_name(class), + &err); + if (err != NULL) { + error_propagate(errp, err); + return; } class = object_class_get_parent(class); } while (class); diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h index 38469d45a7..39448b716c 100644 --- a/include/hw/qdev-properties.h +++ b/include/hw/qdev-properties.h @@ -169,6 +169,8 @@ void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value); void qdev_prop_register_global(GlobalProperty *prop); void qdev_prop_register_global_list(GlobalProperty *props); void qdev_prop_set_globals(DeviceState *dev, Error **errp); +void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename, + Error **errp); void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, Property *prop, const char *value); From ba2bc7a42e7c7b343f996967484ce3a1543cfebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 1 May 2013 17:05:47 +0200 Subject: [PATCH 08/11] target-i386: Emulate X86CPU subclasses for global properties MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After initializing the object from its x86_def_t and before setting any additional -cpu arguments, set any global properties for the designated subclass -{i386,x86_64}-cpu. Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index eb1825b53d..b43847835b 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -1751,6 +1751,7 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge, CPUX86State *env; gchar **model_pieces; char *name, *features; + char *typename; Error *error = NULL; model_pieces = g_strsplit(cpu_model, ",", 2); @@ -1778,6 +1779,14 @@ X86CPU *cpu_x86_create(const char *cpu_model, DeviceState *icc_bridge, goto out; } + /* Emulate per-model subclasses for global properties */ + typename = 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; From b2a856d99281f2fee60a4313d204205bcd2c4269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Wed, 1 May 2013 17:30:51 +0200 Subject: [PATCH 09/11] target-i386: Change CPUID model of 486 to 8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes the model number of 486 to 8 (DX4) which matches the feature set presented, and actually has the CPUID instruction. This adds a compatibility property, to keep model=0 on pc-*-1.4 and older. Signed-off-by: H. Peter Anvin [AF: Add compat_props entry] Tested-by: Eduardo Habkost Reviewed-by: Eduardo Habkost Signed-off-by: Andreas Färber --- include/hw/i386/pc.h | 4 ++++ target-i386/cpu.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index 41869e56e9..417afe4ef0 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -242,6 +242,10 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t); .driver = "pc-sysfw",\ .property = "rom_only",\ .value = stringify(0),\ + },{\ + .driver = "486-" TYPE_X86_CPU,\ + .property = "model",\ + .value = stringify(0),\ } #endif diff --git a/target-i386/cpu.c b/target-i386/cpu.c index b43847835b..8e21c94d82 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -588,7 +588,7 @@ static x86_def_t builtin_x86_defs[] = { .level = 1, .vendor = CPUID_VENDOR_INTEL, .family = 4, - .model = 0, + .model = 8, .stepping = 0, .features[FEAT_1_EDX] = I486_FEATURES, From 0668af542f99b7bb1d95539829b27d5a1bcecde4 Mon Sep 17 00:00:00 2001 From: Eduardo Habkost Date: Thu, 25 Apr 2013 15:43:00 -0300 Subject: [PATCH 10/11] target-i386: Introduce generic CPUID feature compat function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce x86_cpu_compat_set_features(), that can be used to set/unset feature bits on specific CPU models for machine-type compatibility. Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- target-i386/cpu.c | 26 ++++++++++++++++++++++++++ target-i386/cpu.h | 4 ++++ 2 files changed, 30 insertions(+) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 8e21c94d82..8198a1b472 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -971,6 +971,32 @@ static x86_def_t builtin_x86_defs[] = { }, }; +/** + * x86_cpu_compat_set_features: + * @cpu_model: CPU model name to be changed. If NULL, all CPU models are changed + * @w: Identifies the feature word to be changed. + * @feat_add: Feature bits to be added to feature word + * @feat_remove: Feature bits to be removed from feature word + * + * Change CPU model feature bits for compatibility. + * + * This function may be used by machine-type compatibility functions + * to enable or disable feature bits on specific CPU models. + */ +void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w, + uint32_t feat_add, uint32_t feat_remove) +{ + x86_def_t *def; + int i; + for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) { + def = &builtin_x86_defs[i]; + if (!cpu_model || !strcmp(cpu_model, def->name)) { + def->features[w] |= feat_add; + def->features[w] &= ~feat_remove; + } + } +} + #ifdef CONFIG_KVM static int cpu_x86_fill_model_id(char *str) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 3e2e9f6b72..058c57fc19 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -1255,6 +1255,10 @@ void cpu_report_tpr_access(CPUX86State *env, TPRAccess access); void disable_kvm_pv_eoi(void); +void x86_cpu_compat_set_features(const char *cpu_model, FeatureWord w, + uint32_t feat_add, uint32_t feat_remove); + + /* Return name of 32-bit register, from a R_* constant */ const char *get_register_name_32(unsigned int reg); From 4458c23672904fa131e69897007eeb7c953be7e5 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 25 Apr 2013 15:43:04 -0300 Subject: [PATCH 11/11] target-i386: n270 can MOVBE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Atom core (cpu name "n270" in QEMU speak) supports MOVBE. This is needed when booting 3.8 and later linux kernels built with the MATOM target because we require MOVBE in order to boot properly now. Signed-off-by: Borislav Petkov [ehabkost: added compat code to disable MOVBE on pc-*-1.4 and older] Signed-off-by: Eduardo Habkost Signed-off-by: Andreas Färber --- hw/i386/pc_piix.c | 1 + hw/i386/pc_q35.c | 1 + target-i386/cpu.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index fe52e5f94b..f7c80ad0a5 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -250,6 +250,7 @@ static void pc_init_pci_1_4(QEMUMachineInitArgs *args) { pc_sysfw_flash_vs_rom_bug_compatible = true; has_pvpanic = false; + x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); pc_init_pci(args); } diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 52511e2b69..4160e2ba37 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -212,6 +212,7 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args) { pc_sysfw_flash_vs_rom_bug_compatible = true; has_pvpanic = false; + x86_cpu_compat_set_features("n270", FEAT_1_ECX, 0, CPUID_EXT_MOVBE); pc_q35_init(args); } diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 8198a1b472..1a501d9d33 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -657,7 +657,8 @@ static x86_def_t builtin_x86_defs[] = { /* Some CPUs got no CPUID_SEP */ .features[FEAT_1_ECX] = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR | CPUID_EXT_SSSE3 | - CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR, + CPUID_EXT_DSCPL | CPUID_EXT_EST | CPUID_EXT_TM2 | CPUID_EXT_XTPR | + CPUID_EXT_MOVBE, .features[FEAT_8000_0001_EDX] = (PPRO_FEATURES & CPUID_EXT2_AMD_ALIASES) | CPUID_EXT2_NX,