From patchwork Mon Feb 11 16:35:11 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Igor Mammedov X-Patchwork-Id: 219657 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 778B62C02AA for ; Tue, 12 Feb 2013 04:38:43 +1100 (EST) Received: from localhost ([::1]:49712 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U4wQg-00058F-Id for incoming@patchwork.ozlabs.org; Mon, 11 Feb 2013 11:40:30 -0500 Received: from eggs.gnu.org ([208.118.235.92]:52781) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U4wPX-0004js-51 for qemu-devel@nongnu.org; Mon, 11 Feb 2013 11:39:21 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1U4wPP-0005Ra-Of for qemu-devel@nongnu.org; Mon, 11 Feb 2013 11:39:19 -0500 Received: from mx1.redhat.com ([209.132.183.28]:36745) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1U4wPP-0005RI-Ff for qemu-devel@nongnu.org; Mon, 11 Feb 2013 11:39:11 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id r1BGdArv018785 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 11 Feb 2013 11:39:10 -0500 Received: from dell-pet610-01.lab.eng.brq.redhat.com (dell-pet610-01.lab.eng.brq.redhat.com [10.34.42.20]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id r1BGctsw028773; Mon, 11 Feb 2013 11:39:09 -0500 From: Igor Mammedov To: qemu-devel@nongnu.org Date: Mon, 11 Feb 2013 17:35:11 +0100 Message-Id: <1360600511-25133-10-git-send-email-imammedo@redhat.com> In-Reply-To: <1360600511-25133-1-git-send-email-imammedo@redhat.com> References: <1360600511-25133-1-git-send-email-imammedo@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 3.x X-Received-From: 209.132.183.28 Cc: Don@cloudswitch.com, afaerber@suse.de, ehabkost@redhat.com Subject: [Qemu-devel] [PATCH 9/9] target-i386: set [+-]feature using static properties X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org * Define static properties for cpuid feature bits * property names of CPUID features are changed to have "f-" prefix, so that it would be easy to distinguish them from other properties. * Convert [+-]cpuid_features to a set(QDict) of key, value pairs, where +feat => (f-feat, on) -feat => (f-feat, off) [+-] unknown feat => (feat, on/off) - it's expected to be rejected by property setter later QDict is used as convinience sturcture to keep -foo semantic. Once all +-foo are parsed, collected features are applied to CPU instance. * Cleanup unused anymore: add_flagname_to_bitmaps(), lookup_feature(), altcmp(), sstrcmp(), * Rename lowlevel 'kvmclock' into 'f-kvmclock1' and introduce legacy composite property 'f-kvmclock' that sets both 'f-kvmclock1' and 'f-kvmclock2' feature bits to mantain legacy kvmclock behavior Signed-off-by: Igor Mammedov --- v4: - major patch reordering, rebasing on current qom-cpu-next - merged patches: "define static properties..." and "set [+-]feature..." - merge in "make 'f-kvmclock' compatible..." to aviod behavior breakage - use register name in feature macros, so that if we rename cpuid_* fields, it wouldn't involve mass rename in features array. - when converting feature names into property names, replace '_' with '-', Requested-By: Don Slutz , mgs-id: <5085D4AA.1060208@CloudSwitch.Com> v3: - new static properties after rebase: - add features "f-rdseed" & "f-adx" - add features added by c8acc380 - add features f-kvm_steal_tm and f-kvmclock_stable - ext4 features f-xstore, f-xstore-en, f-xcrypt, f-xcrypt-en, f-ace2, f-ace2-en, f-phe, f-phe-en, f-pmm, f-pmm-en - f-hypervisor set default to false as for the rest of features - define helper FEAT for declaring CPUID feature properties to make shorter lines (<80 characters) v2: - use X86CPU as a type to count of offset correctly, because env field isn't starting at CPUstate beginning, but located after it. --- target-i386/cpu.c | 348 +++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 242 insertions(+), 106 deletions(-) diff --git a/target-i386/cpu.c b/target-i386/cpu.c index fcfe8ec..2a5a5b5 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -656,6 +656,65 @@ PropertyInfo qdev_prop_enforce = { .defval = _defval \ } +static void x86_cpu_get_kvmclock(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + X86CPU *cpu = X86_CPU(obj); + bool value = cpu->env.cpuid_kvm_features; + value = (value & KVM_FEATURE_CLOCKSOURCE) && + (value & KVM_FEATURE_CLOCKSOURCE2); + visit_type_bool(v, &value, name, errp); +} + +static void x86_cpu_set_kvmclock(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + X86CPU *cpu = X86_CPU(obj); + bool value; + visit_type_bool(v, &value, name, errp); + if (value == true) { + cpu->env.cpuid_kvm_features |= KVM_FEATURE_CLOCKSOURCE | + KVM_FEATURE_CLOCKSOURCE2; + } else { + cpu->env.cpuid_kvm_features &= ~(KVM_FEATURE_CLOCKSOURCE | + KVM_FEATURE_CLOCKSOURCE2); + } +} + +PropertyInfo qdev_prop_kvmclock = { + .name = "boolean", + .get = x86_cpu_get_kvmclock, + .set = x86_cpu_set_kvmclock, +}; +#define DEFINE_PROP_KVMCLOCK(_n) { \ + .name = _n, \ + .info = &qdev_prop_kvmclock \ +} + +#define F_1_EDX(_name, _bit, _defval) \ + DEFINE_PROP_BIT(_name, X86CPU, env.cpuid_features, _bit, _defval) + +#define F_1_ECX(_name, _bit, _defval) \ + DEFINE_PROP_BIT(_name, X86CPU, env.cpuid_ext_features, _bit, _defval) + +#define F_8000_0001_EDX(_name, _bit, _defval) \ + DEFINE_PROP_BIT(_name, X86CPU, env.cpuid_ext2_features, _bit, _defval) + +#define F_8000_0001_ECX(_name, _bit, _defval) \ + DEFINE_PROP_BIT(_name, X86CPU, env.cpuid_ext3_features, _bit, _defval) + +#define F_C000_0001_EDX(_name, _bit, _defval) \ + DEFINE_PROP_BIT(_name, X86CPU, env.cpuid_ext4_features, _bit, _defval) + +#define F_KVM(_name, _bit, _defval) \ + DEFINE_PROP_BIT(_name, X86CPU, env.cpuid_kvm_features, _bit, _defval) + +#define F_SVM(_name, _bit, _defval) \ + DEFINE_PROP_BIT(_name, X86CPU, env.cpuid_svm_features, _bit, _defval) + +#define F_7_0_EBX(_name, _bit, _defval) \ + DEFINE_PROP_BIT(_name, X86CPU, env.cpuid_7_0_ebx_features, _bit, _defval) + static Property cpu_x86_properties[] = { DEFINE_PROP_FAMILY("family"), DEFINE_PROP_MODEL("model"), @@ -670,6 +729,156 @@ static Property cpu_x86_properties[] = { DEFINE_PROP_HV_VAPIC("hv-vapic", false), DEFINE_PROP_CHECK("check", false), DEFINE_PROP_ENFORCE("enforce", false), + F_1_EDX("f-fpu", 0, false), + F_1_EDX("f-vme", 1, false), + F_1_EDX("f-de", 2, false), + F_1_EDX("f-pse", 3, false), + F_1_EDX("f-tsc", 4, false), + F_1_EDX("f-msr", 5, false), + F_1_EDX("f-pae", 6, false), + F_1_EDX("f-mce", 7, false), + F_1_EDX("f-cx8", 8, false), + F_1_EDX("f-apic", 9, false), + F_1_EDX("f-sep", 11, false), + F_1_EDX("f-mtrr", 12, false), + F_1_EDX("f-pge", 13, false), + F_1_EDX("f-mca", 14, false), + F_1_EDX("f-cmov", 15, false), + F_1_EDX("f-pat", 16, false), + F_1_EDX("f-pse36", 17, false), + /* Intel psn */ + F_1_EDX("f-pn", 18, false), + /* Intel clfsh */ + F_1_EDX("f-clflush", 19, false), + /* Intel dts */ + F_1_EDX("f-ds", 21, false), + F_1_EDX("f-acpi", 22, false), + F_1_EDX("f-mmx", 23, false), + F_1_EDX("f-fxsr", 24, false), + F_1_EDX("f-sse", 25, false), + F_1_EDX("f-sse2", 26, false), + F_1_EDX("f-ss", 27, false), + /* Intel htt */ + F_1_EDX("f-ht", 28, false), + F_1_EDX("f-tm", 29, false), + F_1_EDX("f-ia64", 30, false), + F_1_EDX("f-pbe", 31, false), + /* Intel */ + F_1_ECX("f-pni", 0, false), + /* AMD sse3 */ + F_1_ECX("f-sse3", 0, false), + F_1_ECX("f-pclmulqdq", 1, false), + F_1_ECX("f-pclmuldq", 1, false), + F_1_ECX("f-dtes64", 2, false), + F_1_ECX("f-monitor", 3, false), + F_1_ECX("f-ds-cpl", 4, false), + F_1_ECX("f-vmx", 5, false), + F_1_ECX("f-smx", 6, false), + F_1_ECX("f-est", 7, false), + F_1_ECX("f-tm2", 8, false), + F_1_ECX("f-ssse3", 9, false), + F_1_ECX("f-cid", 10, false), + F_1_ECX("f-fma", 12, false), + F_1_ECX("f-cx16", 13, false), + F_1_ECX("f-xtpr", 14, false), + F_1_ECX("f-pdcm", 15, false), + F_1_ECX("f-pcid", 17, false), + F_1_ECX("f-dca", 18, false), + F_1_ECX("f-sse4.1", 19, false), + F_1_ECX("f-sse4.2", 20, false), + F_1_ECX("f-sse4-1", 19, false), + F_1_ECX("f-sse4-2", 20, false), + F_1_ECX("f-x2apic", 21, false), + F_1_ECX("f-movbe", 22, false), + F_1_ECX("f-popcnt", 23, false), + F_1_ECX("f-tsc-deadline", 24, false), + F_1_ECX("f-aes", 25, false), + F_1_ECX("f-xsave", 26, false), + F_1_ECX("f-osxsave", 27, false), + F_1_ECX("f-avx", 28, false), + F_1_ECX("f-f16c", 29, false), + F_1_ECX("f-rdrand", 30, false), + F_1_ECX("f-hypervisor", 31, false), + F_8000_0001_EDX("f-syscall", 11, false), + F_8000_0001_EDX("f-nx", 20, false), + F_8000_0001_EDX("f-xd", 20, false), + F_8000_0001_EDX("f-mmxext", 22, false), + F_8000_0001_EDX("f-fxsr-opt", 25, false), + F_8000_0001_EDX("f-ffxsr", 25, false), + /* AMD Page1GB */ + F_8000_0001_EDX("f-pdpe1gb", 26, false), + F_8000_0001_EDX("f-rdtscp", 27, false), + F_8000_0001_EDX("f-lm", 29, false), + F_8000_0001_EDX("f-i64", 29, false), + F_8000_0001_EDX("f-3dnowext", 30, false), + F_8000_0001_EDX("f-3dnow", 31, false), + /* AMD LahfSahf */ + F_8000_0001_ECX("f-lahf-lm", 0, false), + F_8000_0001_ECX("f-cmp-legacy", 1, false), + F_8000_0001_ECX("f-svm", 2, false), + /* AMD ExtApicSpace */ + F_8000_0001_ECX("f-extapic", 3, false), + /* AMD AltMovCr8 */ + F_8000_0001_ECX("f-cr8legacy", 4, false), + F_8000_0001_ECX("f-abm", 5, false), + F_8000_0001_ECX("f-sse4a", 6, false), + F_8000_0001_ECX("f-misalignsse", 7, false), + F_8000_0001_ECX("f-3dnowprefetch", 8, false), + F_8000_0001_ECX("f-osvw", 9, false), + F_8000_0001_ECX("f-ibs", 10, false), + F_8000_0001_ECX("f-xop", 11, false), + F_8000_0001_ECX("f-skinit", 12, false), + F_8000_0001_ECX("f-wdt", 13, false), + F_8000_0001_ECX("f-lwp", 15, false), + F_8000_0001_ECX("f-fma4", 16, false), + F_8000_0001_ECX("f-tce", 17, false), + F_8000_0001_ECX("f-cvt16", 18, false), + F_8000_0001_ECX("f-nodeid-msr", 19, false), + F_8000_0001_ECX("f-tbm", 21, false), + F_8000_0001_ECX("f-topoext", 22, false), + F_8000_0001_ECX("f-perfctr-core", 23, false), + F_8000_0001_ECX("f-perfctr-nb", 24, false), + F_C000_0001_EDX("f-xstore", 2, false), + F_C000_0001_EDX("f-xstore-en", 3, false), + F_C000_0001_EDX("f-xcrypt", 6, false), + F_C000_0001_EDX("f-xcrypt-en", 7, false), + F_C000_0001_EDX("f-ace2", 8, false), + F_C000_0001_EDX("f-ace2-en", 9, false), + F_C000_0001_EDX("f-phe", 10, false), + F_C000_0001_EDX("f-phe-en", 11, false), + F_C000_0001_EDX("f-pmm", 12, false), + F_C000_0001_EDX("f-pmm-en", 13, false), + DEFINE_PROP_KVMCLOCK("f-kvmclock"), + F_KVM("f-kvmclock1", 0, false), + F_KVM("f-kvm-nopiodelay", 1, false), + F_KVM("f-kvm-mmu", 2, false), + F_KVM("f-kvmclock2", 3, false), + F_KVM("f-kvm-asyncpf", 4, false), + F_KVM("f-kvm-steal-tm", 5, false), + F_KVM("f-kvm-pv-eoi", 6, false), + F_KVM("f-kvmclock-stable", 24, false), + F_SVM("f-npt", 0, false), + F_SVM("f-lbrv", 1, false), + F_SVM("f-svm-lock", 2, false), + F_SVM("f-nrip-save", 3, false), + F_SVM("f-tsc-scale", 4, false), + F_SVM("f-vmcb-clean", 5, false), + F_SVM("f-flushbyasid", 6, false), + F_SVM("f-decodeassists", 7, false), + F_SVM("f-pause-filter", 10, false), + F_SVM("f-pfthreshold", 12, false), + F_7_0_EBX("f-fsgsbase", 0, false), + F_7_0_EBX("f-bmi1", 3, false), + F_7_0_EBX("f-hle", 4, false), + F_7_0_EBX("f-avx2", 5, false), + F_7_0_EBX("f-smep", 7, false), + F_7_0_EBX("f-bmi2", 8, false), + F_7_0_EBX("f-erms", 9, false), + F_7_0_EBX("f-invpcid", 10, false), + F_7_0_EBX("f-rtm", 11, false), + F_7_0_EBX("f-rdseed", 18, false), + F_7_0_EBX("f-adx", 19, false), + F_7_0_EBX("f-smap", 20, false), DEFINE_PROP_END_OF_LIST(), }; @@ -728,85 +937,6 @@ void host_cpuid(uint32_t function, uint32_t count, #endif } -#define iswhite(c) ((c) && ((c) <= ' ' || '~' < (c))) - -/* general substring compare of *[s1..e1) and *[s2..e2). sx is start of - * a substring. ex if !NULL points to the first char after a substring, - * otherwise the string is assumed to sized by a terminating nul. - * Return lexical ordering of *s1:*s2. - */ -static int sstrcmp(const char *s1, const char *e1, const char *s2, - const char *e2) -{ - for (;;) { - if (!*s1 || !*s2 || *s1 != *s2) - return (*s1 - *s2); - ++s1, ++s2; - if (s1 == e1 && s2 == e2) - return (0); - else if (s1 == e1) - return (*s2); - else if (s2 == e2) - return (*s1); - } -} - -/* compare *[s..e) to *altstr. *altstr may be a simple string or multiple - * '|' delimited (possibly empty) strings in which case search for a match - * within the alternatives proceeds left to right. Return 0 for success, - * non-zero otherwise. - */ -static int altcmp(const char *s, const char *e, const char *altstr) -{ - const char *p, *q; - - for (q = p = altstr; ; ) { - while (*p && *p != '|') - ++p; - if ((q == p && !*s) || (q != p && !sstrcmp(s, e, q, p))) - return (0); - if (!*p) - return (1); - else - q = ++p; - } -} - -/* search featureset for flag *[s..e), if found set corresponding bit in - * *pval and return true, otherwise return false - */ -static bool lookup_feature(uint32_t *pval, const char *s, const char *e, - const char **featureset) -{ - uint32_t mask; - const char **ppc; - bool found = false; - - for (mask = 1, ppc = featureset; mask; mask <<= 1, ++ppc) { - if (*ppc && !altcmp(s, e, *ppc)) { - *pval |= mask; - found = true; - } - } - return found; -} - -static void add_flagname_to_bitmaps(const char *flagname, - FeatureWordArray words) -{ - FeatureWord w; - for (w = 0; w < FEATURE_WORDS; w++) { - FeatureWordInfo *wi = &feature_word_info[w]; - if (wi->feat_names && - lookup_feature(&words[w], flagname, NULL, wi->feat_names)) { - break; - } - } - if (w == FEATURE_WORDS) { - fprintf(stderr, "CPU feature %s not found\n", flagname); - } -} - typedef struct x86_def_t { const char *name; uint32_t level; @@ -1527,23 +1657,35 @@ static inline void feat2prop(char *s) static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) { char *featurestr; /* Single 'key=value" string being parsed */ - /* Features to be added */ - FeatureWordArray plus_features = { 0 }; - /* Features to be removed */ - FeatureWordArray minus_features = { 0 }; uint32_t numvalue; - CPUX86State *env = &cpu->env; + QDict *props = qdict_new(); + const QDictEntry *ent; featurestr = features ? strtok(features, ",") : NULL; while (featurestr) { char *val; - if (featurestr[0] == '+') { - add_flagname_to_bitmaps(featurestr + 1, plus_features); - } else if (featurestr[0] == '-') { - add_flagname_to_bitmaps(featurestr + 1, minus_features); + feat2prop(featurestr); + if (featurestr[0] == '+' || featurestr[0] == '-') { + const gchar *feat = featurestr + 1; + gchar *cpuid_fname = NULL; + + if (strncmp(feat, "f-", 2)) { + cpuid_fname = g_strconcat("f-", feat, NULL); + feat = cpuid_fname; + } + + if (featurestr[0] == '+') { + /* preseve legacy behaviour, if feature was disabled once + * do not allow to enable it again */ + if (!qdict_haskey(props, feat)) { + qdict_put(props, feat, qstring_from_str("on")); + } + } else { + qdict_put(props, feat, qstring_from_str("off")); + } + g_free(cpuid_fname); } else if ((val = strchr(featurestr, '='))) { - feat2prop(featurestr); *val = 0; val++; if (!strcmp(featurestr, "xlevel")) { char *err; @@ -1578,7 +1720,6 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) object_property_parse(OBJECT(cpu), val, featurestr, errp); } } else { - feat2prop(featurestr); object_property_parse(OBJECT(cpu), "on", featurestr, errp); } if (error_is_set(errp)) { @@ -1586,24 +1727,19 @@ static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp) } featurestr = strtok(NULL, ","); } - env->cpuid_features |= plus_features[FEAT_1_EDX]; - env->cpuid_ext_features |= plus_features[FEAT_1_ECX]; - env->cpuid_ext2_features |= plus_features[FEAT_8000_0001_EDX]; - env->cpuid_ext3_features |= plus_features[FEAT_8000_0001_ECX]; - env->cpuid_ext4_features |= plus_features[FEAT_C000_0001_EDX]; - env->cpuid_kvm_features |= plus_features[FEAT_KVM]; - env->cpuid_svm_features |= plus_features[FEAT_SVM]; - env->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX]; - env->cpuid_features &= ~minus_features[FEAT_1_EDX]; - env->cpuid_ext_features &= ~minus_features[FEAT_1_ECX]; - env->cpuid_ext2_features &= ~minus_features[FEAT_8000_0001_EDX]; - env->cpuid_ext3_features &= ~minus_features[FEAT_8000_0001_ECX]; - env->cpuid_ext4_features &= ~minus_features[FEAT_C000_0001_EDX]; - env->cpuid_kvm_features &= ~minus_features[FEAT_KVM]; - env->cpuid_svm_features &= ~minus_features[FEAT_SVM]; - env->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX]; + + for (ent = qdict_first(props); ent; ent = qdict_next(props, ent)) { + const QString *qval = qobject_to_qstring(qdict_entry_value(ent)); + /* TODO: switch to using global properties after subclasses are done */ + object_property_parse(OBJECT(cpu), qstring_get_str(qval), + qdict_entry_key(ent), errp); + if (error_is_set(errp)) { + return; + } + } out: + QDECREF(props); return; }